#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
#source "$(dirname "$0")/lib/ulib/ulib" || exit 1
#urequire DEFAULTS crontab
# Pour pouvoir être copié le cas échéant sur un hôte distant, la librairie ulib
# est inclue avec uinc à partir de lib/ulib. En mode développement, il faut
# replier les inclusions avec uinc -f et décommenter les lignes ci-dessus

function display_help() {
    uecho "$scriptname: Ajouter/Supprimer une ligne dans crontab

USAGE
    $scriptname [options] ctline

OPTIONS
    -a  Ajouter la ligne dans le fichier crontab (par défaut)
    -r  Enlever la ligne dans le fichier crontab
    -u user
        Spécifier l'utilisateur pour lequel on modifie crontab. Par défaut,
        modifier le crontab de root
    -H host:hosts...
        Modifier le crontab sur les hôtes distants spécifiés. Avec l'hôte '.' ou
        'localhost', la modification est faite sur l'hôte local
        Si l'action est -a, un script 'undo-ucrontab.sh' est créé dans le
        répertoire courant, qui annule la planification. Il est possible de
        lancer ce script le lendemain pour enlever les planifications
        installées.
    ctline
        Ligne de crontab de la forme 'minutes hours days months dows command'
        Si la ligne est de la forme halt[@hh:mm], la commande 'shutdown -h now'
        est planifiée pour le LENDEMAIN à hh:mm. si hh:mm n'est pas spécifié,
        l'arrêt est planifié pour 7:00
    -t hh:mm
        Ignorer la partie 'minutes hours days months dows' de ctline, et la
        remplacer par une planification à hh:mm le LENDEMAIN.
    --dom dayOfMonth
    --month month
        Spécifier respectivement le jour du mois et le mois (1-12) auquel faire
        la planification. Par défaut, les planifications sont effectuées pour le
        LENDEMAIN. Il est conseillé de spécifier les deux arguments si le jour
        doit être fixé.
    -s cmdfile
        Spécifier un fichier, dont le contenu est utilisé pour générer le script
        qui est planifié. Le fichier doit contenir l'ensemble des commandes à
        exécuter. Le script est modifié pour s'autodétruire à la fin de son
        exécution. Si ce comportement n'est pas souhaité, il faut rajouter la
        commande 'exit 0' à la fin.
    -S cmd
        Comme -s, mais spécifier le contenu du fichier directement sur la ligne
        de commande.
    -f hostsfile
        Spécifier un fichier qui contient la liste des hôtes sur lesquels faire
        les planifications.
        Les options -s, -S, -H, -d, -n sont ignorées. L'option --add est valide
        jusqu'au premier @group du fichier. Voici le format de ce fichier:

        Un groupe d'hôte débute par une ligne de la forme '@group:adelay:gdelay'
        - adelay est le nombre de minutes à laisser passer entre les hôtes du
          groupe (par défaut 1)
        - gdelay est le nombre de minutes à laisser passer après le traitement
          du groupe (par défaut 15)
        Les autres lignes sont des hôtes sur lequels planifier l'opération, de
        la forme 'host:cmd'
        - host est un nom d'hôte pleinement qualifié, sur lequel il est possible
          de se connecter par clé.
        - cmd est une description de la commande à lancer pour effectuer
          l'opération planifiée. Utiliser la syntaxe '<script' pour prendre le
          contenu du fichier de script spécifié. Le script est copié dans un
          fichier temporaire sur l'hôte, et se supprime après son
          lancement. Sinon, la commande spécifiée est utilisée telle quelle. Si
          cmd n'est pas spécifié, prendre la commande par défaut donnée par
          ctline
        Les lignes vides et commençant par '#' sont ignorées
        La commande '@include:file' permet d'inclure un autre fichier

    -d  Activer l'incrémentation automatique des heures de planification entre
        chaque hôte. Ceci permet par exemple de planifier l'arrêt d'un certain
        nombre de machines dans un ordre précis, en horaire décalé.
        Cette option est activée par défaut si ctline==halt[@time]
    -n  Désactiver l'incrémentation automatique des heures de planification.
    --add ADELAY
        Spécifier le nombre de minutes entre chaque hôte pour l'incrémentation
        automatique des heures de planification. Par défaut, il y a 1 minute
        entre chaque hôte.
    --us undo-script
        Spécifier le nom du script qui annule la planification. Utiliser \"\"
        pour désactiver cette fonctionnalité.
    --fake
        Afficher simplement les modifications qui doivent être effectuées."
}

DEFAULT_ADELAY=1
DEFAULT_GDELAY=15

##@inc[base
## Fonctions de base
##@*inc[base.ulib
## Support des fonctions uprovided(), uprovide() et urequire() de ulib dans le
## cas où cette librairie n'est pas chargée
if [ -z "$ULIBDIR" -o "$ULIBDIR" != "$ULIBINIT" ]; then
    ULIBPROVIDED=()
    function uprovided() {
        local module
        for module in "${ULIBPROVIDED[@]}"; do
            [ "$module" == "$1" ] && return 0
        done
        return 1
    }
    function uprovide() {
        uprovided "$1" && return 1
        ULIBPROVIDED=("${ULIBPROVIDED[@]}" "$1")
    }
    function urequire() {
        local module r=0
        for module in "$@"; do
            uprovided "$module" && continue
            echo "error: $module: this module is required but cannot be automatically loaded" 1>&2
            r=1
        done
        return $r
    }
    uprovide base.ulib
fi
##@*inc]base.ulib
##@inc[base.init
## Fonctions de base: initialisation de l'environnement
uprovide base.init

if [ -n "$UTOOLS_HAVE_SCRIPTVARS" ]; then
    :
elif [ "$0" == "-bash" ]; then
    scriptname=
    scriptdir=
    script=
elif [ ! -f "$0" -a -f "${0#-}" ]; then
    scriptname="$(basename -- "${0#-}")"
    scriptdir="$(dirname -- "${0#-}")"
    scriptdir="$(cd "$scriptdir"; pwd)"
    script="$scriptdir/$scriptname"
else
    scriptname="$(basename -- "$0")"
    scriptdir="$(dirname -- "$0")"
    scriptdir="$(cd "$scriptdir"; pwd)"
    script="$scriptdir/$scriptname"
fi
: "${ULIBDIR:=$scriptdir}"

[ -z "$TMPDIR" -a -d "$HOME/tmp" ] && TMPDIR="$HOME/tmp"
export TMPDIR="${TMPDIR:-${TMP:-${TEMP:-/tmp}}}"

[ -z "$USER" -a -n "$LOGNAME" ] && export USER="$LOGNAME"

[ -f /etc/nutoolsrc ] && . /etc/nutoolsrc
[ -f ~/.nutoolsrc ] && . ~/.nutoolsrc
true
##@inc]base.init
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.string
## Fonctions de base: gestion des valeurs scalaires
uprovide base.string
urequire base.core

function straddp() {
    local p="$1"; shift
    echo "$p$*"
}
function strdelp() {
    local p="$1"; shift
    local str="$*"
    echo "${str#$p}"
}
function strdelp2() {
    local p="$1"; shift
    local str="$*"
    echo "${str##$p}"
}
function stradds() {
    local s="$1"; shift
    echo "$*$s"
}
function strdels() {
    local s="$1"; shift
    local str="$*"
    echo "${str%$s}"
}
function strdels2() {
    local s="$1"; shift
    local str="$*"
    echo "${str%%$s}"
}
function strlower() {
    local str="$*"
    echo "${str,,}"
}
function strlower1() {
    local str="$*"
    echo "${str,}"
}
function strlowers() {
    local str="$*"
    echo "${*,}"
}
function strupper() {
    local str="$*"
    echo "${str^^}"
}
function strupper1() {
    local str="$*"
    echo "${str^}"
}
function struppers() {
    echo "${*^}"
}
function strmid() {
    local range="$1"; shift
    local str="$*"
    if [[ "$range" == *:-* ]]; then
        local max=${#str}
        [ $max -eq 0 ] && return
        local start="${range%%:*}"
        [ -n "$start" ] || start=0
        while [ "$start" -lt 0 ]; do
            start=$(($max$start))
        done
        max=$(($max-$start))
        local length="${range#*:}"
        while [ "$length" -lt 0 ]; do
            length=$(($max$length))
        done
        range="$start:$length"
    fi
    eval 'echo "${str:'" $range"'}"'
}
function strrepl() {
    local pattern="$1"; shift
    local repl="$1"; shift
    local str="$*"
    local cmd='echo "${str/'
    if [ "${pattern#/}" != "$pattern" ]; then
        pattern="${pattern#/}"
        cmd="$cmd/"
    elif [ "${pattern#\#}" != "$pattern" ]; then
        pattern="${pattern#\#}"
        cmd="$cmd#"
    elif [ "${pattern#%}" != "$pattern" ]; then
        pattern="${pattern#%}"
        cmd="$cmd%"
    fi
    cmd="$cmd"'$pattern/$repl}"'
    eval "$cmd"
}

function first_char() {
    local str="$*"
    echo "${str:0:1}"
}
function last_char() {
    local str="$*"
    echo "${str: -1:1}"
}
function first_chars() {
    local str="$*"
    recho "${str:0:$((${#1}-1))}"
}
function last_chars() {
    local str="$*"
    recho "${str:1}"
}
function first_char_is() {
    [ "${1:0:1}" == "$2" ]
}
function last_char_is() {
    [ "${1:$((-1)):1}" == "$2" ]
}
function beginswith() {
    local str="$1" pattern="$2"
    eval '[ "${str#$pattern}" != "$str" ]'
}
function endswith() {
    local str="$1" pattern="$2"
    eval '[ "${str%$pattern}" != "$str" ]'
}
##@inc]base.string
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.array
## Fonctions de base: gestion des tableaux
uprovide base.array
urequire base.core
##@inc]base.array
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
##@inc[base.split
## Fonctions de base: analyse et découpage de valeurs
uprovide base.split
urequire base.core

function splitfsep() {
    if [[ "$1" == *"$2"* ]]; then
        setv "${3:-first}" "${1%%$2*}"
        setv "${4:-second}" "${1#*$2}"
    else
        setv "${3:-first}" "$1"
        setv "${4:-second}"
    fi
}
function splitfsep2() {
    if [[ "$1" == *"$2"* ]]; then
        setv "${3:-first}" "${1%%$2*}"
        setv "${4:-second}" "${1#*$2}"
    else
        setv "${3:-first}"
        setv "${4:-second}" "$1"
    fi
}
function splitlsep() {
    if [[ "$1" == *"$2"* ]]; then
        setv "${3:-first}" "${1%$2*}"
        setv "${4:-second}" "${1##*$2}"
    else
        setv "${3:-first}" "$1"
        setv "${4:-second}"
    fi
}
function splitlsep2() {
    if [[ "$1" == *"$2"* ]]; then
        setv "${3:-first}" "${1%$2*}"
        setv "${4:-second}" "${1##*$2}"
    else
        setv "${3:-first}"
        setv "${4:-second}" "$1"
    fi
}
function splitvar() {
    splitfsep "$1" = "${2:-name}" "${3:-value}"
}
function splitpath() {
    splitlsep2 "$1" / "${2:-dir}" "${3:-name}"
}
function splitname() {
    splitlsep "$1" . "${2:-basename}" "${3:-ext}"
}
function splithost() {
    splitfsep "$1" . "${2:-hostname}" "${3:-domain}"
}
function splituserhost() {
    splitfsep2 "$1" @ "${2:-user}" "${3:-host}"
}
function splitpair() {
    splitfsep "$1" : "${2:-src}" "${3:-dest}"
}
function splitproxy() {
    local __sp_tmp __sp_host __sp_port __sp_creds __sp_user __sp_password

    __sp_tmp="${1#http://}"
    if [[ "$__sp_tmp" == *@* ]]; then
        __sp_creds="${__sp_tmp%%@*}"
        __sp_tmp="${__sp_tmp#${__sp_creds}@}"
        splitpair "$__sp_creds" __sp_user __sp_password
    fi
    __sp_tmp="${__sp_tmp%%/*}"
    splitpair "$__sp_tmp" __sp_host __sp_port
    [ -n "$__sp_port" ] || __sp_port=3128

    setv "${2:-host}" "$__sp_host"
    setv "${3:-port}" "$__sp_port"
    setv "${4:-user}" "$__sp_user"
    setv "${5:-password}" "$__sp_password"
}
function spliturl() {
    local __su_tmp __su_scheme __su_creds __su_user __su_password __su_host __su_port __su_path

    __su_scheme="${1%%:*}"
    __su_tmp="${1#${__su_scheme}://}"
    if [[ "$__su_tmp" == */* ]]; then
        __su_path="${__su_tmp#*/}"
        __su_tmp="${__su_tmp%%/*}"
    fi
    if [[ "$__su_tmp" == *@* ]]; then
        __su_creds="${__su_tmp%%@*}"
        __su_tmp="${__su_tmp#${__su_creds}@}"
        splitpair "$__su_creds" __su_user __su_password
    fi
    splitpair "$__su_tmp" __su_host __su_port
    if [ -z "$__su_port" ]; then
        [ "$__su_scheme" == "http" ] && __su_port=80
        [ "$__su_scheme" == "https" ] && __su_port=443
        [ "$__su_scheme" == "ftp" ] && __su_port=21
    fi

    setv "${2:-scheme}" "$__su_scheme"
    setv "${3:-user}" "$__su_user"
    setv "${4:-password}" "$__su_password"
    setv "${5:-host}" "$__su_host"
    setv "${6:-port}" "$__su_port"
    setv "${7:-path}" "$__su_path"
}
##@inc]base.split
##@inc[base.args
## Analyse des arguments de la ligne de commande
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.string
## Fonctions de base: gestion des valeurs scalaires
uprovide base.string
urequire base.core

function straddp() {
    local p="$1"; shift
    echo "$p$*"
}
function strdelp() {
    local p="$1"; shift
    local str="$*"
    echo "${str#$p}"
}
function strdelp2() {
    local p="$1"; shift
    local str="$*"
    echo "${str##$p}"
}
function stradds() {
    local s="$1"; shift
    echo "$*$s"
}
function strdels() {
    local s="$1"; shift
    local str="$*"
    echo "${str%$s}"
}
function strdels2() {
    local s="$1"; shift
    local str="$*"
    echo "${str%%$s}"
}
function strlower() {
    local str="$*"
    echo "${str,,}"
}
function strlower1() {
    local str="$*"
    echo "${str,}"
}
function strlowers() {
    local str="$*"
    echo "${*,}"
}
function strupper() {
    local str="$*"
    echo "${str^^}"
}
function strupper1() {
    local str="$*"
    echo "${str^}"
}
function struppers() {
    echo "${*^}"
}
function strmid() {
    local range="$1"; shift
    local str="$*"
    if [[ "$range" == *:-* ]]; then
        local max=${#str}
        [ $max -eq 0 ] && return
        local start="${range%%:*}"
        [ -n "$start" ] || start=0
        while [ "$start" -lt 0 ]; do
            start=$(($max$start))
        done
        max=$(($max-$start))
        local length="${range#*:}"
        while [ "$length" -lt 0 ]; do
            length=$(($max$length))
        done
        range="$start:$length"
    fi
    eval 'echo "${str:'" $range"'}"'
}
function strrepl() {
    local pattern="$1"; shift
    local repl="$1"; shift
    local str="$*"
    local cmd='echo "${str/'
    if [ "${pattern#/}" != "$pattern" ]; then
        pattern="${pattern#/}"
        cmd="$cmd/"
    elif [ "${pattern#\#}" != "$pattern" ]; then
        pattern="${pattern#\#}"
        cmd="$cmd#"
    elif [ "${pattern#%}" != "$pattern" ]; then
        pattern="${pattern#%}"
        cmd="$cmd%"
    fi
    cmd="$cmd"'$pattern/$repl}"'
    eval "$cmd"
}

function first_char() {
    local str="$*"
    echo "${str:0:1}"
}
function last_char() {
    local str="$*"
    echo "${str: -1:1}"
}
function first_chars() {
    local str="$*"
    recho "${str:0:$((${#1}-1))}"
}
function last_chars() {
    local str="$*"
    recho "${str:1}"
}
function first_char_is() {
    [ "${1:0:1}" == "$2" ]
}
function last_char_is() {
    [ "${1:$((-1)):1}" == "$2" ]
}
function beginswith() {
    local str="$1" pattern="$2"
    eval '[ "${str#$pattern}" != "$str" ]'
}
function endswith() {
    local str="$1" pattern="$2"
    eval '[ "${str%$pattern}" != "$str" ]'
}
##@inc]base.string
##@inc[base.array
## Fonctions de base: gestion des tableaux
uprovide base.array
urequire base.core
##@inc]base.array
uprovide base.args
urequire base.core base.string base.array #XXX maj de cette liste

function __po_parse_optdescs() {
    local -a optdescs_
    local optdesc_ option_ name_ flag_ value_
    local reset_
    local shift_
    local i_ count_

    let shift_=0
    while [ -n "$1" ]; do
        if [ "$1" == -- ]; then
            shift
            let shift_=$shift_+1
            break
        elif [ "$1" == "%" ]; then
            reset_=1
            shift
            let shift_=$shift_+1
        elif [ "$1" == "-" -o "$1" == "+" ]; then
            if [ "${opts_#+}" != "$opts_" ]; then
                opts_="${opts_#+}"
            elif  [ "${opts_#-}" != "$opts_" ]; then
                opts_="${opts_#-}"
            fi
            opts_="$1$opts_"
            shift
            let shift_=$shift_+1
        elif [ "$1" == "@" ]; then
            destargs_="$2"
            shift; shift
            let shift_=$shift_+2
        elif [[ "$1" == --* ]] || [[ "$1" == -* ]]; then
            array_split optdescs_ "$1" ","
            if [ "$2" == . ]; then
                local autoname_=
                for optdesc_ in "${optdescs_[@]}"; do
                    if [ ${#optdesc_} -gt ${#autoname_} ]; then
                        autoname_="$optdesc_"
                    fi
                done
                while [ -n "$autoname_" -a "${autoname_#-}" != "$autoname_" ]; do autoname_="${autoname_#-}"; done
                while [ -n "$autoname_" -a "${autoname_%:}" != "$autoname_" ]; do autoname_="${autoname_%:}"; done
                autoname_="${autoname_//-/_}"
                shift; shift
                set -- dummy "$autoname_" "$@"
            fi
            for optdesc_ in "${optdescs_[@]}"; do
                if [[ "$2" == \$* ]]; then
                    name_="$2"
                    if [[ "$optdesc_" == *:: ]]; then
                        option_="${optdesc_%::}"
                        flag_='::$'
                    elif [[ "$optdesc_" == *: ]]; then
                        option_="${optdesc_%:}"
                        flag_=':$'
                    else
                        option_="$optdesc_"
                        flag_='$'
                    fi
                elif [[ "$optdesc_" == *:: ]]; then
                    option_="${optdesc_%::}"
                    if [[ "$2" == *=* ]]; then
                        name_="${2%%=*}="
                        [ -n "$reset_" ] && eval "$name_="
                    else
                        name_="$2"
                        [ -n "$reset_" ] && eval "$name_=()"
                    fi
                    flag_=::
                elif [[ "$optdesc_" == *: ]]; then
                    option_="${optdesc_%:}"
                    if [[ "$2" == *=* ]]; then
                        name_="${2%%=*}="
                        [ -n "$reset_" ] && eval "$name_="
                    else
                        name_="$2"
                        [ -n "$reset_" ] && eval "$name_=()"
                    fi
                    flag_=:
                else
                    option_="$optdesc_"
                    name_="$2"
                    [ -n "$reset_" ] && eval "$name_="
                    flag_=
                fi

                if i_="$(array_find options_ "$option_")"; then
                    options_=("${options_[@]:0:$i_}" "${options_[@]:$(($i_ + 1))}")
                    names_=("${names_[@]:0:$i_}" "${names_[@]:$(($i_ + 1))}")
                    flags_=("${flags_[@]:0:$i_}" "${flags_[@]:$(($i_ + 1))}")
                fi
                options_=("${options_[@]}" "$option_")
                names_=("${names_[@]}" "$name_")
                flags_=("${flags_[@]}" "$flag_")
            done
            shift; shift
            let shift_=$shift_+2
        else
            break
        fi
    done

    i_=0
    count_=${#options_[*]}
    while [ $i_ -lt $count_ ]; do
        option_="${options_[$i_]}"
        flag_="${flags_[$i_]}"
        i_=$(($i_ + 1))

        flag_="${flag_%$}"
        if [[ "$option_" == --* ]]; then
            longopts_="${longopts_:+$longopts_,}${option_#--}$flag_"
        elif [[ "$option_" == -* ]]; then
            opts_="$opts_${option_#-}$flag_"
        fi
    done

    return $shift_
}
function __po_check_options() {
    local -a getopt_args_
    getopt_args_=(-o "$opts_" ${longopts_:+-l "$longopts_"} -- "$@")
    local args_
    if args_="$(getopt -q "${getopt_args_[@]}")"; then
        recho "$args_"
        return 0
    else
        LANG=C getopt "${getopt_args_[@]}" 2>&1 1>/dev/null
        return 1
    fi
}
function __po_process_options() {
    while [ -n "$1" ]; do
        if [ "$1" == -- ]; then
            shift
            break
        elif [[ "$1" == -* ]]; then
            local i_
            let i_=0
            for option_ in "${options_[@]}"; do
                [ "$1" == "${options_[$i_]}" ] && break
                let i_=$i_+1
            done
            name_="names_[$i_]"; name_="${!name_}"
            flag_="flags_[$i_]"; flag_="${!flag_}"
            function inc@ { eval "let $1=\$$1+1"; }
            function res@ { setv "$1" "${value_:-$2}"; }
            function add@ { array_add "$1" "${value_:-$2}"; }
            if [ -z "$name_" ]; then
                ewarn "$1: option non reconnue, elle sera ignorée"
            elif [[ "$flag_" == *\$ ]]; then
                if [[ "$flag_" == :* ]]; then
                    value_="$2"; shift
                    function set@ { res@ "$@"; }
                else
                    value_=
                    function set@ { inc@ "$@"; }
                fi
                eval "${name_#\$}"
            elif [ "$flag_" == "" ]; then
                if [[ "$name_" == *=* ]]; then
                    setv "${name_%%=*}" "${name_#*=}"
                else
                    inc@ "$name_"
                fi
            elif [ "$flag_" == ":" -o "$flag_" == "::" ]; then
                value_="$2"; shift
                if [ "${name_%=}" != "$name_" ]; then
                    setv "${name_%=}" "$value_"
                elif [[ "$name_" == *=* ]]; then
                    setv "${name_%%=*}" "${name_#*=}"
                else
                    array_add "$name_" "$value_"
                fi
            fi
        else
            break
        fi
        shift
    done
    unset -f inc@ res@ add@ set@
    [ -n "$destargs_" ] &&
    set_array "$destargs_" @ "$@"
    return 0
}
function parse_opts() {



    local -a options_ names_ flags_ destargs_
    local opts_ longopts_
    __po_parse_optdescs "$@" || shift $?
    local args_
    if args_="$(__po_check_options "$@")"; then
        eval "set -- $args_"
        __po_process_options "$@"
    else
        [ -n "$destargs_" ] && setv "$destargs_" "$args_"
        return 1
    fi
}

function parse_args_check() {
    parse_opts "${PRETTYOPTS[@]}" "${args[@]}" @ args -- "$@" && return 0
    eerror "$args"
    return 1
}
function parse_args() {
    parse_opts "${PRETTYOPTS[@]}" "${args[@]}" @ args -- "$@" || die "$args"
}

HELP_DESC=
HELP_USAGE=
HELP_OPTIONS=
function __genparse_shortopt() {
    local LC_COLLATE=C
    local shortopt="${1//[^A-Z]}"
    shortopt="$(strlower "${shortopt:0:1}")"
    [ -n "$shortopt" ] && echo "$shortopt"
}
function genparse() {

    local -a names descs vars options
    local i desc var option name uname value shortopt

    for var in "$@"; do
        if [[ "$var" == *=* ]]; then
            splitvar "$var" name value
            shortopt="$(__genparse_shortopt "$name")"
            option="$(strlower "$name")"
            name="${option//-/_}"
            array_add names "$name"
            array_add descs "${shortopt:+-$shortopt, }--$option VALUE"
            array_add vars "$(echo_setv "$name" "$value")"
            array_add options "${shortopt:+-$shortopt:,}--$option: $name="
        else
            name="$var"
            shortopt="$(__genparse_shortopt "$name")"
            option="$(strlower "$name")"
            name="${option//-/_}"
            array_add names "$name"
            array_add descs "${shortopt:+-$shortopt, }--$option"
            array_add vars "$name="
            array_add options "${shortopt:+-$shortopt,}--$option $name=1"
        fi
    done

    echo -n 'function display_help() {
    [ -n "$HELP_USAGE" ] || HELP_USAGE="USAGE
    $scriptname'
    [ -n "$descs" ] && echo -n ' [options]'
    echo '"'
    if [ -n "$descs" ]; then
        echo -n '    [ -n "$HELP_OPTIONS" ] || HELP_OPTIONS="OPTIONS'
        i=0
        while [ $i -lt ${#descs[*]} ]; do
            name="${names[$i]}"
            uname="$(strupper "$name")"
            desc="${descs[$i]}"
            echo -n "
\${HELP_${uname}_OPTION:-    $desc\${HELP_${uname}_DESC:+
        \${HELP_${uname}_DESC//
/
        }}}"
            i=$(($i + 1))
        done
        echo '"'
    fi
    echo '    uecho "${HELP_DESC:+$HELP_DESC

}$HELP_USAGE${HELP_OPTIONS:+

$HELP_OPTIONS}"
}
'
    for var in "${vars[@]}"; do
        echo "$var"
    done
    echo 'parse_opts "${PRETTYOPTS[@]}" \'
    echo '    --help '\''$exit_with display_help'\'' \'
    for option in "${options[@]}"; do
        echo "    $option \\"
    done
    echo '    @ args -- "$@" && set -- "${args[@]}" || die "$args"'
}
##@inc]base.args
##@inc[base.tools
## Fonctions de base: outils divers
##@inc[base.args
## Analyse des arguments de la ligne de commande
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.string
## Fonctions de base: gestion des valeurs scalaires
uprovide base.string
urequire base.core

function straddp() {
    local p="$1"; shift
    echo "$p$*"
}
function strdelp() {
    local p="$1"; shift
    local str="$*"
    echo "${str#$p}"
}
function strdelp2() {
    local p="$1"; shift
    local str="$*"
    echo "${str##$p}"
}
function stradds() {
    local s="$1"; shift
    echo "$*$s"
}
function strdels() {
    local s="$1"; shift
    local str="$*"
    echo "${str%$s}"
}
function strdels2() {
    local s="$1"; shift
    local str="$*"
    echo "${str%%$s}"
}
function strlower() {
    local str="$*"
    echo "${str,,}"
}
function strlower1() {
    local str="$*"
    echo "${str,}"
}
function strlowers() {
    local str="$*"
    echo "${*,}"
}
function strupper() {
    local str="$*"
    echo "${str^^}"
}
function strupper1() {
    local str="$*"
    echo "${str^}"
}
function struppers() {
    echo "${*^}"
}
function strmid() {
    local range="$1"; shift
    local str="$*"
    if [[ "$range" == *:-* ]]; then
        local max=${#str}
        [ $max -eq 0 ] && return
        local start="${range%%:*}"
        [ -n "$start" ] || start=0
        while [ "$start" -lt 0 ]; do
            start=$(($max$start))
        done
        max=$(($max-$start))
        local length="${range#*:}"
        while [ "$length" -lt 0 ]; do
            length=$(($max$length))
        done
        range="$start:$length"
    fi
    eval 'echo "${str:'" $range"'}"'
}
function strrepl() {
    local pattern="$1"; shift
    local repl="$1"; shift
    local str="$*"
    local cmd='echo "${str/'
    if [ "${pattern#/}" != "$pattern" ]; then
        pattern="${pattern#/}"
        cmd="$cmd/"
    elif [ "${pattern#\#}" != "$pattern" ]; then
        pattern="${pattern#\#}"
        cmd="$cmd#"
    elif [ "${pattern#%}" != "$pattern" ]; then
        pattern="${pattern#%}"
        cmd="$cmd%"
    fi
    cmd="$cmd"'$pattern/$repl}"'
    eval "$cmd"
}

function first_char() {
    local str="$*"
    echo "${str:0:1}"
}
function last_char() {
    local str="$*"
    echo "${str: -1:1}"
}
function first_chars() {
    local str="$*"
    recho "${str:0:$((${#1}-1))}"
}
function last_chars() {
    local str="$*"
    recho "${str:1}"
}
function first_char_is() {
    [ "${1:0:1}" == "$2" ]
}
function last_char_is() {
    [ "${1:$((-1)):1}" == "$2" ]
}
function beginswith() {
    local str="$1" pattern="$2"
    eval '[ "${str#$pattern}" != "$str" ]'
}
function endswith() {
    local str="$1" pattern="$2"
    eval '[ "${str%$pattern}" != "$str" ]'
}
##@inc]base.string
##@inc[base.array
## Fonctions de base: gestion des tableaux
uprovide base.array
urequire base.core
##@inc]base.array
uprovide base.args
urequire base.core base.string base.array #XXX maj de cette liste

function __po_parse_optdescs() {
    local -a optdescs_
    local optdesc_ option_ name_ flag_ value_
    local reset_
    local shift_
    local i_ count_

    let shift_=0
    while [ -n "$1" ]; do
        if [ "$1" == -- ]; then
            shift
            let shift_=$shift_+1
            break
        elif [ "$1" == "%" ]; then
            reset_=1
            shift
            let shift_=$shift_+1
        elif [ "$1" == "-" -o "$1" == "+" ]; then
            if [ "${opts_#+}" != "$opts_" ]; then
                opts_="${opts_#+}"
            elif  [ "${opts_#-}" != "$opts_" ]; then
                opts_="${opts_#-}"
            fi
            opts_="$1$opts_"
            shift
            let shift_=$shift_+1
        elif [ "$1" == "@" ]; then
            destargs_="$2"
            shift; shift
            let shift_=$shift_+2
        elif [[ "$1" == --* ]] || [[ "$1" == -* ]]; then
            array_split optdescs_ "$1" ","
            if [ "$2" == . ]; then
                local autoname_=
                for optdesc_ in "${optdescs_[@]}"; do
                    if [ ${#optdesc_} -gt ${#autoname_} ]; then
                        autoname_="$optdesc_"
                    fi
                done
                while [ -n "$autoname_" -a "${autoname_#-}" != "$autoname_" ]; do autoname_="${autoname_#-}"; done
                while [ -n "$autoname_" -a "${autoname_%:}" != "$autoname_" ]; do autoname_="${autoname_%:}"; done
                autoname_="${autoname_//-/_}"
                shift; shift
                set -- dummy "$autoname_" "$@"
            fi
            for optdesc_ in "${optdescs_[@]}"; do
                if [[ "$2" == \$* ]]; then
                    name_="$2"
                    if [[ "$optdesc_" == *:: ]]; then
                        option_="${optdesc_%::}"
                        flag_='::$'
                    elif [[ "$optdesc_" == *: ]]; then
                        option_="${optdesc_%:}"
                        flag_=':$'
                    else
                        option_="$optdesc_"
                        flag_='$'
                    fi
                elif [[ "$optdesc_" == *:: ]]; then
                    option_="${optdesc_%::}"
                    if [[ "$2" == *=* ]]; then
                        name_="${2%%=*}="
                        [ -n "$reset_" ] && eval "$name_="
                    else
                        name_="$2"
                        [ -n "$reset_" ] && eval "$name_=()"
                    fi
                    flag_=::
                elif [[ "$optdesc_" == *: ]]; then
                    option_="${optdesc_%:}"
                    if [[ "$2" == *=* ]]; then
                        name_="${2%%=*}="
                        [ -n "$reset_" ] && eval "$name_="
                    else
                        name_="$2"
                        [ -n "$reset_" ] && eval "$name_=()"
                    fi
                    flag_=:
                else
                    option_="$optdesc_"
                    name_="$2"
                    [ -n "$reset_" ] && eval "$name_="
                    flag_=
                fi

                if i_="$(array_find options_ "$option_")"; then
                    options_=("${options_[@]:0:$i_}" "${options_[@]:$(($i_ + 1))}")
                    names_=("${names_[@]:0:$i_}" "${names_[@]:$(($i_ + 1))}")
                    flags_=("${flags_[@]:0:$i_}" "${flags_[@]:$(($i_ + 1))}")
                fi
                options_=("${options_[@]}" "$option_")
                names_=("${names_[@]}" "$name_")
                flags_=("${flags_[@]}" "$flag_")
            done
            shift; shift
            let shift_=$shift_+2
        else
            break
        fi
    done

    i_=0
    count_=${#options_[*]}
    while [ $i_ -lt $count_ ]; do
        option_="${options_[$i_]}"
        flag_="${flags_[$i_]}"
        i_=$(($i_ + 1))

        flag_="${flag_%$}"
        if [[ "$option_" == --* ]]; then
            longopts_="${longopts_:+$longopts_,}${option_#--}$flag_"
        elif [[ "$option_" == -* ]]; then
            opts_="$opts_${option_#-}$flag_"
        fi
    done

    return $shift_
}
function __po_check_options() {
    local -a getopt_args_
    getopt_args_=(-o "$opts_" ${longopts_:+-l "$longopts_"} -- "$@")
    local args_
    if args_="$(getopt -q "${getopt_args_[@]}")"; then
        recho "$args_"
        return 0
    else
        LANG=C getopt "${getopt_args_[@]}" 2>&1 1>/dev/null
        return 1
    fi
}
function __po_process_options() {
    while [ -n "$1" ]; do
        if [ "$1" == -- ]; then
            shift
            break
        elif [[ "$1" == -* ]]; then
            local i_
            let i_=0
            for option_ in "${options_[@]}"; do
                [ "$1" == "${options_[$i_]}" ] && break
                let i_=$i_+1
            done
            name_="names_[$i_]"; name_="${!name_}"
            flag_="flags_[$i_]"; flag_="${!flag_}"
            function inc@ { eval "let $1=\$$1+1"; }
            function res@ { setv "$1" "${value_:-$2}"; }
            function add@ { array_add "$1" "${value_:-$2}"; }
            if [ -z "$name_" ]; then
                ewarn "$1: option non reconnue, elle sera ignorée"
            elif [[ "$flag_" == *\$ ]]; then
                if [[ "$flag_" == :* ]]; then
                    value_="$2"; shift
                    function set@ { res@ "$@"; }
                else
                    value_=
                    function set@ { inc@ "$@"; }
                fi
                eval "${name_#\$}"
            elif [ "$flag_" == "" ]; then
                if [[ "$name_" == *=* ]]; then
                    setv "${name_%%=*}" "${name_#*=}"
                else
                    inc@ "$name_"
                fi
            elif [ "$flag_" == ":" -o "$flag_" == "::" ]; then
                value_="$2"; shift
                if [ "${name_%=}" != "$name_" ]; then
                    setv "${name_%=}" "$value_"
                elif [[ "$name_" == *=* ]]; then
                    setv "${name_%%=*}" "${name_#*=}"
                else
                    array_add "$name_" "$value_"
                fi
            fi
        else
            break
        fi
        shift
    done
    unset -f inc@ res@ add@ set@
    [ -n "$destargs_" ] &&
    set_array "$destargs_" @ "$@"
    return 0
}
function parse_opts() {



    local -a options_ names_ flags_ destargs_
    local opts_ longopts_
    __po_parse_optdescs "$@" || shift $?
    local args_
    if args_="$(__po_check_options "$@")"; then
        eval "set -- $args_"
        __po_process_options "$@"
    else
        [ -n "$destargs_" ] && setv "$destargs_" "$args_"
        return 1
    fi
}

function parse_args_check() {
    parse_opts "${PRETTYOPTS[@]}" "${args[@]}" @ args -- "$@" && return 0
    eerror "$args"
    return 1
}
function parse_args() {
    parse_opts "${PRETTYOPTS[@]}" "${args[@]}" @ args -- "$@" || die "$args"
}

HELP_DESC=
HELP_USAGE=
HELP_OPTIONS=
function __genparse_shortopt() {
    local LC_COLLATE=C
    local shortopt="${1//[^A-Z]}"
    shortopt="$(strlower "${shortopt:0:1}")"
    [ -n "$shortopt" ] && echo "$shortopt"
}
function genparse() {

    local -a names descs vars options
    local i desc var option name uname value shortopt

    for var in "$@"; do
        if [[ "$var" == *=* ]]; then
            splitvar "$var" name value
            shortopt="$(__genparse_shortopt "$name")"
            option="$(strlower "$name")"
            name="${option//-/_}"
            array_add names "$name"
            array_add descs "${shortopt:+-$shortopt, }--$option VALUE"
            array_add vars "$(echo_setv "$name" "$value")"
            array_add options "${shortopt:+-$shortopt:,}--$option: $name="
        else
            name="$var"
            shortopt="$(__genparse_shortopt "$name")"
            option="$(strlower "$name")"
            name="${option//-/_}"
            array_add names "$name"
            array_add descs "${shortopt:+-$shortopt, }--$option"
            array_add vars "$name="
            array_add options "${shortopt:+-$shortopt,}--$option $name=1"
        fi
    done

    echo -n 'function display_help() {
    [ -n "$HELP_USAGE" ] || HELP_USAGE="USAGE
    $scriptname'
    [ -n "$descs" ] && echo -n ' [options]'
    echo '"'
    if [ -n "$descs" ]; then
        echo -n '    [ -n "$HELP_OPTIONS" ] || HELP_OPTIONS="OPTIONS'
        i=0
        while [ $i -lt ${#descs[*]} ]; do
            name="${names[$i]}"
            uname="$(strupper "$name")"
            desc="${descs[$i]}"
            echo -n "
\${HELP_${uname}_OPTION:-    $desc\${HELP_${uname}_DESC:+
        \${HELP_${uname}_DESC//
/
        }}}"
            i=$(($i + 1))
        done
        echo '"'
    fi
    echo '    uecho "${HELP_DESC:+$HELP_DESC

}$HELP_USAGE${HELP_OPTIONS:+

$HELP_OPTIONS}"
}
'
    for var in "${vars[@]}"; do
        echo "$var"
    done
    echo 'parse_opts "${PRETTYOPTS[@]}" \'
    echo '    --help '\''$exit_with display_help'\'' \'
    for option in "${options[@]}"; do
        echo "    $option \\"
    done
    echo '    @ args -- "$@" && set -- "${args[@]}" || die "$args"'
}
##@inc]base.args
uprovide base.tools
urequire base.args #XXX il manque des dépendances!

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
uprovide base.tools
urequire base

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
uprovide base.tools
urequire base

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
uprovide base.tools
urequire base

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
uprovide base.tools
urequire base

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
uprovide base.tools
urequire base

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
uprovide base.tools
urequire base

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
uprovide base.tools
urequire base

function base_umove() {
    local -a args
    local updatedir
    args=(-d:,--updatedir: .)
    parse_args_check "$@" || return; set -- "${args[@]}"

    eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return
    eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à déplacer" || return
    eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return

    local -a srcs
    local dest

    srcs=("$@")
    setx dest=last_value srcs
    array_del_last srcs

    if [ $# -eq 2 ]; then
        if [ -d "$dest" ]; then
            : # ce cas sera traité ci-dessous
        elif [ -e "$dest" ]; then
            eerror "$dest: refus d'écraser la destination"
            return 1
        else
            src="${srcs[0]}"
            if [ -n "$updatedir" ]; then
                if [ -L "$src" ]; then
                    ldest="$(readlinka "$src")"
                    array_find_links update_links "$ldest" "$updatedir"
                else
                    array_find_links update_links "$src" "$updatedir"
                fi
                move_file "$src" "$dest" "${update_links[@]}"
            else
                move_link "$src" "$dest"
            fi
            return $?
        fi
    fi

    [ -d "$dest" ] || {
        eerror "$dest: doit être un répertoire"
        return 1
    }
    for src in "${srcs[@]}"; do
        if [ -n "$updatedir" ]; then
            if [ -L "$src" ]; then
                move_link "$src" "$dest"
            else
                array_find_links update_links "$src" "$updatedir"
                move_file "$src" "$dest" "${update_links[@]}"
            fi
        else
            move_link "$src" "$dest"
        fi
    done
}
##@inc]base.tools
##@inc[base.compat
## Fonctions de base: support des fonctions obsolètes et des versions de bash < 4.x
##@inc[base.core
## Fonctions de base: fondement
uprovide base.core

function echo_() {
    echo -n "$*"
}
function recho() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo "$first$@"
    else
        echo "$@"
    fi
}
function recho_() {
    if [[ "${1:0:2}" == -[eEn] ]]; then
        echo -n -
        local first="${1:1}"; shift
        echo -n "$first$@"
    else
        echo -n "$@"
    fi
}
function _rval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\'/\'}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    s="${s// /\\ }"
    recho_ "$s"
}
function _qval() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//\$/\\\$}"
    s="${s//\`/\\\`}"
    recho_ "$s"
}
function should_quote() {
    local l="${#1}"
    [ $l -eq 0 -o $l -gt 80 ] && return 0
    local s="${*//[a-zA-Z0-9]/}"
    s="${s//,/}"
    s="${s//./}"
    s="${s//+/}"
    s="${s//\//}"
    s="${s//-/}"
    s="${s//_/}"
    s="${s//=/}"
    [ -n "$s" ]
}
function qval() {
    echo -n \"
    _qval "$@"
    echo \"
}
function qvalm() {
    if should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvalr() {
    if [ -z "$*" ]; then
        :
    elif should_quote "$*"; then
        echo -n \"
        _qval "$@"
        echo \"
    else
        recho "$*"
    fi
}
function qvals() {
    local arg first=1
    for arg in "$@"; do
        [ -z "$first" ] && echo -n " "
        if should_quote "$arg"; then
            echo -n \"
            _qval "$arg"
            echo -n \"
        else
            recho_ "$arg"
        fi
        first=
    done
    [ -z "$first" ] && echo
}
function qlines() {
    sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    eval "$__s_var=\"\$*\""
}
function _setv() {
    local __s_var="$1"; shift
    eval "$__s_var=\"\$*\""
}
function echo_setv() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    echo "$__s_var=$(qvalr "$*")"
}
function setx() {
    if [ "$1" == -a ]; then
        shift
        local __s_array="$1"; shift
        if [[ "$__s_array" == *=* ]]; then
            set -- "${__s_array#*=}" "$@"
            __s_array="${__s_array%%=*}"
        fi
        eval "$__s_array=($("$@" | qlines))"
    else
        local __s_var="$1"; shift
        if [[ "$__s_var" == *=* ]]; then
            set -- "${__s_var#*=}" "$@"
            __s_var="${__s_var%%=*}"
        fi
        eval "$__s_var="'"$("$@")"'
    fi
}
function _setvx() {
    local __s_var="$1"; shift
    eval "$__s_var="'"$("$@")"'
}
function _setax() {
    local __s_array="$1"; shift
    eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
    local __e_val __e_arg __e_r=0
    local -a __e_cmd

    local __e_first=1
    while [ $# -gt 0 ]; do
        __e_cmd=()
        while [ $# -gt 0 ]; do
            __e_arg="$1"; shift
            [ "$__e_arg" == // ] && break
            if [ "${__e_arg%//}" != "$__e_arg" ]; then
                local __e_tmp="${__e_arg%//}"
                if [ -z "${__e_tmp//\\/}" ]; then
                    __e_arg="${__e_arg#\\}"
                    __e_cmd=("${__e_cmd[@]}" "$__e_arg")
                    continue
                fi
            fi
            __e_cmd=("${__e_cmd[@]}" "$__e_arg")
        done

        if [ -n "$__e_first" ]; then
            __e_val="$("${__e_cmd[@]}")" || __e_r=$?
        else
            __e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
        fi
        __e_first=
    done
    [ -n "$__e_val" ] && echo "$__e_val"
    return $__e_r
}
function setxx() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
    local __e_arg __e_cmd

    while [ $# -gt 0 ]; do
        __e_arg="$1"; shift
        if [ "$__e_arg" == // ]; then
            __e_cmd="$__e_cmd |"
            continue
        elif [ "${__e_arg%//}" != "$__e_arg" ]; then
            local __e_tmp="${__e_arg%//}"
            if [ -z "${__e_tmp//\\/}" ]; then
                __e_arg="${__e_arg#\\}"
            fi
        fi
        __e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
    done
    eval "$__e_cmd"
}
function setxp() {
    local -a __s_args
    if [ "$1" == -a ]; then __s_args=(-a); shift; fi
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    __s_args=("${__s_args[@]}" "$__s_var")
    setx "${__s_args[@]}" evalp "$@"
}
function testx() {
    local __t_op="$1"; shift
    local __t_val="$(evalx "$@")"
    [ $__t_op "$__t_val" ]
}
function test2x() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalx "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
    local __t_op="$1"; shift
    local __t_val="$(evalp "$@")"
    [ $__t_op "$__t_val" ]
}
function test2p() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    [ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
    local __t_val1="$1"; shift
    local __t_op="$1"; shift
    local __t_val2="$(evalp "$@")"
    eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}

function err2out() {
    "$@" 2>&1
}
##@inc]base.core
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
##@inc[base.bool
## Fonctions de base: valeurs booléennes
##@inc[base.num
## Fonctions de base: gestion des valeurs numériques
uprovide base.num

function isnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function ispnum() {
    [ ${#1} -gt 0  ] || return 1
    local v="$1"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
function isrnum() {
    [ ${#1} -gt 0 ] || return 1
    local v="$1"
    v="${v#-}"
    v="${v//./}"
    v="${v//,/}"
    v="${v//[0-9]/}"
    [ -z "$v" ]
}
##@inc]base.num
uprovide base.bool
urequire base.num

function is_yes() {
    case "${1,,}" in
    o|oui|y|yes|v|vrai|t|true|on) return 0;;
    esac
    isnum "$1" && [ "$1" -ne 0 ] && return 0
    return 1
}
function is_no() {
    case "${1,,}" in
    n|non|no|f|faux|false|off) return 0;;
    esac
    isnum "$1" && [ "$1" -eq 0 ] && return 0
    return 1
}
function yesval() {
    is_yes "$1" && echo 1
}

function setb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    local __s_r
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        __s_r=$?
        eval "$__s_var="
        return $__s_r
    fi
}
function _setb() {
    local __s_var="$1"; shift
    if "$@" >/dev/null; then
        eval "$__s_var=1"
    else
        eval "$__s_var="
    fi
}

function evalb() {
    if evalx "$@" >/dev/null; then
        echo 1
    else
        return $?
    fi
}
function setxb() {
    local __s_var="$1"; shift
    if [[ "$__s_var" == *=* ]]; then
        set -- "${__s_var#*=}" "$@"
        __s_var="${__s_var%%=*}"
    fi
    setx "$__s_var" evalb "$@"
}
##@inc]base.bool
##@inc[base.quote
## Fonctions de base: protection de valeurs chaine
uprovide base.quote
urequire base.core

function _qawk() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//
/\\n}"
    recho_ "$s"
}
function qawk() {
    echo -n \"
    _qawk "$@"
    echo \"
}
function qseds() {
    local s="$*"
    s="${s//\\/\\\\}"
    s="${s//\//\\/}"
    recho "$s"
}
function _qform() {
    local s="$*"
    s="${s//\%/%25}"
    s="${s//+/%2B}"
    s="${s//&/%26}"
    s="${s//=/%3D}"
    s="${s// /+}"
    recho_ "$s"
}
function qform() {
    local s="$*"
    if [[ "$s" == *=* ]]; then
        _qform "${s%%=*}"
        echo -n =
        _qform "${s#*=}"
        echo
    else
        _qform "$s"
        echo
    fi
}
##@inc]base.quote
uprovide base.compat
urequire base.core base.num base.bool base.quote


function setx2() { setxx "$@"; }
function rawecho() { recho "$@"; }
function rawecho_() { recho_ "$@"; }
function quote_arg() { _qval "$@"; }
function quoted_arg() { qvalm "$@"; }
function quoted_args() { qvals "$@"; }
function set_var() { setv "$@"; }
function set_var_cmd() { echo_setv "$@"; }
function set_var_literal() { eval "$1=$2"; }

function quote_awk() { _qawk "$@"; }
function quoted_awk() { qawk "$@"; }
function quote_seds() { qseds "$@"; }
function quote_form() { _qform "$@"; }
function quoted_form() { qform "$@"; }


if [ -n "$BASH_VERSINFO" -a "${BASH_VERSINFO[0]}" -lt 4 ]; then
    function strlower() { tr A-Z a-z <<<"$*"; }
    function strlower1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr A-Z a-z <<<"$h")$r"
    }
    function strlowers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strlower1 "$v")")
        done
        echo "${vs[*]}"
    }
    function strupper() { tr a-z A-Z <<<"$*"; }
    function strupper1() {
        local str="$*"
        local h="${str:0:1}" r="${str:1}"
        echo "$(tr a-z A-Z <<<"$h")$r"
    }
    function struppers() {
        local -a vs; local v
        for v in "$@"; do
            vs=("${vs[@]}" "$(strupper1 "$v")")
        done
        echo "${vs[*]}"
    }

    function is_yes() {
        case "$1" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        O|OUI|Y|YES|V|VRAI|T|TRUE|ON) return 0;;
        esac
        isnum "$1" && [ "$1" -ne 0 ] && return 0
        case "$(strlower "$1")" in
        o|oui|y|yes|v|vrai|t|true|on) return 0;;
        esac
        return 1
    }
    function is_no() {
        case "$1" in
        n|non|no|f|faux|false|off) return 0;;
        N|NON|NO|F|FAUX|FALSE|OFF) return 0;;
        esac
        isnum "$1" && [ "$1" -eq 0 ] && return 0
        case "$(strlower "$1")" in
        n|non|no|f|faux|false|off) return 0;;
        esac
        return 1
    }
fi
##@inc]base.compat
uprovide base
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.tools base.compat

UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$UTOOLS_UNAME_SYSTEM"
    [ -n "$UTOOLS_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$UTOOLS_UNAME_MACHINE"
fi

function setyesval() {
    is_yes "$2" && set_var "$1" 1 || set_var "$1" ""
}
function normyesval() {
    is_yes "${2:-"${!1}"}" && set_var "$1" 1 || set_var "$1" ""
}
function normyesvals() {
    local __nyv_yesvar
    for __nyv_yesvar in "$@"; do
        is_yes "${!__nyv_yesvar}" && set_var "$__nyv_yesvar" 1 || set_var "$__nyv_yesvar" ""
    done
}
function quote_in() {
    sed 's/\\/\\\\/g
s/"/\\"/g
s/\$/\\$/g
s/`/\\`/g'
}
function quote_sin() {
    sed "s/'/'\\\\''/g"
}
function quote_sarg() {
    quote_sin <<<"$1"
}
function quoted_sarg() {
    echo "'$(quote_sarg "$1")'"
}
function quoted_sargs() {
    local a s
    for a in "$@"; do
        s="${s:+$s }$(quoted_sarg "$a")"
    done
    rawecho "$s"
}

function set_array_cmd() {
    [ $# -eq 1 ] && set -- "$1" "$1"
    local __sac_s __sac_v __sac_f
    __sac_s="$1=("; shift
    if [ "$1" == "@" ]; then
        shift
    else
        eval "set -- \"\${$1[@]}\""
    fi
    __sac_f=1
    for __sac_v in "$@"; do
        [ -n "$__sac_f" ] && __sac_f= || __sac_s="$__sac_s "
        __sac_s="$__sac_s$(quoted_arg "$__sac_v")"
    done
    __sac_s="$__sac_s)"
    echo "$__sac_s"
}
function set_array() {
    eval "$(set_array_cmd "$@")"
}
function array_count() {
    eval "echo \${#$1[*]}"
}
function array_isempty() {
    [ $(array_count "$1") -eq 0 ]
}
function array_new() {
    eval "$1=()"
}
function array_add() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\${$__aa_a[@]}\" \"\$@\")"
}
function array_ins() {
    local __aa_a="$1"; shift
    eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function array_del() {
    local __ad_v
    local -a __ad_vs
    eval 'for __ad_v in "${'"$1"'[@]}"; do
  if [ "$__ad_v" != '"$(quoted_arg "$2")"' ]; then
    array_add __ad_vs "$__ad_v"
  fi
done'
    array_copy "$1" __ad_vs
}
function array_addu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_add "$1" "$2"
    return 0
}
function array_set() {
    array_addu "$@"
}
function array_insu() {
    local __as_v
    eval 'for __as_v in "${'"$1"'[@]}"; do
  if [ "$__as_v" == '"$(quoted_arg "$2")"' ]; then
    return 1
  fi
done'
    array_ins "$1" "$2"
    return 0
}
function array_fillrange() {
    local -a __af_vs
    local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
    while [ "$__af_i" -le "$__af_to" ]; do
        __af_vs=("${__af_vs[@]}" "$__af_i")
        __af_i=$(($__af_i + $__af_step))
    done
    array_copy "$1" __af_vs
}
function array_eq() {
    local -a __ae_a1 __ae_a2
    array_copy __ae_a1 "$1"
    array_copy __ae_a2 "$2"
    [ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
    local __ae_v __ae_i=0
    for __ae_v in "${__ae_a1[@]}"; do
        [ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
        __ae_i=$(($__ae_i + 1))
    done
    return 0
}
function array_contains() {
    local __ac_v
    eval 'for __ac_v in "${'"$1"'[@]}"; do
  if [ "$__ac_v" == '"$(quoted_arg "$2")"' ]; then
    return 0
  fi
done'
    return 1
}
function array_find() {
    local __af_i __af_v
    __af_i=0
    eval 'for __af_v in "${'"$1"'[@]}"; do
  if [ "$__af_v" == '"$(quoted_arg "$2")"' ]; then
    if [ -n "$3" ]; then
      echo "${'"$3"'[$__af_i]}"
    else
      echo "$__af_i"
    fi
    return 0
  fi
  __af_i=$(($__af_i + 1))
done'
    return 1
}
function array_reverse() {
    local -a __ar_vs
    local __ar_v
    array_copy __ar_vs "$1"
    array_new "$1"
    for __ar_v in "${__ar_vs[@]}"; do
        array_ins "$1" "$__ar_v"
    done
}

function array_replace() {
    local __ar_sn="$1"; shift
    local __ar_f="$1"; shift
    local -a __ar_s __ar_d
    local __ar_v
    array_copy __ar_s "$__ar_sn"
    for __ar_v in "${__ar_s[@]}"; do
        if [ "$__ar_v" == "$__ar_f" ]; then
            __ar_d=("${__ar_d[@]}" "$@")
        else
            __ar_d=("${__ar_d[@]}" "$__ar_v")
        fi
    done
    array_copy "$__ar_sn" __ar_d
}
function array_each() {
    local __ae_an="$1"; shift
    local __ae_f="$1"; shift
    local -a __ae_a
    local __ae_v
    array_copy __ae_a "$__ae_an"
    for __ae_v in "${__ae_a[@]}"; do
        "$__ae_f" "$__ae_v" "$@"
    done
}
function array_map() {
    local __am_an="$1"; shift
    local __am_f="$1"; shift
    local -a __am_a __am_vs
    local __am_v
    array_copy __am_a "$__am_an"
    for __am_v in "${__am_a[@]}"; do
        __am_vs=("${__am_vs[@]}" "$("$__am_f" "$__am_v" "$@")")
    done
    array_copy "$__am_an" __am_vs
}
function first_value() {
    eval "rawecho \"\${$1[@]:0:1}\""
}
function last_value() {
    eval "rawecho \"\${$1[@]:\$((-1)):1}\""
}
function array_copy() {
    eval "$1=(\"\${$2[@]}\")"
}
function array_copy_firsts() {
    eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function array_del_last() {
    array_copy_firsts "$1"
}
function array_copy_lasts() {
    eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function array_del_first() {
    array_copy_lasts "$1"
}
function array_extend() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function array_extendu() {
    local __ae_v __ae_s=1
    eval 'for __ae_v in "${'"$2"'[@]}"; do
  array_addu "$1" "$__ae_v" && __ae_s=0
done'
    return "$__ae_s"
}
function array_extend_firsts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function array_extend_lasts() {
    eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function array_xsplit() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_split() {
    eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_path() {
    array_split "$1" "$2" ":"
}
function array_from_xlines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_from_lines() {
    eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next }
{
    gsub(/'\''/, "'\'\\\\\'\''")
    print "'\''" $0 "'\''"
}'))" #"
}
function array_join() {
    local __aj_an __aj_l __aj_j __aj_s="${2:-,}" __aj_pf __aj_sf
    if [ "$1" == "@" ]; then
        __aj_an="\$@"
        shift; shift
    else
        __aj_an="\${$1[@]}"
        __aj_pf="$4"
        __aj_sf="$5"
    fi
    eval 'for __aj_l in "'"$__aj_an"'"; do
  __aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
    if [ -n "$__aj_j" ]; then
        rawecho "$__aj_j"
    elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
        rawecho "$3"
    fi
}
function array_mapjoin() {
    local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
    shift; shift; shift
    if [ "$__amj_src" == "@" ]; then
        local -a __amj_tmpsrc
        __amj_tmpsrc=("$@")
        __amj_src=__amj_tmpsrc
        set --
    fi
    local -a __amj_tmp
    array_copy __amj_tmp "$__amj_src"
    array_map __amj_tmp "$__amj_func"
    array_join __amj_tmp "$__amj_sep" "$@"
}
function array_to_lines() {
    array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
    array_join "$1" ":" "$2" "$3" "$4"
}
function array_fix_paths() {
    local __afp_an="$1" __afp_s="${2:-:}"
    local -a __afp_vs
    local __afp_v
    array_copy __afp_vs "$__afp_an"
    array_new "$__afp_an"
    for __afp_v in "${__afp_vs[@]}"; do
        array_split __afp_v "$__afp_v" "$__afp_s"
        array_extend "$__afp_an" __afp_v
    done
}


function get_date_rfc822() {
    LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
}
function get_date_fr() {
    LC_TIME=C date +"%d/%m/%Y"
}
function get_time_fr() {
    LC_TIME=C date +"%Hh%M"
}
function parse_date() {
    local value="$1" type="${2:-date}"
    local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
    case "$value" in
    +*)
        value="$(($now + ${value#+} * 86400))"
        ;;
    *)
        value="$(<<<"$value" awk -F/ '{
            nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
            d = $1 + 0; if (d < 1) d = nd;
            m = $2 + 0; if (m < 1) m = nm;
            if ($3 == "") y = ny;
            else { y = $3 + 0; if (y < 100) y = y + 2000; }
            print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
        }')"
    esac
    case "$type" in
    d|date) awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value";;
    l|ldap) awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value";;
    m|mysql) awk '{ print strftime("%Y-%m-%d", $0 + 0) }' <<<"$value";;
    *)
        rawecho "$value"
        ;;
    esac
}


function udelpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function uaddpath() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function uinspathm() {
    local _qdir="${1//\//\\/}"
    eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function uinspath() {
    udelpath "$@"
    uinspathm "$@"
}

function withpath() {
    [ "${1#./}" != "$1" -o "${1#../}" != "$1" -o "${1#/}" != "$1" ]
}
function withext() {
    local basename="$(basename -- "$1")"
    [ "${basename%.*}" != "$basename" ]
}
function normpath() {
    local -a parts
    local part ap
    array_split parts "$1" /
    if [ "${1#/}" != "$1" ]; then
        ap=/
    elif [ -n "$2" ]; then
        ap="$2"
    else
        ap="$(pwd)"
    fi
    for part in "${parts[@]}"; do
        if [ "$part" == "." ]; then
            continue
        elif [ "$part" == ".." ]; then
            ap="${ap%/*}"
            [ -n "$ap" ] || ap=/
        else
            [ "$ap" != "/" ] && ap="$ap/"
            ap="$ap$part"
        fi
    done
    rawecho "$ap"
}
function abspath() {
    local ap="$1"
    if [ "${ap#/}" != "$ap" ]; then
        __normpath "$ap" && return
    else
        local cwd
        if [ -n "$2" ]; then
            cwd="$(abspath "$2")"
        else
            cwd="$(pwd)"
        fi
        ap="$cwd/$ap"
        __normpath "$ap" && return
    fi
    normpath "$ap"
}
function __normpath() {
    if [ -d "$1" ]; then
        if [ -x "$1" ]; then
            (cd "$1"; pwd)
            return 0
        fi
    elif [ -f "$1" ]; then
        local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
        if [ -x "$dn" ]; then
            (cd "$dn"; echo "$(pwd)/$bn")
            return 0
        fi
    fi
    return 1
}
function parentdirs() {
    array_new "$1"
    local __pd_d="$(abspath "$2")"
    if [[ "$3" == r* ]]; then
        while [ "$__pd_d" != "/" ]; do
            array_ins "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    else
        while [ "$__pd_d" != "/" ]; do
            array_add "$1" "$__pd_d"
            __pd_d="$(dirname "$__pd_d")"
        done
    fi
}
function ppath() {
    local path="$1" cwd="$2"

    path="$(abspath "$path")" # essayer de normaliser le chemin
    [ -n "$cwd" ] || cwd="$(pwd)"

    [ "$path" = "$cwd" ] && path="."
    [ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path/#$cwd\//}"
    path="${path/#$HOME/~}"

    rawecho "$path"
}
function relpath() {
    local p="$(abspath "$1" "$3")" cwd="$2"
    if [ -z "$cwd" ]; then
        cwd="$(pwd)"
    else
        cwd="$(abspath "$cwd" "$3")"
    fi
    if [ "$p" == "$cwd" ]; then
        echo ""
    elif [ "${p#$cwd/}" != "$p" ]; then
        rawecho "${p#$cwd/}"
    else
        local rp
        while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
            rp="${rp:+$rp/}.."
            cwd="${cwd%/*}"
        done
        rp="$rp/${p#$cwd/}"
        echo "${rp%//}"
    fi
}
function relpathx() {
    local p="$(relpath "$@")"
    if [ -z "$p" ]; then
        echo .
    elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
        echo "$p"
    else
        echo "./$p"
    fi
}
function withinpath() {
    local b="$1" p="$2" strict="${3:-N}"
    b="$(abspath "$b")"
    p="$(abspath "$p")"
    if is_yes "$strict"; then
        [ "${p#$b/}" != "$p" ]
    else
        [ "$p" == "$b" -o "${p#$b/}" != "$p" ]
    fi
}
function safe_abspath() {
    local p="$1" ba="$2" br="$3"
    if [ -n "$ba" ]; then
        ba="$(abspath "$ba")"
    else
        ba="$(pwd)"
    fi
    [ -n "$br" ] || br="$ba"
    br="$(abspath "$br" "$ba")"
    p="$(abspath "$p" "$ba")"
    if [ "$p" == "$br" -o "${p#$br/}" != "$p" ]; then
        echo "$p"
    else
        return 1
    fi
}
function safe_relpath() {
    local p
    if p="$(safe_abspath "$1" "$2" "$3")"; then
        relpath "$p" "$2" "$(pwd)"
    else
        return 1
    fi
}
function splitwcs() {
    local __sw_p="$1"
    local __sw_dd="${2:-basedir}" __sw_df="${3:-filespec}" __sw_part __sw_d __sw_f
    local -a __sw_parts
    array_split __sw_parts "$__sw_p" "/"
    for __sw_part in "${__sw_parts[@]}"; do
        if [[ "$__sw_part" == *\** ]] || [[ "$__sw_part" == *\?* ]] || [ -n "$__sw_f" ]; then
            __sw_f="${__sw_f:+$__sw_f/}$__sw_part"
        else
            __sw_d="${__sw_d:+$__sw_d/}$__sw_part"
        fi
    done
    [ "${__sw_p#/}" != "$__sw_p" ] && __sw_d="/$__sw_d"
    set_var "$__sw_dd" "$__sw_d"
    set_var "$__sw_df" "$__sw_f"
}
function deref() {
    local OENC="$UTF8"

    local max_deref=50
    local file="$1"
    local basedir link
    while [ -L "$file" ]; do
        basedir="$(dirname "$file")"
        link="$(readlink "$file")"
        if first_char_is "$link" "/"; then
            file="$link"
        else
            file="$basedir/$link"
        fi

        max_deref=$(($max_deref - 1))
        [ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
    done
    abspath "$file"
}
function readlinka() {
    if [ -L "$1" ]; then
        local linkdir="$(dirname -- "$1")"
        abspath "$(readlink "$1")" "$linkdir"
    else
        abspath "$1"
    fi
}
function readlinkm() {
    readlink -m "$1"
}
function path_if_test() {
    local op="$1"; shift
    local file="$1"; shift
    local rel="$1" reldir=; shift
    if beginswith "$rel" relative; then
        reldir="${rel#relative}"
        if beginswith "$reldir" :; then
            reldir="${reldir#:}"
            if [ -n "$reldir" ]; then
                reldir="${reldir}/"
            fi
        else
            reldir=
        fi
    else
        rel=
    fi

    while [ -n "$1" ]; do
        local basedir="$1"
        if [ $op "$basedir/$file" ]; then
            if [ -n "$rel" ]; then
                rawecho "$reldir$file"
            else
                rawecho "$basedir/$file"
            fi
            break
        fi
        shift
    done
}
function update_link() {
    [ -L "$2" ] || return 1
    local dest link="$2"
    local linkdir="$(dirname "$link")"
    local ldest="$(readlink "$link")"
    if [ "${ldest#/}" != "$ldest" ]; then
        dest="$(abspath "$1")"
    else
        dest="$(relpath "$1" "$linkdir")"
    fi
    if [ "$dest" == "$ldest" ]; then
        : # pas besoin de mettre à jour
    elif [ -d "$link" ]; then
        rm -f "$link" && ln -s "$dest" "$link"
    else
        ln -sf "$dest" "$link"
    fi
}
function update_links() {
    [ -n "$1" ] || return 1
    local dest="$1"; shift
    local r=0 link
    for link in "$@"; do
        update_link "$dest" "$link" || r=$?
    done
    return $r
}
function move_link() {
    [ -n "$1" -a -n "$2" ] || return 1
    local link="$1" dest="$2"
    [ -d "$dest" ] && dest="$dest/$(basename -- "$link")"
    dest="$(abspath "$dest")"
    if [ -L "$link" ]; then
        link="$(abspath "$link")"
        [ "$dest" == "$link" ] && return 0
        ldest="$(readlinka "$link")"
        mv "$link" "$dest" || return 1
        update_link "$ldest" "$dest"
    else
        [ "$dest" == "$link" ] && return 0
        mv "$link" "$dest"
    fi
}
function array_find_links() {
    local -a __afl_links __afl_result
    local __afl_dir="${3:-.}"
    local __afl_dest __afl_destname __afl_link __afl_linkdir __afl_ldest
    __afl_dest="$(abspath "$2")"
    __afl_destname="${__afl_dest##*/}"
    array_from_lines __afl_links "$(find "$__afl_dir" -type l)"
    for __afl_link in "${__afl_links[@]}"; do
        __afl_ldest="$(readlink "$__afl_link")"
        if [ "$__afl_ldest" != "$__afl_destname" ]; then
            [[ "$__afl_ldest" == */"$__afl_destname" ]] || continue
        fi
        __afl_link="$(abspath "$__afl_link" "$__afl_dir")"
        __afl_linkdir="$(dirname -- "$__afl_link")"
        __afl_ldest="$(abspath "$__afl_ldest" "$__afl_linkdir")"
        if [ "$__afl_ldest" == "$__afl_dest" ]; then
            array_add __afl_result "$__afl_link"
        fi
    done
    array_copy "$1" __afl_result
}
function list_links() {
    local -a links
    array_find_links links "$@"
    array_to_lines links
}
function move_file() {
    [ -n "$1" -a -n "$2" ] || return 1
    local src="$1" dest="$2" link
    shift; shift
    [ -d "$dest" ] && dest="$dest/$(basename -- "$src")"
    move_link "$src" "$dest" || return 1
    update_links "$dest" "$@"
}

function get_nblines() {
    [ -f "$1" ] && sed -ne '$=' "$1" || echo 0
}
function mktempf() {
    mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mktempd() {
    mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function mkdirof() {
    mkdir -p "$(dirname -- "$1")"
}
function cp_a() {
    /bin/cp -a "$@"
}
function cp_R() {
    /bin/cp -pR "$@"
}
function quietgrep() {
    grep -q "$@" 2>/dev/null
}
function quietdiff() {
    diff -q "$@" >&/dev/null
}
function testsame() {
    quietdiff "$@"
}
function testdiff() {
    ! quietdiff "$@"
}
function testupdated() {
    if [ -f "$2" ]; then
        testdiff "$1" "$2"
    else
        return 0
    fi
}
function testnewer() {
    test ! -e "$2" -o "$1" -nt "$2"
}
function ps_all() {
    ps -axww
}
function progexists() {
    test -n "$1" -a -x "$(which "$1" 2>/dev/null)"
}
function has_python() {
    progexists python
}
function has_gawk() {
    progexists gawk
}
function is_root() {
    test `id -u` -eq 0
}
function source_ifexists() {
    if [ -f "$1" ]; then source "$1" || die; fi
}
function little_sleep {
    LC_NUMERIC=C sleep 0.1
}
function random_sleep {
    sleep $(($RANDOM % ${1:-1800}))
}
function is_running() {
    kill -0 "$1" >&/dev/null
}
function sedi() {
    sed -i "$@"
}
function csort() {
    LANG=C sort "$@"
}
function lsort() { sort "$@"; }
function cgrep() {
    LANG=C grep "$@"
}
function lgrep() { grep "$@"; }
function csed() {
    LANG=C sed "$@"
}
function lsed() { sed "$@"; }
function cawk() {
    LANG=C awk "$@"
}
function lawk() { awk "$@"; }
function cdiff() {
    LANG=C diff "$@"
}
function ldiff() { diff "$@"; }


function fix_mode() {
    local file="$1"
    [ -f "$file" ] || touch "$file" || return 1
    if [ ! -w "$file" ]; then
        local mode="$(stat -c %a "$file")"
        chmod ${mode:0:${#mode}-3}6${mode:${#mode}-2:2} "$file"
        echo "$mode"
    fi
}
function unfix_mode() {
    [ -n "$2" ] && chmod "$2" "$1"
}
function get_mode() {
    [ -f "$1" ] || touch "$1" || return 1
    stat -c %a "$1"
}
function rm_maybe() {
    local parse_opts=1 arg rm
    for arg in "$@"; do
        if [ -n "$parse_opts" ]; then
            if [ "$arg" == "--" ]; then
                parse_opts=
            elif [[ "$arg" == "-*" ]]; then
                continue
            elif [ -n "$arg" ]; then
                rm=1
                break
            fi
        elif [ -n "$arg" ]; then
            rm=1
            break
        fi
    done
    [ -n "$rm" ] && /bin/rm "$@"
}
__CPDIR_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPDIR_RSYNC_ARGS=(-q)
function cpdir() {

    if progexists rsync; then
        [ -d "$2" ] || mkdir -p "$2" || return 1
        if [ -d "$1" ]; then
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1/" "$2/"
        else
            rsync -a ${__CPDIR_RSYNC_SLOW:+-c} "${__CPDIR_RSYNC_ARGS[@]}" "$1" "$2/"
        fi
    else
        __cpdir "$@"
    fi
}
function __cpdir() {
    local src="$1" dest="$2" method="${3:-cp_a}"

    if [ -d "$src" ]; then
        [ -d "$dest" ] || mkdir -p "$dest" || return 1

        local prevdir="$(pwd)"

        dest="$(abspath "$dest")"
        cd "$src"
        if [ -n "$(/bin/ls -a1)" ]; then
            [ -n "$(/bin/ls -1)" ] && "$method" * "$dest"
            local i
            for i in .*; do
                [ "$i" == "." -o "$i" == ".." ] && continue
                "$method" "$i" "$dest"
            done
        fi
        cd "$prevdir"
    else
        if [ -f "$dest" ]; then
            "$method" "$src" "$dest"
        elif [ -d "$dest" ]; then
            "$method" "$src" "$dest"
        else
            mkdir -p "$dest"
            "$method" "$src" "$dest"
        fi
    fi
}
__CPNOVCS_RSYNC_SLOW=1 # synchro potentiellement plus lente, mais plus fidèle (option -c)
__CPNOVCS_RSYNC_ARGS=(-q)
function cpnovcs() {
    local src="$1" destdir="$2"
    [ -d "$destdir" ] || mkdir -p "$destdir" || return 1
    if progexists rsync; then
        local gitexclude=/.git/
        if [ "${src%/}" == "$src" ]; then
            gitexclude="/$(basename -- "$src")$gitexclude"
        fi
        rsync -a ${__CPNOVCS_RSYNC_SLOW:+-c} --exclude CVS/ --exclude .svn/ --exclude "$gitexclude" "${__CPNOVCS_RSYNC_ARGS[@]}" "$src" "$destdir/"
    elif [ "${src%/}" != "$src" ]; then
        __cpdir "$src" "$destdir"
    else
        local srcname="$(basename -- "$src")"
        mkdir -p "$destdir/$srcname"
        __cpdir "$src" "$destdir/$srcname"
    fi
}
function cpdirnovcs() {
    if [ -d "$1" ]; then
        cpnovcs "$1/" "$2"
    else
        cpnovcs "$1" "$2"
    fi
}
function doinplace() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        [ "$s" == 0 ] && /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function doinplacef() {
    if [ -n "$1" -a "$1" != "-" ]; then
        local __dip_file="$1"; shift
        autoclean "$__dip_file.tmp.$$"
        "$@" <"$__dip_file" >"$__dip_file.tmp.$$"
        local s=$?
        /bin/cat "$__dip_file.tmp.$$" >"$__dip_file"
        /bin/rm -f "$__dip_file.tmp.$$"
        return $s
    else
        shift
        "$@"
    fi
}
function stripnl() {
    tr -d '\r\n'
}
function _nl2lf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print}'
}
function nl2lf() {
    doinplace "$1" _nl2lf
}
function _nl2crlf() {
    awk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
}
function nl2crlf() {
    doinplace "$1" _nl2crlf
}
function _nl2cr() {
    awk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
}
function nl2cr() {
    doinplace "$1" _nl2cr
}
function _latin1compat() {
    LANG=fr_FR.UTF-8 sed $'
s/[‘’]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
'
}
function _noaccents() {
    LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
}
function list_all() {
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        rawecho "$f"
    done
    cd "$curdir"
}
function __la_cmd() {
    [ $# -gt 0 ] || set '*'
    local arg
    local cmd="/bin/ls -1d"
    for arg in "$@"; do
        arg="$(_rval "$arg")"
        cmd="$cmd $arg"
    done
    cmd="$cmd 2>/dev/null"
    echo "$cmd"
}
function list_files() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ -f "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function list_dirs() {
    local f
    local curdir="$(pwd)"
    local b="${1:-.}"; shift

    cd "$b" 2>/dev/null || return
    eval "$(__la_cmd "$@")" | while read f; do
        [ "$f" == "." -o "$f" == ".." ] && continue
        [ -d "$f" ] && rawecho "$f"
    done
    cd "$curdir"
}
function __array_ls() {
    local __al_l="list_${1:-all}"; shift
    local __al_an="$1"; shift
    local __al_d="${1:-.}"; shift
    local -a __al_fs
    array_from_lines __al_fs "$("$__al_l" "$__al_d" "$@")"
    local __al_f
    array_new "$__al_an"
    for __al_f in "${__al_fs[@]}"; do
        array_add "$__al_an" "$__al_d/$__al_f"
    done
}
function array_lsall() {
    __array_ls all "$@"
}
function array_lsdirs() {
    __array_ls dirs "$@"
}
function array_lsfiles() {
    __array_ls files "$@"
}
function filter_empty() {
    sed '/^$/d'
}
function filter_vcspath() {
    sed '
/^.git$/d
/^.git\//d
/\/.git$/d
/\/.git\//d
/^.svn$/d
/^.svn\//d
/\/.svn$/d
/\/.svn\//d
'
}
function merge_contlines() {
    awk 'substr($0, length($0)) == "\\" {
  while (getline nextline) {
    $0 = substr($0, 1, length($0) - 1) nextline
    if (substr($0, length($0)) != "\\") break
  }
  print
  next
}
{print}'
}
function filter_comment() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    awk '
 /^[ \t]*#/ { next }
 /^[ \t]*$/ { next }
 { print }' | "${merge[@]}"
}
function filter_conf() {
    local -a merge
    [ "$1" == -m ] && merge=(merge_contlines) || merge=(cat)
    grep -v '^#' | grep -v '^$' | "${merge[@]}"
}
function is_archive() {
    local name="${1%.zip}"
    name="${name%.tgz}"
    name="${name%.tbz2}"
    name="${name%.tar.gz}"
    name="${name%.tar.bz2}"
    name="${name%.tar}"
    name="${name%.jar}"
    name="${name%.war}"
    name="${name%.ear}"
    [ "$name" != "$1" ]
}
function extract_archive() {
    local arch="$1" destdir="${2:-.}"
    shift; shift
    if endswith "$arch" .zip; then
        unzip -q -d "$destdir" "$arch" "$@" || return
    elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
        tar xzf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
        tar xjf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .tar; then
        tar xf "$arch" -C "$destdir" "$@" || return
    elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
        (
            arch="$(abspath "$arch")"
            cd "$destdir"
            jar xf "$arch" "$@"
        ) || return
    else
        return 1
    fi
}
function get_archive_basename() {
    local basename="$(basename -- "$1")"
    basename="${basename%.zip}"
    basename="${basename%.tgz}"
    basename="${basename%.tbz2}"
    basename="${basename%.gz}"
    basename="${basename%.bz2}"
    basename="${basename%.tar}"
    basename="${basename%.jar}"
    basename="${basename%.war}"
    basename="${basename%.ear}"
    echo "$basename"
}
function get_archive_appname() {
    local appname="$(basename -- "$1")"
    appname="${appname%.zip}"
    appname="${appname%.tgz}"
    appname="${appname%.tbz2}"
    appname="${appname%.gz}"
    appname="${appname%.bz2}"
    appname="${appname%.tar}"
    appname="${appname%.jar}"
    appname="${appname%.war}"
    appname="${appname%.ear}"
    echo "$appname" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/)) {
    print substr($0, 1, RSTART - 1)
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print substr($0, 1, RSTART - 1)
  } else {
    print $0
  }
}'
}
function get_archive_versionsuffix() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /([-_.][0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function get_archive_version() {
    local basename="$(get_archive_basename "$1")"
    echo "$basename" | awk '{
  if (match($0, /[-_.]([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+([-_.][0-9]+)*([a-zA-Z][0-9]*|[-_.][0-9]+[a-zA-Z][0-9]*)?)$/, vs)) {
    print vs["1"]
  } else if (match($0, /([0-9]+[a-z][a-z][a-z0-9]?)$/, vs)) {
    print vs["1"]
  }
}'
}
function __dump_usernames() {
    </etc/passwd awkrun FS=: '($3 + 0) >= 500 && $6 ~ /^\/home\// { print $1 }'
}
function dump_usernames() {
    array_from_lines "${1:-usernames}" "$(__dump_usernames)"
}
function __resolv_ips() {
    LANG=C host "$1" 2>/dev/null | awk '/address / { gsub(/^.*address /, ""); print }'
}
function resolv_ips() {
    array_from_lines "${1:-ips}" "$(__resolv_ips "$2")"
}
function __resolv_hosts() {
    LANG=C host "$1" 2>/dev/null | awk '/domain name pointer / { gsub(/^.*domain name pointer /, ""); gsub(/\.$/, ""); print }'
}
function resolv_hosts() {
    array_from_lines "${1:-hosts}" "$(__resolv_hosts "$2")"
}
function runscript_as() {
    local OENC="$UTF8"
    local user="${1:-root}"; shift
    local exec_maybe=
    if [ "$1" = "exec" ]; then
        exec_maybe=exec
        shift
    fi

    local cmd
    cmd="\
__estack=$(quoted_arg "$__estack")
__tlevel=$(quoted_args "$__tlevel")
export __estack __tlevel
exec ${BASH:-/bin/sh} $(quoted_args "$@")"

    if is_yes "$UTOOLS_USES_SU" || ! progexists sudo; then
        eecho "Entrez le mot de passe de root"
        $exec_maybe su "$user" -c "$cmd"
    else
        if [ "$user" == "root" ]; then
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " "${BASH:-/bin/sh}" -c "$cmd"
        else
            $exec_maybe sudo -p "Entrez le mot de passe de %u: " su "$user" -c "$cmd"
        fi
    fi
}
function runscript_as_root() {
    if is_root; then
        local exec_maybe=
        if [ "$1" = "exec" ]; then
            exec_maybe=exec
            shift
        fi
        $exec_maybe "${BASH:-/bin/sh}" "$@"
    else
        runscript_as root "$@"
    fi
}
function run_as() {
    local user="${1:-root}"; shift
    local exec_maybe=exec
    if [ "$1" = "--noexec" ]; then
        exec_maybe=
        shift
    fi

    runscript_as "$user" $exec_maybe "$0" "$@"
}
function run_as_root() {
    is_root || run_as root "$@"
}
function check_user() {
    local user
    for user in "$@"; do
        [ "$USER" == "$user" ] && return 0
    done
    return 1
}
function ensure_user() {
    local -a users
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add users "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    if ! check_user "${users[@]}"; then
        if [ ${#users[*]} -gt 1 ]; then
            ewarn "Cette commande doit être lancée avec l'un des users ${users[*]}"
        else
            ewarn "Cette commande doit être lancée avec le user ${users[0]}"
        fi
        if ask_yesno "Voulez-vous tenter de relancer la commande avec le bon user?" O; then
            estep "Lancement du script avec le user ${users[0]}"
            run_as "${users[0]}" "$@"
            return 1
        elif is_root; then
            return 11
        else
            return 10
        fi
    fi
    return 0
}
function check_hostname() {
    local userhost user host path
    for userhost in "$@"; do
        splitfsep "$userhost" : userhost path
        splituserhost "$userhost" user host
        [ "$MYHOSTNAME" == "${host%%.*}" ] && return 0
    done
    return 1
}
function check_userhostname() {
    local userhost path user host
    for userhost in "$@"; do
        if check_hostname "$userhost"; then
            [[ "$userhost" == *@* ]] || return 0
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            check_user "$user" && return 0
        fi
    done
    return 1
}
UTOOLS_ENSURE_HOSTNAME_SSH_OPTS=()
function ensure_hostname() {
    local -a userhosts
    while [ $# -gt 0 -a "$1" != "--" ]; do
        array_add userhosts "$1"
        shift
    done
    [ "$1" == "--" ] && shift

    local userhost user host path
    if ! check_hostname "${userhosts[@]}"; then
        if [ ${#userhosts[*]} -gt 1 ]; then
            ewarn "Cette commande n'est valide que sur l'un des hôtes ${userhosts[*]}"
        else
            ewarn "Cette commande n'est valide que sur l'hôte ${userhosts[0]}"
        fi

        enote "Vous pouvez tenter de relancer le script sur ${userhosts[0]}, mais cela requière que ce script ET les données dont il a besoin soient installés dans la même version et dans le même répertoire sur l'hôte distant"
        if ask_yesno "Voulez-vous tenter de relancer le script sur l'hôte distant?" N; then
            splitfsep "${userhosts[0]}" : userhost path
            splituserhost "$userhost" user host
            [ -n "$user" ] || user=root

            estep "Lancement de la commande sur l'hôte distant $user@$host"
            local cmd
            [ -n "$path" ] && cmd="$(quoted_args cd "$path"); "
            cmd="$cmd$(quoted_args "$script" "$@")"
            ssh -qt "${UTOOLS_ENSURE_HOSTNAME_SSH_OPTS[@]}" "$user@$host" "$cmd"
            [ $? -eq 255 ] && return 12
            return 1
        else
            return 11
        fi
    fi
    local userhost user host
    for userhost in "${userhosts[@]}"; do
        [[ "$userhost" == *@* ]] || continue
        if check_hostname "$userhost"; then
            splitfsep "$userhost" : userhost path
            splituserhost "$userhost" user host
            [ -n "$path" ] && cd "$path"
            ensure_user "$user" -- "$@"
            return $?
        fi
    done
    return 0
}

__AWKDEF_FUNCTIONS='
function quote_html(s) {
  gsub(/&/, "\\&amp;", s)
  gsub(/"/, "\\&quot;", s)
  gsub(/>/, "\\&gt;", s)
  gsub(/</, "\\&lt;", s)
  return s
}
function unquote_html(s) {
  gsub(/&lt;/, "<", s)
  gsub(/&gt;/, ">", s)
  gsub(/&quot;/, "\"", s)
  gsub(/&amp;/, "\\&", s)
  return s
}
function quote_value(s) {'"
  gsub(/'/, \"'\\\\''\", s)
  return \"'\" s \"'\"
"'}
function quoted_values(             i, line) {
  line = ""
  for (i = 1; i <= NF; i++) {
    if (i > 1) line = line " "
    line = line quote_value($i)
  }
  return line
}
function quote_subrepl(s) {
  gsub(/\\/, "\\\\", s)
  gsub(/&/, "\\\\&", s)
  return s
}
function quote_grep(s) {
  gsub(/[[\\.^$*]/, "\\\\&", s)
  return s
}
function quote_egrep(s) {
  gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
  return s
}
function quote_sql(s) {'"
  gsub(/'/, \"''\", s)
  return \"'\" s \"'\"
"'}
function unquote_mysqlcsv(s) {
  gsub(/\\n/, "\n", s)
  gsub(/\\t/, "\t", s)
  gsub(/\\0/, "\0", s)
  gsub(/\\\\/, "\\", s)
  return s
}
function array_new(dest) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
}
function array_newsize(dest, size,              i) {
  dest[0] = 0 # forcer awk à considérer dest comme un tableau
  delete dest
  size = int(size)
  for (i = 1; i <= size; i++) {
    dest[i] = ""
  }
}
function array_len(values,    count, i) {
  count = 0
  for (i in values) {
    count++
  }
  return count
}
function mkindices(values, indices,        i, j) {
  array_new(indices)
  j = 1
  for (i in values) {
    indices[j++] = int(i)
  }
  return asort(indices)
}
function array_copy(dest, src,             count, indices, i) {
  array_new(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[indices[i]] = src[indices[i]]
  }
}
function array_getlastindex(src,           count, indices) {
  count = mkindices(src, indices)
  if (count == 0) return 0
  return indices[count]
}
function array_add(dest, value,              lastindex) {
  lastindex = array_getlastindex(dest)
  dest[lastindex + 1] = value
}
function array_deli(dest, i,                 l) {
  i = int(i)
  if (i == 0) return
  l = array_len(dest)
  while (i < l) {
    dest[i] = dest[i + 1]
    i++
  }
  delete dest[l]
}
function array_del(dest, value, ignoreCase,              i) {
  do {
    i = key_index(value, dest, ignoreCase)
    if (i != 0) array_deli(dest, i)
  } while (i != 0)
}
function array_extend(dest, src,             count, lastindex, indices, i) {
  lastindex = array_getlastindex(dest)
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    dest[lastindex + i] = src[indices[i]]
  }
}
function array_fill(dest,           i) {
  array_new(dest)
  for (i = 1; i <= NF; i++) {
    dest[i] = $i
  }
}
function array_getline(src,             count, indices, i, j) {
  $0 = ""
  count = mkindices(src, indices)
  for (i = 1; i <= count; i++) {
    j = indices[i]
    $j = src[j]
  }
}
function array_appendline(src,             count, indices, i, nf, j) {
  count = mkindices(src, indices)
  nf = NF
  for (i = 1; i <= count; i++) {
    j = nf + indices[i]
    $j = src[indices[i]]
  }
}
function in_array(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return 1
    }
  } else {
    for (i in values) {
      if (values[i] == value) return 1
    }
  }
  return 0
}
function key_index(value, values, ignoreCase,         i) {
  if (ignoreCase) {
    value = tolower(value)
    for (i in values) {
      if (tolower(values[i]) == value) return int(i)
    }
  } else {
    for (i in values) {
      if (values[i] == value) return int(i)
    }
  }
  return 0
}
function array2s(values, prefix, sep, suffix, noindices,     first, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  first = 1
  for (i in values) {
    if (first) first = 0
    else s = s sep
    if (!noindices) s = s "[" i "]="
    s = s values[i]
  }
  s = s suffix
  return s
}
function array2so(values, prefix, sep, suffix, noindices,      count, indices, i, s) {
  if (!prefix) prefix = "["
  if (!sep) sep = ", "
  if (!suffix) suffix = "]"
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    if (!noindices) s = s "[" indices[i] "]="
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function array_join(values, sep, prefix, suffix,            count, indices, i, s) {
  s = prefix
  count = mkindices(values, indices)
  for (i = 1; i <= count; i++) {
    if (i > 1) s = s sep
    s = s values[indices[i]]
  }
  s = s suffix
  return s
}
function printto(s, output) {
  if (output == "") {
    print s
  } else if (output ~ /^>>/) {
    sub(/^>>/, "", output)
    print s >>output
  } else if (output ~ /^>/) {
    sub(/^>/, "", output)
    print s >output
  } else {
    print s >output
  }
}
function find_line(input, field, value,              orig, line) {
  orig = $0
  line = ""
  while ((getline <input) > 0) {
    if ($field == value) {
      line = $0
      break
    }
  }
  close(input)
  $0 = orig
  return line
}
function merge_line(input, field, key,               line) {
  line = find_line(input, field, $key)
  if (line != "") $0 = $0 FS line
}
function __csv_parse_quoted(line, destl, colsep, qchar, echar,       pos, tmpl, nextc, resl) {
  line = substr(line, 2)
  resl = ""
  while (1) {
    pos = index(line, qchar)
    if (pos == 0) {
      resl = resl line
      destl[0] = ""
      destl[1] = 0
      return resl
    }
    if (echar != "" && pos > 1) {
      prevc = substr(line, pos - 1, 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (prevc == echar) {
        tmpl = substr(line, 1, pos - 2)
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
        continue
      }
      tmpl = substr(line, 1, pos - 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    } else {
      tmpl = substr(line, 1, pos - 1)
      quotec = substr(line, pos, 1)
      nextc = substr(line, pos + 1, 1)
      if (nextc == colsep || nextc == "") {
        resl = resl tmpl
        destl[0] = substr(line, pos + 2)
        destl[1] = nextc == colsep
        return resl
      } else if (nextc == qchar) {
        resl = resl tmpl quotec
        line = substr(line, pos + 2)
      } else {
        resl = resl tmpl quotec
        line = substr(line, pos + 1)
      }
    }
  }
}
function __csv_parse_unquoted(line, destl, colsep, qchar, echar,     pos) {
  pos = index(line, colsep)
  if (pos == 0) {
    destl[0] = ""
    destl[1] = 0
    return line
  } else {
    destl[0] = substr(line, pos + 1)
    destl[1] = 1
    return substr(line, 1, pos - 1)
  }
}
function __array_parsecsv(fields, line, nbfields, colsep, qchar, echar,     shouldparse, destl, i) {
  array_new(fields)
  array_new(destl)
  i = 1
  shouldparse = 0
  while (shouldparse || line != "") {
    if (index(line, qchar) == 1) {
      value = __csv_parse_quoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    } else {
      value = __csv_parse_unquoted(line, destl, colsep, qchar, echar)
      line = destl[0]
      shouldparse = destl[1]
    }
    fields[i] = value
    i = i + 1
  }
  if (nbfields) {
    nbfields = int(nbfields)
    i = array_len(fields)
    while (i < nbfields) {
      i++
      fields[i] = ""
    }
  }
  return array_len(fields)
}
BEGIN {
  DEFAULT_COLSEP = ","
  DEFAULT_QCHAR = "\""
  DEFAULT_ECHAR = ""
}
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
  if (colsep == "") colsep = DEFAULT_COLSEP
  if (qchar == "") qchar = DEFAULT_QCHAR
  if (echar == "") echar = DEFAULT_ECHAR
  return __array_parsecsv(fields, line, nbfields, colsep, qchar, echar)
}
function parsecsv(line,             fields) {
  array_parsecsv(fields, line)
  array_getline(fields)
  return NF
}
function getlinecsv(file,          fields) {
  if (file) {
    getline <file
  } else {
    getline
  }
  return parsecsv($0)
}
function __csv_should_quote(s) {
  if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
  if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
  return 0
}
function array_formatcsv2(fields, colsep, mvsep, qchar, echar,      count, indices, line, i, value) {
  line = ""
  count = mkindices(fields, indices)
  for (i = 1; i <= count; i++) {
    value = fields[indices[i]]
    if (i > 1) line = line colsep
    if (qchar != "" && index(value, qchar) != 0) {
      if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
      else gsub(qchar, "&&", value);
    }
    if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || __csv_should_quote(value))) {
      line = line qchar value qchar
    } else {
      line = line value
    }
  }
  return line
}
function array_formatcsv(fields) {
  return array_formatcsv2(fields, ",", ";", "\"", "")
}
function array_printcsv(fields, output) {
  printto(array_formatcsv(fields), output)
}
function get_formatcsv(                 fields) {
  array_fill(fields)
  return array_formatcsv(fields)
}
function formatcsv() {
  $0 = get_formatcsv()
}
function printcsv(output,           fields) {
  array_fill(fields)
  array_printcsv(fields, output)
}
function array_findcsv(fields, input, field, value, nbfields,          orig, found, i) {
  array_new(orig)
  array_fill(orig)
  array_new(fields)
  found = 0
  while ((getline <input) > 0) {
    array_parsecsv(fields, $0, nbfields)
    if (fields[field] == value) {
      found = 1
      break
    }
  }
  close(input)
  array_getline(orig)
  if (!found) {
    delete fields
    if (nbfields) {
      nbfields = int(nbfields)
      i = array_len(fields)
      while (i < nbfields) {
        i++
        fields[i] = ""
      }
    }
  }
  return found
}

function __and(var, x, l_res, l_i) {
  l_res=0;
  for (l_i=0; l_i < 8; l_i++){
    if (var%2 == 1 && x%2 == 1) l_res=l_res/2 + 128;
    else l_res/=2;
    var=int(var/2);
    x=int(x/2);
  }
  return l_res;
}
function __lshift(var, x) {
  while(x > 0){
    var*=2;
    x--;
  }
  return var;
}
function __rshift(var, x) {
  while(x > 0){
    var=int(var/2);
    x--;
  }
  return var;
}
BEGIN {
  __BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
}
function b64decode(src,      result, base1, base2, base3, base4) {
  result = ""
  while (length(src) > 0) {
    base1 = substr(src, 1, 1)
    base2 = substr(src, 2, 1)
    base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
    base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
    byte1 = index(__BASE64, base1) - 1
    if (byte1 < 0) byte1 = 0
    byte2 = index(__BASE64, base2) - 1
    if (byte2 < 0) byte2 = 0
    byte3 = index(__BASE64, base3) - 1
    if (byte3 < 0) byte3 = 0
    byte4 = index(__BASE64, base4) - 1
    if (byte4 < 0) byte4 = 0
    result = result sprintf( "%c", __lshift(__and(byte1, 63), 2) + __rshift(__and(byte2, 48), 4) )
    if (base3 != "=") result = result sprintf( "%c", __lshift(__and(byte2, 15), 4) + __rshift(__and(byte3, 60), 2) )
    if (base4 != "=") result = result sprintf( "%c", __lshift(__and(byte3, 3), 6) + byte4 )
    src = substr(src, 5)
  }
  return result
}
'
function awkdef() {

    if [ "${1:0:3}" == "-f" ]; then
        shift
        echo "$__AWKDEF_FUNCTIONS"
    fi
    if [ $# -gt 0 ]; then
        local __ad_arg __ad_vpos __ad_name __ad_value
        echo "BEGIN {"
        while [ -n "${1:0:1}" ]; do
            __ad_arg="${1:0:256}"
            local __ad_array=
            if [ "${__ad_arg%\[@\]}" != "$__ad_arg" ]; then
                __ad_array=1
                __ad_name="${__ad_arg%\[@\]}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *\[@\]=* ]]; then
                __ad_array=1
                __ad_name="${__ad_arg%%\[@\]=*}"
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_vpos=$((${#__ad_name} + 4))
                __ad_value="${1:$__ad_vpos}"
                [ ${#__ad_value} -ne 0 ] || __ad_value="$__ad_name"
            elif [[ "$__ad_arg" == *=* ]]; then
                local __ad_int= __ad_str=
                __ad_name="${__ad_arg%%=*}"
                __ad_vpos=$((${#__ad_name} + 1))
                if [ "${__ad_name%:int}" != "$__ad_name" ]; then
                    __ad_int=1
                    __ad_name="${__ad_name%:int}"
                elif [ "${__ad_name%:str}" != "$__ad_name" ]; then
                    __ad_str=1
                    __ad_name="${__ad_name%:str}"
                fi
                [ -z "${__ad_name//[a-zA-Z0-9_]/}" ] || break
                __ad_value="${1:$__ad_vpos}"
                if [ -n "$__ad_int" ]; then
                    echo "$__ad_name = int($(quoted_awk "$__ad_value") + 0)"
                elif [ -n "$__ad_str" ]; then
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                elif [ ${#__ad_value} -lt 256 ] && isnum "$__ad_value"; then
                    echo "$__ad_name = $__ad_value"
                else
                    echo "$__ad_name = $(quoted_awk "$__ad_value")"
                fi
            else
                break
            fi
            if [ -n "$__ad_array" ]; then
                if [ "${__ad_value:0:2}" == $'<\n' ]; then
                    local -a __ad_values
                    array_from_lines __ad_values "${__ad_value:2}"
                    __ad_value=__ad_values
                fi
                __ad_value="${__ad_value}[@]"
                local __ad_i=1
                echo "$__ad_name[0] = 0; delete $__ad_name"
                for __ad_arg in "${!__ad_value}"; do
                    echo "$__ad_name[$__ad_i]=$(quoted_awk "$__ad_arg")"
                    __ad_i=$(($__ad_i + 1))
                done
                eval "echo \"\${__ad_name}_count = \${#$__ad_value}\""
            fi
            shift
        done
        echo "}"
        for __ad_arg in "$@"; do
            rawecho "$__ad_arg"
        done
    fi
}
function lawkrun() {
    local -a __ar_defs __ar_args
    while [ $# -gt 0 -a "$1" != "--" ]; do
        __ar_defs=("${__ar_defs[@]}" "$1")
        shift
    done
    shift
    while [ $# -gt 0 ]; do
        __ar_args=("${__ar_args[@]}" "$1")
        shift
    done
    local __ar_script="$(awkdef "${__ar_defs[@]}")"
    awk "$__ar_script" "${__ar_args[@]}"
}
function cawkrun() { LANG=C lawkrun "$@"; }
function awkrun() { LANG=C lawkrun "$@"; }

function __lf_get_age() {
    local y=$(date "+%Y")
    local dy=$(date "+%j"); while [ "${dy#0}" != "$dy" ]; do dy="${dy#0}"; done
    [ -n "$dy" ] || dy=0
    local h=$(date "+%H"); while [ "${h#0}" != "$h" ]; do h="${h#0}"; done
    [ -n "$h" ] || h=0
    echo $((($y * 365 + $dy) * 24 + $h))
}
function lf_trylock() {
    local eoo lockfile max_hours=4
    while [ -n "$1" ]; do
        case "$1" in
        -h) shift; max_hours="$1";;
        --) shift; eoo=1;;
        *) eoo=1;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    lockfile="$1"
    [ -n "$lockfile" ] || die "il faut spécifier un fichier pour le verrou"

    local now="$(__lf_get_age)"
    if (set -C; echo "$now" >"$lockfile") 2>/dev/null; then
        return 0
    fi
    local prev diff
    if prev="$(<"$lockfile")"; then
        diff="$(($now - $prev))"
        if [ "$diff" -gt "$max_hours" ]; then
            echo stale
        else
            echo locked
        fi
    elif [ -f "$lockfile" ]; then
        echo retry
    fi
    return 1
}
function pidfile_set() {
    local eoo pidfile pid=$$ replace=
    while [ -n "$1" ]; do
        case "$1" in
        -p)
            shift
            pid="$1"
            ;;
        -r)
            replace=1
            ;;
        --)
            shift
            eoo=1
            ;;
        *)
            eoo=1
            ;;
        esac
        [ -n "$eoo" ] && break
        shift
    done

    pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        local curpid="$(<"$pidfile")"
        if is_running "$curpid"; then
            return 1
        elif [ -n "$replace" ]; then
            /bin/rm -f "$pidfile" || return 10
        else
            return 2
        fi
    fi

    echo_ "$pid" >"$pidfile" || return 10
    autoclean "$pidfile"
    return 0
}
function pidfile_check() {
    local pidfile="$1"
    [ -n "$pidfile" ] || return 10

    if [ -f "$pidfile" ]; then
        [ -r "$pidfile" ] || return 10
        local pid="$(<"$pidfile")"
        is_running "$pid" && return 0
    fi
    return 1
}
function page_maybe() {
    if isatty; then
        less -XF "$@"
    else
        cat
    fi
}


function utools_local() {
    local arg
    [ $# -gt 0 ] || set -- opts verbosity interaction
    for arg in "$@"; do
        case "$arg" in
        parse_opts|opts|o|args) echo "local -a args";;
        verbosity|v) echo "local __verbosity='$__verbosity'";;
        interaction|i) echo "local __interaction='$__interaction'";;
        esac
    done
}

function isatty() {
    tty -s <&1
}
function in_isatty() {
    tty -s
}
function out_isatty() {
    tty -s <&1
}
function err_isatty() {
    tty -s <&2
}
function die() { [ $# -gt 0 ] && eerror "$@"; exit 1; }
function exit_with { if [ $# -gt 0 ]; then "$@"; fi; exit $?; }
function die_with { [ $# -gt 0 ] && eerror "$1"; shift; [ $# -gt 0 ] && "$@"; exit 1; }
function die_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        exit 1
    elif [ $count -eq 1 ]; then
        "$@" || exit $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            exit $r
        fi
    fi
}
function eerror_unless() {
    local count=$#
    if [ $count -eq 0 ]; then
        return 1
    elif [ $count -eq 1 ]; then
        "$@" || return $?
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            :
        else
            r=$?
            eerror "$m"
            return $r
        fi
    fi
}
function die_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && exit 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            exit 1
        fi
    fi
}
function eerror_if() {
    local count=$#
    if [ $count -eq 0 ]; then
        :
    elif [ $count -eq 1 ]; then
        "$@" && return 1
    else
        local m r
        m="${@:$count}"
        count=$(($count - 1))
        set -- "${@:1:$count}"
        if "$@"; then
            eerror "$m"
            return 1
        fi
    fi
}

TAB=$'\t'
LATIN1=iso-8859-1
LATIN9=iso-8859-15
UTF8=utf-8
OENC="$UTF8"

if ! progexists iconv; then
    function iconv() { cat; }
fi

function __lang_encoding() {
    local lang="$(<<<"$LANG" awk '{ print tolower($0) }')"
    case "$lang" in
    *@euro) echo "iso-8859-15";;
    *.utf-8|*.utf8) echo "utf-8";;
    *) echo "iso-8859-1";;
    esac
}
function __norm_encoding() {
    awk '{
        enc = tolower($0)
        gsub(/^latin$/, "latin1", enc)
        gsub(/^latin1$/, "iso-8859-1", enc)
        gsub(/^latin9$/, "iso-8859-15", enc)
        gsub(/[-_]/, "", enc)
        if (enc == "iso8859" || enc == "iso88591" || enc == "8859" || enc == "88591") print "iso-8859-1"
        else if (enc == "iso885915"  || enc == "885915") print "iso-8859-15"
        else if (enc == "utf" || enc == "utf8") print "utf-8"
        else print $0
    }' <<<"$1"
}
function __init_encoding() {
    local DEFAULT_ENCODING="$(__lang_encoding)"
    [ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
    [ -n "$UTOOLS_OUTPUT_ENCODING" ] || UTOOLS_OUTPUT_ENCODING="$DEFAULT_ENCODING"
    UTOOLS_OUTPUT_ENCODING="$(__norm_encoding "$UTOOLS_OUTPUT_ENCODING")"
    [ -n "$UTOOLS_INPUT_ENCODING" ] || UTOOLS_INPUT_ENCODING="$UTOOLS_OUTPUT_ENCODING"
    UTOOLS_INPUT_ENCODING="$(__norm_encoding "$UTOOLS_INPUT_ENCODING")"
    [ -n "$UTOOLS_EDITOR_ENCODING" ] || UTOOLS_EDITOR_ENCODING="$UTOOLS_INPUT_ENCODING"
    UTOOLS_EDITOR_ENCODING="$(__norm_encoding "$UTOOLS_EDITOR_ENCODING")"

    IENC="$UTOOLS_INPUT_ENCODING"
    OENC="$UTOOLS_OUTPUT_ENCODING"
}

if [ -n "$UTOOLS_LANG" -a -z "$LANG" ]; then
    export UTOOLS_LANG
    export LANG="$UTOOLS_LANG"
fi
__init_encoding

function tooenc() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho "$src"
    else
        iconv -f "$from" -t "$to" <<<"$src"
    fi
}
function uecho() {
    tooenc "$*"
}
function tooenc_() {
    local src="$1" from="${2:-$OENC}" to="${3:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        rawecho_ "$src"
    else
        rawecho_ "$src" | iconv -f "$from" -t "$to"
    fi
}
function uecho_() {
    tooenc_ "$*"
}
function toienc() {
    local __tie_var="$1" __tie_to="${2:-$IENC}" __tie_from="${3:-$UTOOLS_INPUT_ENCODING}"
    if [ "$__tie_from" != "$__tie_to" ]; then
        set_var "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
    fi
}
function uread() {
    [ $# -gt 0 ] || set -- REPLY
    local __r_var
    read "$@"
    for __r_var in "$@"; do
        [ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
        toienc "$__r_var"
    done
}

function stooenc() {
    local from="${1:-$OENC}" to="${2:-$UTOOLS_OUTPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}
function stoienc() {
    local to="${1:-$IENC}" from="${2:-$UTOOLS_INPUT_ENCODING}"
    if [ "$from" == "$to" ]; then
        cat
    else
        iconv -f "$from" -t "$to"
    fi
}

export UTOOLS_EDATE
function __edate() { [ -n "$UTOOLS_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }

export UTOOLS_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
    UTOOLS_EDATE=1
    if [ -n "$1" -a -n "$2" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>"$2"
        else
            exec >>"$1" 2>>"$2"
        fi
    elif [ -n "$1" ]; then
        LANG=fr_FR.UTF8
        UTOOLS_OUTPUT_ENCODING="$UTF8"
        __set_no_colors 1
        if [ -n "$UTOOLS_ELOG_OVERWRITE" ]; then
            exec >"$1" 2>&1
        else
            exec >>"$1" 2>&1
        fi
    fi
}

export __estack __tlevel
function __indent() {
    if [ "${1/
/}" != "$1" ]; then
        sed "2,\$s/^/${__tlevel}/g" <<<"$1"
    else
        rawecho "$1"
    fi
}
function __eerror() { tooenc "$(__edate)${__tlevel}* error: $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}* warning: $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}* note: $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}* important: $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}* attention: $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}* info: $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}* debug: $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe() { __estep "$@"; }
function __estepw() { __estep "$@"; }
function __estepn() { __estep "$@"; }
function __estepi() { __estep "$@"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1")"; }
function __estepe_() { __estep_ "$@"; }
function __estepw_() { __estep_ "$@"; }
function __estepn_() { __estep_ "$@"; }
function __estepi_() { __estep_ "$@"; }
function __etitle() { tooenc "$(__edate)${__tlevel}+++ $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}* $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "w"; }
function __edotx() { echo_ "x"; }
function __edotp() { echo_ "+"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "[ok]"; }
function __eendx() { echo "[error]"; }
PRETTYOPTS=()
function set_verbosity() { :;}
function set_interaction() { :;}
function show_error() {
    return 0
}
function show_warn() {
    return 0
}
function show_info() {
    return 0
}
function show_verbose() {
    return 0
}
function show_debug() {
    [ -n "$DEBUG" ]
}
function check_verbosity() {
    return 0
}
function get_verbosity_option() { :;}
function check_interaction() {
    return 0
}
function is_interaction() {
    return 1
}
function get_interaction_option() { :;}
__epending=
function eflush() {
    if [ -n "$__epending" ]; then rawecho "$__epending" 1>&2; __epending=; fi
}
function eclearp() {
    __epending=
}
function eerror() {
    show_error || return; eflush; __eerror "$*" 1>&2
}
function ewarn() {
    show_warn || return; eflush; __ewarn "$*" 1>&2
}
function enote() {
    show_info || return; eflush; __enote "$*" 1>&2
}
function ebanner() {
    show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
}
function eimportant() {
    show_error || return; eflush; __eimportant "$*" 1>&2
}
function eattention() {
    show_warn || return; eflush; __eattention "$*" 1>&2
}
function einfo() {
    show_info || return; eflush; __einfo "$*" 1>&2
}
function eecho() {
    show_info || return; eflush; __eecho "$*" 1>&2
}
function eecho_() {
    show_info || return; eflush; __eecho_ "$*" 1>&2
}
function edebug() {
    show_debug || return; eflush; __edebug "$*" 1>&2
}
function trace() {
    local r cmd="$(quoted_args "$@")"
    show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        if show_info; then
            eflush; __eecho "^ [EC #$r]" 1>&2
        elif show_error; then
            eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
        fi
    fi
    return $r
}
function trace_error() {
    local r
    "$@"; r=$?
    if [ $r -ne 0 ]; then
        local cmd="$(quoted_args "$@")"
        show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
    fi
    return $r
}

function etitle() {
    local __t_deferred=
    __t_etitle "$@"
}
function etitled() {
    local __t_deferred=1
    __t_etitle "$@"
}
function __t_etitle() {
    local __t_eend=default
    local __t_clearp=
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __t_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __t_eend=1
            shift
        elif [ "$1" == "-p" ]; then
            __t_clearp=1
            shift
        else
            break
        fi
    done
    local __t_title="$1"; shift
    local __t_s=0
    [ -n "$__estack" ] && __tlevel="${__tlevel}    "
    __estack="$__estack:t"
    if show_info; then
        if [ -n "$__t_deferred" ]; then
            __epending="${__epending:+$__epending
}$(__etitle "$__t_title")"
        else
            eflush
            __etitle "$__t_title" 1>&2
        fi
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __t_s=$?
        [ "$__t_eend" == "default" ] && __t_eend=1
    fi
    [ "$__t_eend" == "default" ] && __t_eend=
    if [ -n "$__t_eend" ]; then
        eend $__t_s
        [ -n "$__t_clearp" ] && eclearp
    fi
    return $__t_s
}
function estep() {
    show_info || return; eflush; __estep "$*" 1>&2
}
function estepe() {
    show_info || return; eflush; __estepe "$*" 1>&2
}
function estepw() {
    show_info || return; eflush; __estepw "$*" 1>&2
}
function estepn() {
    show_info || return; eflush; __estepn "$*" 1>&2
}
function estepi() {
    show_info || return; eflush; __estepi "$*" 1>&2
}
function estep_() {
    show_info || return; eflush; __estep_ "$*" 1>&2
}
function estepe_() {
    show_info || return; eflush; __estepe_ "$*" 1>&2
}
function estepw_() {
    show_info || return; eflush; __estepw_ "$*" 1>&2
}
function estepn_() {
    show_info || return; eflush; __estepn_ "$*" 1>&2
}
function estepi_() {
    show_info || return; eflush; __estepi_ "$*" 1>&2
}
function ebegin() {
    local __b_eend=default
    while [ -n "$1" ]; do
        if [ "$1" == "--" ]; then
            shift
            break
        elif [ "$1" == "-s" ]; then
            __b_eend=
            shift
        elif [ "$1" == "--eend" ]; then
            __b_eend=1
            shift
        else
            break
        fi
    done
    local __b_msg="$1"; shift
    local __b_s=0
    __estack="$__estack:b"
    if show_info; then
        eflush
        __ebegin "$__b_msg" 1>&2
    fi
    if [ $# -gt 0 ]; then
        "$@"
        __b_s=$?
        [ "$__b_eend" == "default" ] && __b_eend=1
    fi
    [ "$__b_eend" == "default" ] && __b_eend=
    [ -n "$__b_eend" ] && eend $__b_s
    return $__b_s
}
function edot() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    if [ "$s" == "0" ]; then
        __edoto 1>&2
    else
        __edotx 1>&2
    fi
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function edotw() {
    local s=$?
    show_info || return
    eflush
    [ -n "$1" ] && s="$1"
    shift
    __edotw 1>&2
    show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
    return $s
}
function ewait() {
    [ -n "$1" ] || return 1
    if show_info; then
        local count=2
        eflush
        little_sleep # certains processus retournent tout de suite
        while is_running "$1"; do
            sleep 1
            if [ $count -gt 0 ]; then
                count=$(($count - 1))
            else
                __edotp 1>&2
            fi
        done
        __edoto 1>&2
    else
        wait "$1"
    fi
}
function eend() {
    local s=$?
    if [ "$1" == "-c" ]; then
        __estack=
        __tlevel=
    elif [ "${__estack%:b}" != "$__estack" ]; then
        __estack="${__estack%:b}"
        show_info || return
        eflush
        [ -n "$1" ] && s="$1"
        if [ "$s" == "0" ]; then
            __eendo 1>&2
        else
            __eendx 1>&2
        fi
    elif [ "${__estack%:t}" != "$__estack" ]; then
        __estack="${__estack%:t}"
        __tlevel="${__tlevel%    }"
    fi
}
function ask_yesno() {
    local interactive=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || interactive=
        fi
        shift
    else
        check_interaction -c || interactive=
    fi
    local default="${2:-N}"
    if [ "$default" == "C" ]; then
        [ -n "$interactive" ] && default=N || default=O
    elif [ "$default" == "X" ]; then
        [ -n "$interactive" ] && default=O || default=N
    fi
    if [ -n "$interactive" ]; then
        eflush
        local message="$1"
        local prompt="[oN]"
        local r
        is_yes "$default" && prompt="[On]"
        if [ -n "$message" ]; then
            tooenc_ "$message" 1>&2
        else
            tooenc_ "Voulez-vous continuer?" "$UTF8" 1>&2
        fi
        tooenc_ " $prompt " "$UTF8" 1>&2
        uread r
        is_yes "${r:-$default}"
    else
        is_yes "$default"
    fi
}
function read_value() {
    local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
    __rv_opts=()
    [ -n "$UTOOLS_NO_READLINE" ] && __rv_readline=
    __rv_read "$@"
}
function read_password() {
    local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
    __rv_opts=(-s)
    __rv_read "$@"
}
function __rv_read() {
    local __rv_int=1
    if [[ "$1" == -* ]]; then
        if [ "$1" != -- ]; then
            check_interaction "$1" || __rv_int=
        fi
        shift
    else
        check_interaction -c || __rv_int=
    fi
    local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
    if [ -z "$__rv_int" ]; then
        if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
            OENC="$UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
            return 1
        fi
        set_var "$__rv_v" "$__rv_d"
        return 0
    fi

    eflush
    local __rv_r
    while true; do
        if [ -n "$__rv_msg" ]; then
            tooenc_ "$__rv_msg" 1>&2
        else
            tooenc_ "Entrez la valeur" "$UTF8" 1>&2
        fi
        if [ -n "$__rv_readline" ]; then
            tooenc_ ": " "$UTF8" 1>&2
            uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
        else
            if [ -n "$__rv_d" ]; then
                if [ -n "$__rv_showdef" ]; then
                    tooenc_ " [$__rv_d]" 1>&2
                else
                    tooenc_ " [****]" 1>&2
                fi
            fi
            tooenc_ ": " "$UTF8" 1>&2
            uread "${__rv_opts[@]}" __rv_r
            [ -n "$__rv_nl" ] && echo
        fi
        __rv_r="${__rv_r:-$__rv_d}"
        if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
            set_var "$__rv_v" "$__rv_r"
            return 0
        fi
    done
}
function simple_menu() {
    local __sm_title= __sm_yourchoice= __sm_default=
    local -a __sm_args
    parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
    set -- "${__sm_args[@]}" || ewarn "$__sm_args"

    local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
    local __sm_option __sm_options
    __sm_options="$__sm_options_var[*]"
    if [ -z "${!__sm_options}" ]; then
        OENC="$UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
        return 1
    fi
    [ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"

    eflush
    array_copy __sm_options "$__sm_options_var"
    local __sm_c=0 __sm_i __sm_choice
    while true; do
        if [ "$__sm_c" == "0" ]; then
            [ -n "$__sm_title" ] && tooenc "=== $__sm_title ===" 1>&2
            __sm_i=1
            for __sm_option in "${__sm_options[@]}"; do
                if [ "$__sm_option" == "$__sm_default" ]; then
                    tooenc "$__sm_i*- $__sm_option" 1>&2
                else
                    tooenc "$__sm_i - $__sm_option" 1>&2
                fi
                let __sm_i=$__sm_i+1
            done
        fi

        if [ -n "$__sm_yourchoice" ]; then
            tooenc_ "$__sm_yourchoice" 1>&2
        else
            tooenc_ "Entrez le numéro de l'option choisie" "$UTF8" 1>&2
        fi
        tooenc_ ": " "$UTF8" 1>&2
        uread __sm_choice

        if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
            __sm_option="$__sm_default"
            break
        fi
        if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
            if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
                __sm_option="${__sm_options[$(($__sm_choice - 1))]}"
                break
            else
                OENC="$UTF8" eerror "Numéro d'option incorrect"
            fi
        else
            OENC="$UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
        fi

        let __sm_c=$__sm_c+1
        if [ "$__sm_c" -eq 5 ]; then
            tooenc "" "$UTF8" 1>&2
            __sm_c=0
        fi
    done
    set_var "$__sm_option_var" "$__sm_option"
}

function actions_menu() {
    local -a __am_action_descs __am_options __am_void_actions
    local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
    local __am_default_action=auto __am_quit_action=auto
    local __am_default_option=
    local -a __am_args
    parse_opts \
        -t: __am_title= \
        -m: __am_optyc= \
        -M: __am_actyc= \
        -e: __am_void_actions \
        -d: __am_default_action= \
        -q: __am_quit_action= \
        -o: __am_default_option= \
        @ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }

    __am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
    __am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
    [ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
    array_copy __am_action_descs "${3:-actions}"
    array_copy __am_options "${4:-options}"

    eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
    __actions_menu || return 1
    setv "${1:-action}" "$__am_select_action"
    setv "${2:-option}" "$__am_select_option"
}
function __actions_menu() {
    local title="$__am_title"
    local optyc="$__am_optyc" actyc="$__am_actyc"
    local default_action="$__am_default_action"
    local quit_action="$__am_quit_action"
    local select_action="$__am_select_action"
    local select_option="$__am_select_option"
    local -a action_descs options void_actions
    array_copy action_descs __am_action_descs
    array_copy options __am_options
    array_copy void_actions __am_void_actions

    local no_options
    array_isempty options && no_options=1

    local -a actions
    local tmp action name
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        action="$(strlower "$action")"
        array_addu actions "$action"
    done

    if [ "$default_action" == auto ]; then
        default_action="$select_action"
        if [ -n "$default_action" ]; then
            array_contains actions "$default_action" || default_action=
        fi
        [ -n "$default_action" ] || default_action="${actions[0]}"
    fi
    default_action="${default_action:0:1}"
    default_action="$(strlower "$default_action")"

    if [ "$quit_action" == auto ]; then
        if [ ${#actions[*]} -gt 1 ]; then
            quit_action="${actions[@]:$((-1)):1}"
            array_addu void_actions "$quit_action"
        fi
    fi
    quit_action="${quit_action:0:1}"
    quit_action="$(strlower "$quit_action")"

    local action_title
    for tmp in "${action_descs[@]}"; do
        splitfsep2 "$tmp" : action name
        [ -n "$action" ] || action="${name:0:1}"
        [ -n "$name" ] || name="$action"
        action="$(strlower "$action")"
        if [ -n "$no_options" ]; then
            if ! array_contains void_actions "$action"; then
                array_del actions "$action"
                continue
            fi
        fi
        [ "$action" == "$default_action" ] && name="$name*"
        action_title="${action_title:+$action_title/}$name"
    done
    if [ -n "$default_action" ]; then
        array_contains actions "$default_action" || default_action=
    fi
    if [ -n "$quit_action" ]; then
        array_contains actions "$quit_action" || quit_action=
    fi

    if [ -n "$no_options" ]; then
        if array_isempty void_actions; then
            eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
            return 1
        fi
        __void_actions_menu
    else
        __options_actions_menu
    fi
}
function __void_actions_menu() {
    eflush
    local c=0 choice
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            __eecho_ "=== Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$actyc" ]; then
            __eecho_ "$actyc" 1>&2
        elif [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action à effectuer" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice
        if [ -z "$choice" -a -n "$default_action" ]; then
            select_action="$default_action"
            break
        fi

        choice="${choice:0:1}"
        choice="$(strlower "$choice")"
        if array_contains actions "$choice"; then
            select_action="$choice"
            break
        elif [ -n "$choice" ]; then
            eerror "$choice: action incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option=
}
function __options_actions_menu() {
    eflush
    local c=0 option choice action option
    while true; do
        if [ $c -eq 0 ]; then
            [ -n "$title" ] && __etitle "$title" 1>&2
            i=1
            for option in "${options[@]}"; do
                if [ "$option" == "$select_option" ]; then
                    tooenc "$i*- $option" 1>&2
                else
                    tooenc "$i - $option" 1>&2
                fi
                let i=$i+1
            done
            __estepn_ "Actions disponibles: " 1>&2
            tooenc "$action_title" 1>&2
        fi
        if [ -n "$optyc" ]; then
            __eecho_ "$optyc" 1>&2
        else
            __eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
        fi
        tooenc_ ": " 1>&2
        uread choice

        if [ -z "$choice" -a -n "$default_action" ]; then
            action="$default_action"
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            elif [ -n "$select_option" ]; then
                select_action="$action"
                break
            fi
        fi
        action="${choice:0:1}"
        action="$(strlower "$action")"
        if array_contains actions "$action"; then
            if array_contains void_actions "$action"; then
                select_action="$action"
                select_option=
                break
            else
                option="${choice:1}"
                option="${option// /}"
                if [ -z "$option" -a -n "$select_option" ]; then
                    select_action="$action"
                    break
                elif [ -z "$option" ]; then
                    eerror "vous devez saisir le numéro de l'option"
                elif isnum "$option"; then
                    if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                        select_action="$action"
                        select_option="${options[$(($option - 1))]}"
                        break
                    fi
                else
                    eerror "$option: numéro d'option incorrecte"
                fi
            fi
        elif isnum "$choice"; then
            action="$default_action"
            if [ -n "$action" ]; then
                if array_contains void_actions "$action"; then
                    select_action="$action"
                    select_option=
                    break
                else
                    option="${choice// /}"
                    if [ -z "$option" ]; then
                        eerror "vous devez saisir le numéro de l'option"
                    elif isnum "$option"; then
                        if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
                            select_action="$action"
                            select_option="${options[$(($option - 1))]}"
                            break
                        fi
                    else
                        eerror "$option: numéro d'option incorrecte"
                    fi
                fi
            else
                eerror "Vous devez spécifier l'action à effectuer"
            fi
        elif [ -n "$choice" ]; then
            eerror "$choice: action et/ou option incorrecte"
        else
            eerror "vous devez saisir l'action à effectuer"
        fi
        let c=$c+1
        if [ $c -eq 5 ]; then
            tooenc "" 1>&2
            c=0
        fi
    done
    __am_select_action="$select_action"
    __am_select_option="$select_option"
}


function __ac_forgetall() { __ac_files=(); }
__ac_forgetall
function __ac_trap() {
    local file
    for file in "${__ac_files[@]}"; do
        [ -e "$file" ] && rm -rf "$file" 2>/dev/null
    done
    __ac_forgetall
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
    local file
    for file in "$@"; do
        [ -n "$file" ] && array_add __ac_files "$file"
    done
}
function ac_cleanall() {
    __ac_trap
}
function ac_clean() {
    local file
    for file in "$@"; do
        if array_contains __ac_files "$file"; then
            [ -e "$file" ] && rm -rf "$file" 2>/dev/null
            array_del __ac_files "$file"
        fi
    done
}
function ac_set_tmpfile() {
    local __acst_d
    if show_debug; then
        if [ -n "$5" ]; then
            is_yes "${!5}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        [ -f "$3" -a "$4" == keep ] || >"$3"
    else
        local __acst_t="$(mktempf "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function ac_set_tmpdir() {
    local __acst_d
    if show_debug; then
        if [ -n "$4" ]; then
            is_yes "${!4}" && __acst_d=1
        else
            __acst_d=1
        fi
    fi
    if [ -n "$__acst_d" -a -n "$3" ]; then
        set_var "$1" "$3"
        mkdir -p "$3"
    else
        local __acst_t="$(mktempd "$2")"
        autoclean "$__acst_t"
        set_var "$1" "$__acst_t"
    fi
}
function debug_tee() {
    if show_debug; then
        tee "$@"
    else
        cat
    fi
}


function get_defaults_files() {
    local __gd_dest="${1:-defaults}"; shift
    local -a __gd_fs
    local __gd_f __gd_found
    for __gd_f in "$@"; do
        __gd_found=
        if [ -r "/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -r "$HOME/etc/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$HOME/etc/default/$__gd_f")
            __gd_found=1
        fi
        if [ -z "$__gd_found" -a -r "$scriptdir/lib/default/$__gd_f" ]; then
            __gd_fs=("${__gd_fs[@]}" "$scriptdir/lib/default/$__gd_f")
        fi
    done
    array_copy "$__gd_dest" __gd_fs
}

function set_defaults() {
    local -a __sd_fs
    local __sd_f
    get_defaults_files __sd_fs "$@"
    for __sd_f in "${__sd_fs[@]}"; do
        source "$__sd_f"
    done
}


: "${MYHOST:=$HOSTNAME}"
: "${MYHOSTNAME:=${MYHOST%%.*}}"
export MYHOST MYHOSTNAME

function myhost() {
    hostname -f 2>/dev/null || echo "$MYHOST"
}
function myhostname() {
    hostname -s 2>/dev/null || echo "$MYHOSTNAME"
}
##@inc]base
##@inc[pretty
## Affichage en couleur, et support de niveaux de "verbosité" et d'interaction
##@require base
uprovide pretty
urequire base


function __get_color() {
    [ -z "$*" ] && set RESET
    echo_ $'\e['
    local sep
    while [ -n "$1" ]; do
        [ -n "$sep" ] && echo_ ";"
        case "$1" in
        z|RESET) echo_ "0";;
        o|BLACK) echo_ "30";;
        r|RED) echo_ "31";;
        g|GREEN) echo_ "32";;
        y|YELLOW) echo_ "33";;
        b|BLUE) echo_ "34";;
        m|MAGENTA) echo_ "35";;
        c|CYAN) echo_ "36";;
        w|WHITE) echo_ "37";;
        DEFAULT) echo_ "39";;
        O|BLACK_BG) echo_ "40";;
        R|RED_BG) echo_ "41";;
        G|GREEN_BG) echo_ "42";;
        Y|YELLOW_BG) echo_ "43";;
        B|BLUE_BG) echo_ "44";;
        M|MAGENTA_BG) echo_ "45";;
        C|CYAN_BG) echo_ "46";;
        W|WHITE_BG) echo_ "47";;
        DEFAULT_BG) echo_ "49";;
        @|BOLD) echo_ "1";;
        -|FAINT) echo_ "2";;
        _|UNDERLINED) echo_ "4";;
        ~|REVERSE) echo_ "7";;
        n|NORMAL) echo_ "22";;
        esac
        sep=1
        shift
    done
    echo_ "m"
}
function get_color() {
    [ -n "$NO_COLORS" ] && return
    __get_color "$@"
}
function __set_no_colors() {
    if [ -z "$1" ]; then
        if [ -n "$UTOOLS_NO_COLORS" ]; then NO_COLORS=1
        elif out_isatty && err_isatty; then NO_COLORS=
        else NO_COLORS=1
        fi
    else
        is_yes "$1" && NO_COLORS=1 || NO_COLORS=
    fi
    COULEUR_ROUGE="$(get_color RED BOLD)"
    COULEUR_VERTE="$(get_color GREEN BOLD)"
    COULEUR_JAUNE="$(get_color YELLOW BOLD)"
    COULEUR_BLEUE="$(get_color BLUE BOLD)"
    COULEUR_BLANCHE="$(get_color WHITE BOLD)"
    COULEUR_NORMALE="$(get_color RESET)"
}
__set_no_colors

function __eerror() { tooenc "$(__edate)${__tlevel}${COULEUR_ROUGE}* error:${COULEUR_NORMALE} $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}${COULEUR_JAUNE}* warning:${COULEUR_NORMALE} $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}${COULEUR_VERTE}* note:${COULEUR_NORMALE} $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$COULEUR_ROUGE$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix$COULEUR_NORMALE"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}${COULEUR_ROUGE}* important:${COULEUR_NORMALE} $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}${COULEUR_JAUNE}* attention:${COULEUR_NORMALE} $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}${COULEUR_BLEUE}* info:${COULEUR_NORMALE} $(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}${COULEUR_BLANCHE}* debug:${COULEUR_NORMALE} $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}${COULEUR_BLANCHE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepe() { tooenc "$(__edate)${__tlevel}${COULEUR_ROUGE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepw() { tooenc "$(__edate)${__tlevel}${COULEUR_JAUNE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepn() { tooenc "$(__edate)${__tlevel}${COULEUR_VERTE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepi() { tooenc "$(__edate)${__tlevel}${COULEUR_BLEUE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_BLANCHE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepe_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_ROUGE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepw_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_JAUNE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepn_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_VERTE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepi_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_BLEUE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __etitle() { tooenc "$(__edate)${__tlevel}${COULEUR_BLEUE}+++ $(get_color _)$(__indent "$1")${COULEUR_NORMALE}"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}${COULEUR_BLANCHE}*${COULEUR_NORMALE} $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "${COULEUR_JAUNE}w${COULEUR_NORMALE}"; }
function __edotx() { echo_ "${COULEUR_ROUGE}x${COULEUR_NORMALE}"; }
function __edotp() { echo_ "${COULEUR_JAUNE}+${COULEUR_NORMALE}"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "${COULEUR_VERTE}[ok]${COULEUR_NORMALE}"; }
function __eendx() { echo "${COULEUR_ROUGE}[error]${COULEUR_NORMALE}"; }

export __verbosity
[ -z "$__verbosity" ] && __verbosity=3
function set_verbosity() {
    [ -z "$__verbosity" ] && __verbosity=3
    case "$1" in
    -Q|--very-quiet) __verbosity=0;;
    -q|--quiet) [ "$__verbosity" -gt 0 ] && let __verbosity=$__verbosity-1;;
    -v|--verbose) [ "$__verbosity" -lt 5 ] && let __verbosity=$__verbosity+1;;
    -c|--default) __verbosity=3;;
    -D|--debug) __verbosity=5; DEBUG=1;;
    *) return 1;;
    esac
    return 0
}
export __interaction
[ -z "$__interaction" ] && __interaction=2
function set_interaction() {
    [ -z "$__interaction" ] && __interaction=2
    case "$1" in
    -b|--batch) __interaction=0;;
    -y|--automatic) [ "$__interaction" -gt 0 ] && let __interaction=$__interaction-1;;
    -i|--interactive) [ "$__interaction" -lt 3 ] && let __interaction=$__interaction+1;;
    -c|--default) __interaction=2;;
    *) return 1;;
    esac
    return 0
}
PRETTYOPTS=(
    -L:,--log-to: '$elogto $value_'
    -Q,--very-quiet,-q,--quiet,-v,--verbose,-D,--debug '$set_verbosity $option_'
    -b,--batch,-y,--automatic,-i,--interactive '$set_interaction $option_'
)

function show_error() { [ "$__verbosity" -ge 1 ]; }
function show_warn() { [ "$__verbosity" -ge 2 ]; }
function show_info() { [ "$__verbosity" -ge 3 ]; }
function show_verbose() { [ "$__verbosity" -ge 4 ]; }
function show_debug() { [ -n "$DEBUG" -o "$__verbosity" -ge 5 ]; }
function check_verbosity() {
    case "$1" in
    -Q|--very-quiet) [ "$__verbosity" -ge 1 ];;
    -q|--quiet) [ "$__verbosity" -ge 2 ];;
    -c|--default) [ "$__verbosity" -ge 3 ];;
    -v|--verbose) [ "$__verbosity" -ge 4 ];;
    -D|--debug) [ -n "$DEBUG" -o "$__verbosity" -ge 5 ];;
    *) return 0;;
    esac
}
function get_verbosity_option() {
    case "$__verbosity" in
    0) echo --very-quiet;;
    1) echo --quiet --quiet;;
    2) echo --quiet;;
    4) echo --verbose;;
    5) echo --debug;;
    esac
}
function check_interaction() {
     case "$1" in
    -b|--batch) return 0;;
    -y|--automatic) [ -n "$__interaction" -a "$__interaction" -ge 1 ];;
    -c|--default) [ -n "$__interaction" -a "$__interaction" -ge 2 ];;
    -i|--interactive) [ -n "$__interaction" -a "$__interaction" -ge 3 ];;
    *) return 0;;
    esac
}
function is_interaction() {
     case "$1" in
    -b|--batch) [ -n "$__interaction" -a "$__interaction" -eq 0 ];;
    -Y) [ -n "$__interaction" -a "$__interaction" -le 1 ];;
    -y|--automatic) [ -n "$__interaction" -a "$__interaction" -eq 1 ];;
    -c|--default) [ -n "$__interaction" -a "$__interaction" -eq 2 ];;
    -i|--interactive) [ -n "$__interaction" -a "$__interaction" -eq 3 ];;
    -C) [ -n "$__interaction" -a "$__interaction" -ge 2 ];;
    *) return 1;;
    esac
}
function get_interaction_option() {
    case "$__interaction" in
    0) echo --batch;;
    1) echo --automatic;;
    3) echo --interactive;;
    esac
}

##@inc]pretty
##@inc[sysinfos
## Gestion des informations sur l'hôte local
##@require base
uprovide sysinfos
urequire base


SYSNAMES=(linux linux64 linux32 linuxppc64 linuxppc32 linuxarm macosx)
linux_SYSDISTS=(debianlike debian ubuntu redhatlike rhel fedora centos suse gentoo)
linux32_SYSDISTS=(debianlike debian ubuntu redhatlike rhel fedora centos suse gentoo)
linux64_SYSDISTS=(debianlike debian ubuntu redhatlike rhel fedora centos suse gentoo)
linuxppc32_SYSDISTS=(debianlike debian ubuntu redhatlike fedora)
linuxppc64_SYSDISTS=(debianlike debian ubuntu redhatlike fedora)
linuxarm_SYSDISTS=(debianlike debian ubuntu)
macosx_SYSDISTS=(lion snowleopard leopard tiger panther)
SYSDIST_ALIASES=(
    10.7=lion 10.6=snowleopard 10.5=leopard 10.4=tiger 10.3=panther
)
debianlike_SYSVERS=()
debian_SYSVERS=(wheezy squeeze lenny etch)
ubuntu_SYSVERS=(oneiric natty maverick lucid karmic jaunty intrepid hardy)
redhatlike_SYSVERS=()
rhel_SYSVERS=(rhel6 rhel5 rhel4 redhat6 redhat5 redhat4)
fedora_SYSVERS=(fedora14 fedora13 fedora12 fedora11)
centos_SYSVERS=(centos6 centos5 centos4 redhat6 redhat5 redhat4)
suse_SYSVERS=()
gentoo_SYSVERS=()
SYSVER_ALIASES=(
    7=wheezy 6=squeeze 5=lenny 4=etch
    11.10=oneiric 11.04=natty 10.10=maverick 10.04=lucid 9.10=karmic 9.04=jaunty 8.10=intrepid 8.04=hardy
)

function __setup_ALL_SYSvars() {
    local s ds d fs f
    ALL_SYSDISTS=()
    for s in "${SYSNAMES[@]}"; do
        array_copy ds "${s}_SYSDISTS"
        for d in "${ds[@]}"; do
            array_set ALL_SYSDISTS "$d"
        done
    done
    ALL_SYSVERS=()
    for d in "${ALL_SYSDISTS[@]}"; do
        array_copy fs "${d}_SYSVERS"
        for f in "${fs[@]}"; do
            array_contains ALL_SYSVERS "$f" && array_del ALL_SYSVERS "$f"
            array_add ALL_SYSVERS "$f"
        done
    done
}
__setup_ALL_SYSvars
unset -f __setup_ALL_SYSvars

MYSYSNAME=()
MYBITS=
MYSYSDIST=()
MYSYSVER=()
if [ "$UNAME_SYSTEM" == "Linux" ]; then
    case "$UNAME_MACHINE" in
    x86_64)
        MYSYSNAME=(linux64 linux)
        MYBITS=64
        ;;
    i386|i586|i686)
        MYSYSNAME=(linux32 linux)
        MYBITS=32
        ;;
    ppc)
        MYSYSNAME=(linuxppc32 linuxppc linux)
        MYBITS=32
        ;;
    ppc64)
        MYSYSNAME=(linuxppc64 linuxppc linux)
        MYBITS=64
        ;;
    arm*)
        MYSYSNAME=(linuxarm linux)
        ;;
    *)
        MYSYSNAME=(linux)
        ;;
    esac

    if [ -f /etc/debian_version ]; then
        case "$(</etc/debian_version)" in
        7*|wheezy*) MYSYSDIST=(debian debianlike); MYSYSVER=(wheezy);;
        6*|squeeze*) MYSYSDIST=(debian debianlike); MYSYSVER=(squeeze);;
        5*) MYSYSDIST=(debian debianlike); MYSYSVER=(lenny);;
        4*) MYSYSDIST=(debian debianlike); MYSYSVER=(etch);;
        *) MYSYSDIST=(debianlike);;
        esac
    elif [ -f /etc/gentoo-release ]; then
        MYSYSDIST=(gentoo)
    elif [ -f /etc/redhat-release ]; then
        case "$(</etc/redhat-release)" in
        Fedora*) MYSYSDIST=(fedora redhatlike);;
        Red*Hat*Enterprise*Linux*) MYSYSDIST=(rhel redhatlike);;
        CentOS*) MYSYSDIST=(centos redhatlike);;
        *) MYSYSDIST=(redhatlike);;
        esac
        case "$(</etc/redhat-release)" in
        Fedora*14*) MYSYSVER=(fedora14);;
        Fedora*13*) MYSYSVER=(fedora13);;
        Fedora*12*) MYSYSVER=(fedora12);;
        Fedora*11*) MYSYSVER=(fedora11);;
        Red*Hat*Enterprise*Linux*release\ 6*) MYSYSVER=(rhel6 redhat6);;
        Red*Hat*Enterprise*Linux*release\ 5*) MYSYSVER=(rhel5 redhat5);;
        Red*Hat*Enterprise*Linux*release\ 4*) MYSYSVER=(rhel4 redhat4);;
        CentOS*release\ 6*) MYSYSVER=(centos6 redhat6);;
        CentOS*release\ 5*) MYSYSVER=(centos5 redhat5);;
        CentOS*release\ 4*) MYSYSVER=(centos4 redhat4);;
        esac
    fi
elif [ "$UNAME_SYSTEM" == "Darwin" ]; then
    function get_macosx_version() {
        local i
        for i in /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Resources/version.plist /System/Library/Frameworks/CoreServices.framework/Resources/version.plist; do
            if [ -f "$i" ]; then
                grep -A 1 CFBundleShortVersionString "$i" | grep string | sed 's/.*<string>//g
s/<\/string>.*$//g'
                break
            fi
        done
    }
    MYSYSNAME=(macosx darwin)
    case "$(get_macosx_version)" in
    10.7*) MYSYSDIST=(lion);;
    10.6*) MYSYSDIST=(snowleopard);;
    10.5*) MYSYSDIST=(leopard);;
    10.4*) MYSYSDIST=(tiger);;
    10.3*) MYSYSDIST=(panther);;
    esac
fi
if [ -n "$UTOOLS_CHROOT" ]; then
    [ -n "$UTOOLS_SYSNAME" ] && eval "MYSYSNAME=($UTOOLS_SYSNAME)"
    [ -n "$UTOOLS_BITS" ] && eval "MYBITS=$UTOOLS_BITS"
    [ -n "$UTOOLS_SYSDIST" ] && eval "MYSYSDIST=($UTOOLS_SYSDIST)"
    [ -n "$UTOOLS_SYSVER" ] && eval "MYSYSVER=($UTOOLS_SYSVER)"
fi

function __get_sysdist_alias() {
    if ! array_contains ALL_SYSDISTS "$1"; then
        local nd n d
        for nd in "${SYSDIST_ALIASES[@]}"; do
            splitvar "$nd" n d
            if [ "$n" == "$1" ]; then
                echo "$d"
                return
            fi
        done
    fi
    echo "$1"
}

function __get_sysver_alias() {
    if ! array_contains ALL_SYSVERS "$1"; then
        local nv n v
        for nv in "${SYSVER_ALIASES[@]}"; do
            splitvar "$nv" n v
            if [ "$n" == "$1" ]; then
                echo "$v"
                return
            fi
        done
    fi
    echo "$1"
}

function __fix_sysinfos_upward() {
    local sysname_ sysdists_ sysdist_ sysvers_ sysver_
    if [ -z "${!sysnamevar_}" ]; then
        if [ -z "${!sysdistvar_}" ]; then
            [ -z "${!sysvervar_}" ] && return
            for sysname_ in "${SYSNAMES[@]}"; do
                array_copy sysdists_ "${sysname_}_SYSDISTS"
                for sysdist_ in "${sysdists_[@]}"; do
                    array_copy sysvers_ "${sysdist_}_SYSVERS"
                    for sysver_ in "${sysvers_[@]}"; do
                        if [ "$sysver_" == "${!sysvervar_}" ]; then
                            set_var "$sysdistvar_" "$sysdist_"
                            set_var "$sysnamevar_" "$sysname_"
                            return
                        fi
                    done
                done
            done
        fi
        [ -z "${!sysdistvar_}" ] && return 0
        for sysname_ in "${SYSNAMES[@]}"; do
            array_copy sysdists_ "${sysname_}_SYSDISTS"
            for sysdist_ in "${sysdists_[@]}"; do
                if [ "$sysdist_" == "${!sysdistvar_}" ]; then
                    set_var "$sysnamevar_" "$sysname_"
                    return
                fi
            done
        done
    fi
}
function __fix_sysinfos_downward() {
    local sysname_ sysdist_ sysver_

    [ -z "${!sysnamevar_}" ] && return

    if [ -z "${!sysdistvar_}" ]; then
        array_copy sysdists_ "${!sysnamevar_}_SYSDISTS"
        for sysdist_ in "${sysdists_[@]}"; do
            set_var "$sysdistvar_" "$sysdist_"
            break
        done
    fi
    [ -z "${!sysdistvar_}" ] && return

    if [ -z "${!sysvervar_}" ]; then
        array_copy sysvers_ "${sysdistvar_}_SYSVERS"
        for sysver_ in "${sysvers_[@]}"; do
            set_var "$sysvervar_" "$sysver_"
            break
        done
    fi
}
function ensure_sysinfos() {
    local sysnamevar_="${1:-SYSNAME}"
    local sysdistvar_="${2:-SYSDIST}"
    local sysvervar_="${3:-SYSVER}"
    [ -n "${!sysdistvar_}" ] && set_var "$sysdistvar_" "$(__get_sysdist_alias "${!sysdistvar_}")"
    [ -n "${!sysvervar_}" ] && set_var "$sysvervar_" "$(__get_sysver_alias "${!sysvervar_}")"
    __fix_sysinfos_upward
    __fix_sysinfos_downward
}

function check_sysinfos() {
    local sysnamevar_="MYSYSNAME"
    local sysdistvar_="MYSYSDIST"
    local sysvervar_="MYSYSVER"
    local bitsvar_="MYBITS"
    local check_=sysname r_=0
    while [ -n "$1" ]; do
        if [[ "$1" == -* ]]; then
            [ "$1" == "-S" ] && { sysnamevar_="$2"; shift 2; continue; }
            [ "$1" == "-D" ] && { sysdistvar_="$2"; shift 2; continue; }
            [ "$1" == "-V" ] && { sysvervar_="$2"; shift 2; continue; }
            [ "$1" == "-B" ] && { bitsvar_="$2"; shift 2; continue; }
            [ "$r_" == "1" ] && break
            [ "$1" == "-s" ] && check_=sysname
            [ "$1" == "-d" ] && check_=sysdist
            [ "$1" == "-v" ] && check_=sysver
            [ "$1" == "-b" ] && check_=bits
            r_=1
            shift
            continue
        fi
        if [ "$check_" == "sysname" ]; then
            if array_contains "$sysnamevar_" "$1"; then
                r_=0
                check_=skip
            fi

        elif [ "$check_" == "sysdist" ]; then
            local mode_=exact value_="$1"
            if [ "${value_%+}" != "$value_" ]; then
                mode_=after
                value_="${value_%+}"
            elif [ "${value_%-}" != "$value_" ]; then
                mode_=before
                value_="${value_%-}"
            fi
            value_="$(__get_sysdist_alias "$value_")"
            if [ "$mode_" == "exact" ]; then
                if array_contains "$sysdistvar_" "$value_"; then
                    r_=0
                    check_=skip
                fi
            elif [ "$mode_" == "after" ]; then
                local sysdist_
                for sysdist_ in "${ALL_SYSDISTS[@]}"; do
                    if array_contains "$sysdistvar_" "$sysdist_"; then
                        r_=0
                        check_=skip
                    elif [ "$sysdist_" == "$value_" ]; then
                        break
                    fi
                done
            elif [ "$mode_" == "before" ]; then
                local sysdist_ found_
                for sysdist_ in "${ALL_SYSDISTS[@]}"; do
                    [ "$sysdist_" == "$value_" ] && found_=1
                    if [ -n "$found_" ]; then
                        if array_contains "$sysdistvar_" "$sysdist_"; then
                            r_=0
                            check_=skip
                            break
                        fi
                    fi
                done
            fi

        elif [ "$check_" == "sysver" ]; then
            local mode_=exact value_="$1"
            if [ "${value_%+}" != "$value_" ]; then
                mode_=after
                value_="${value_%+}"
            elif [ "${value_%-}" != "$value_" ]; then
                mode_=before
                value_="${value_%-}"
            fi
            value_="$(__get_sysver_alias "$value_")"
            if [ "$mode_" == "exact" ]; then
                if array_contains "$sysvervar_" "$value_"; then
                    r_=0
                    check_=skip
                fi
            elif [ "$mode_" == "after" ]; then
                local sysver_
                for sysver_ in "${ALL_SYSVERS[@]}"; do
                    if array_contains "$sysvervar_" "$sysver_"; then
                        r_=0
                        check_=skip
                    elif [ "$sysver_" == "$value_" ]; then
                        break
                    fi
                done
            elif [ "$mode_" == "before" ]; then
                local sysver_ found_
                for sysver_ in "${ALL_SYSVERS[@]}"; do
                    [ "$sysver_" == "$value_" ] && found_=1
                    if [ -n "$found_" ]; then
                        if array_contains "$sysvervar_" "$sysver_"; then
                            r_=0
                            check_=skip
                            break
                        fi
                    fi
                done
            fi

        elif [ "$check_" == "bits" ]; then
            if [ "$1" == "${!bitsvar_}" ]; then
                r_=0
                check_=skip
            fi
        fi
        shift
    done
    return $r_
}
##@inc]sysinfos
##@inc[compat
# Code de support pour les architectures autre que Linux
##@require base
##@require sysinfos
uprovide compat
urequire base sysinfos

if check_sysinfos -s macosx; then
    function __rlnp() { local p="$1" np f; [ "${p#/}" == "$p" ] && p="$(pwd)/$p"; while [[ "$p" == *//* ]]; do p="${p//\/\///}"; done; p="${p%/}"; p="${p#/}"; np=; while [ -n "$p" ]; do if [[ "$p" == */* ]]; then f="${p%%/*}"; p="${p#*/}"; else f="$p"; p=; fi; if [ "$f" == . ]; then :; elif [ "$f" == .. ]; then if [[ "$np" == */* ]]; then np="${np%/*}"; else np=; fi; else [ -n "$np" ] && np="$np/"; np="$np$f"; fi; done; echo "/$np"; }
    function readlinkm() { local p="$(__rlnp "$1")" np n; while [ -n "$p" ]; do local max=50; while [ -L "$p" -a $max -gt 0 ]; do n="$(readlink "$p")"; if [ "${n#/}" != "$n" ]; then p="$n"; else p="${p%/*}/$n"; fi; p="$(__rlnp "$p")"; max=$(($max-1)); done; [ -n "$np" ] && np="/$np"; if [[ "$p" == */* ]]; then np="${p##*/}$np"; p="${p%/*}"; else np="$p$np"; p=; fi; done; echo "/$np"; }
    function _nl2lf() { awk '{ sub(/\r$/, ""); gsub(/\r/, "\n"); print }'; }
    function _nl2crlf() { _nl2lf | awk '{ print $0 "\r" }'; }
    function _nl2cr() { _nl2lf | awk 'BEGIN { ORS="" } { print $0 "\r" }'; }
    function sedi() { sed -i '' "$@"; }

    function __po_check_options() {
        local -a options args
        local option value flag
        if [ "${opts_#+}" != "$opts_" ]; then
            while [ -n "$*" ]; do
                if [ "$1" == "--" ]; then
                    shift
                    break
                elif [[ "$1" == --* ]]; then
                    option="${1%%=*}"
                    if flag="$(array_find options_ "$option" flags_)"; then
                        if [[ "$flag" == ::* ]]; then
                            if [[ "$1" == *=* ]]; then
                                value="${1#--*=}"
                            else
                                value=
                            fi
                            shift
                            options=("${options[@]}" "$option" "$value")
                        elif [[ "$flag" == :* ]]; then
                            if [[ "$1" == *=* ]]; then
                                value="${1#--*=}"
                                shift
                            elif [ $# -gt 1 ]; then
                                value="$2"
                                shift 2
                            else
                                echo "option requires an argument: $option"
                                return 1
                            fi
                            options=("${options[@]}" "$option" "$value")
                        else
                            shift
                            options=("${options[@]}" "$option")
                        fi
                    else
                        echo "invalid option: $1"
                        return 1
                    fi

                elif [[ "$1" == -* ]]; then
                    option="${1:0:2}"
                    if flag="$(array_find options_ "$option" flags_)"; then
                        if [[ "$flag" == ::* ]]; then
                            value="${1:2}"
                            shift
                            options=("${options[@]}" "$option" "$value")
                        elif [[ "$flag" == :* ]]; then
                            if [[ -n "${1:2}" ]]; then
                                value="${1:2}"
                                shift
                            elif [ $# -gt 1 ]; then
                                value="$2"
                                shift 2
                            else
                                echo "option requires an argument: $option"
                                return 1
                            fi
                            options=("${options[@]}" "$option" "$value")
                        else
                            shift
                            options=("${options[@]}" "$option")
                        fi
                    else
                        echo "invalid option: $1"
                        return 1
                    fi

                else
                    break
                fi
            done
            args=("$@")
        elif [ "${opts_#-}" != "$opts_" ]; then
            while [ -n "$*" ]; do
                if [ "$1" == "--" ]; then
                    shift
                    break
                elif [[ "$1" == --* ]]; then
                    option="${1%%=*}"
                    if flag="$(array_find options_ "$option" flags_)"; then
                        if [[ "$flag" == ::* ]]; then
                            if [[ "$1" == *=* ]]; then
                                value="${1#--*=}"
                            else
                                value=
                            fi
                            shift
                            options=("${options[@]}" "$option" "$value")
                        elif [[ "$flag" == :* ]]; then
                            if [[ "$1" == *=* ]]; then
                                value="${1#--*=}"
                                shift
                            elif [ $# -gt 1 ]; then
                                value="$2"
                                shift 2
                            else
                                echo "option requires an argument: $option"
                                return 1
                            fi
                            options=("${options[@]}" "$option" "$value")
                        else
                            shift
                            options=("${options[@]}" "$option")
                        fi
                    else
                        echo "invalid option: $1"
                        return 1
                    fi

                elif [[ "$1" == -* ]]; then
                    option="${1:0:2}"
                    if flag="$(array_find options_ "$option" flags_)"; then
                        if [[ "$flag" == ::* ]]; then
                            value="${1:2}"
                            shift
                            options=("${options[@]}" "$option" "$value")
                        elif [[ "$flag" == :* ]]; then
                            if [[ -n "${1:2}" ]]; then
                                value="${1:2}"
                                shift
                            elif [ $# -gt 1 ]; then
                                value="$2"
                                shift 2
                            else
                                echo "option requires an argument: $option"
                                return 1
                            fi
                            options=("${options[@]}" "$option" "$value")
                        else
                            shift
                            options=("${options[@]}" "$option")
                        fi
                    else
                        echo "invalid option: $1"
                        return 1
                    fi

                else
                    options=("${options[@]}" "$1")
                    shift
                fi
            done
            args=("$@")
        else
            while [ -n "$*" ]; do
                if [ "$1" == "--" ]; then
                    shift
                    break
                elif [[ "$1" == --* ]]; then
                    option="${1%%=*}"
                    if flag="$(array_find options_ "$option" flags_)"; then
                        if [[ "$flag" == ::* ]]; then
                            if [[ "$1" == *=* ]]; then
                                value="${1#--*=}"
                            else
                                value=
                            fi
                            shift
                            options=("${options[@]}" "$option" "$value")
                        elif [[ "$flag" == :* ]]; then
                            if [[ "$1" == *=* ]]; then
                                value="${1#--*=}"
                                shift
                            elif [ $# -gt 1 ]; then
                                value="$2"
                                shift 2
                            else
                                echo "option requires an argument: $option"
                                return 1
                            fi
                            options=("${options[@]}" "$option" "$value")
                        else
                            shift
                            options=("${options[@]}" "$option")
                        fi
                    else
                        echo "invalid option: $1"
                        return 1
                    fi

                elif [[ "$1" == -* ]]; then
                    option="${1:0:2}"
                    if flag="$(array_find options_ "$option" flags_)"; then
                        if [[ "$flag" == ::* ]]; then
                            value="${1:2}"
                            shift
                            options=("${options[@]}" "$option" "$value")
                        elif [[ "$flag" == :* ]]; then
                            if [[ -n "${1:2}" ]]; then
                                value="${1:2}"
                                shift
                            elif [ $# -gt 1 ]; then
                                value="$2"
                                shift 2
                            else
                                echo "option requires an argument: $option"
                                return 1
                            fi
                            options=("${options[@]}" "$option" "$value")
                        else
                            shift
                            options=("${options[@]}" "$option")
                        fi
                    else
                        echo "invalid option: $1"
                        return 1
                    fi

                else
                    args=("${args[@]}" "$1")
                    shift
                fi
            done
            args=("${args[@]}" "$@")
        fi
        quoted_args "${options[@]}" -- "${args[@]}"
        return 0
    }

    function __pd_isleap() {
        [ $(($1 % 4)) -eq 0 -a \( $(($1 % 100)) -ne 0 -o $(($1 % 400)) -eq 0 \) ]
    }
    function __pd_fix_month() {
        local __pdfm_y="${!1}" __pdfm_m="${!2}"
        let __pdfm_m=$__pdfm_m-1
        while [ $__pdfm_m -gt 11 ]; do
            let __pdfm_m=$__pdfm_m-12
            let __pdfm_y=$__pdfm_y+1
        done
        while [ $__pdfm_m -lt 0 ]; do
            let __pdfm_m=$__pdfm_m+12
            let __pdfm_y=$__pdfm_y-1
        done
        let __pdfm_m=$__pdfm_m+1
        eval "$1=$__pdfm_y; $2=$__pdfm_m"
    }
    __PD_MONTHDAYS=(0 31 28 31 30 31 30 31 31 30 31 30 31)
    function __pd_monthdays() {
        local y="$1" m="$2" mds
        __pd_fix_month y m
        mds="${__PD_MONTHDAYS[$m]}"
        [ "$m" -eq 2 ] && __pd_isleap "$y" && let mds=$mds+1
        echo $mds
    }
    function __pd_fix_day() {
        local __pdfd_y="${!1}" __pdfd_m="${!2}" __pdfd_d="${!3}" __pdfd_mds
        let __pdfd_d=$__pdfd_d-1
        let __pdfd_mds=$(__pd_monthdays $__pdfd_y $__pdfd_m)
        while [ $__pdfd_d -gt $(($__pdfd_mds-1)) ]; do
            let __pdfd_d=$__pdfd_d-$__pdfd_mds
            let __pdfd_m=$__pdfd_m+1
            __pd_fix_month __pdfd_y __pdfd_m
            let __pdfd_mds=$(__pd_monthdays $__pdfd_y $__pdfd_m)
        done
        while [ $__pdfd_d -lt 0 ]; do
            let __pdfd_m=$__pdfd_m-1
            __pd_fix_month __pdfd_y __pdfd_m
            let __pdfd_d=$__pdfd_d-$(__pd_monthdays $__pdfd_y $__pdfd_m)
        done
        let __pdfd_d=$__pdfd_d+1
        eval "$1=$__pdfd_y; $2=$__pdfd_m; $3=$__pdfd_d"
    }
    function __pd_fix_date() {
        local __pdf_y="${!1}" __pdf_m="${!2}" __pdf_d="${!3}"
    }
    function parse_date() {
        local value="$1" type="${2:-date}"
        local d m y
        eval "$(date +%d/%m/%Y | awk -F/ '{
            print "d=" $1 "; m=" $2 "; y=" $3
        }')"
        if [ "${value#+}" != "$value" ]; then
            d="$(($d+${value#+}))"
        else
            eval "$(<<<"$value" awkrun FS=/ dn="$dn" mn="$mn" yn="$yn" type="$type" '{
                d = $1 + 0; if (d < 1) d = dn + 0;
                m = $2 + 0; if (m < 1) m = mn + 0;
                if ($3 == "") y = yn + 0;
                else { y = $3 + 0; if (y < 100) y = y + 2000; }
                print "d=" d "; m=" m "; y=" y
            }')"
        fi
        __pd_fix_month y m
        __pd_fix_day y m d
        case "$type" in
        d|date)
            awkrun d="$d" m="$m" y="$y" 'BEGIN { printf "%02i/%02i/%04i\n", d, m, y }'
            ;;
        l|ldap)
            awkrun d="$d" m="$m" y="$y" 'BEGIN { printf "%04i%02i%02i000000+0400\n", y, m, d }'
            ;;
        esac
    }
    function myhost() {
        hostname
    }
    function myhostname() {
        hostname -s
    }
fi
##@inc]compat
##@inc[crontab
## Gestion du fichier crontab
##@require base
uprovide crontab
urequire base

function add_to_crontab() {
    local -a crontab=(crontab ${2:+-u "$2"})
    local current="$("${crontab[@]}" -l 2>/dev/null)"
    local tmpfile
    ac_set_tmpfile tmpfile
    if [ -n "$current" ]; then
        echo "$current" >"$tmpfile"
    fi
    local NL=$'\n'
    if quietgrep -xF "$1$NL#$1" "$tmpfile"; then
        ac_clean "$tmpfile"
        return 123
    else
        echo "$1" >>"$tmpfile"
        "${crontab[@]}" "$tmpfile"
        ac_clean "$tmpfile"
    fi
}
function remove_from_crontab() {
    local -a crontab=(crontab ${2:+-u "$2"})
    local current="$("${crontab[@]}" -l 2>/dev/null)"
    local tmpfile
    ac_set_tmpfile tmpfile
    if [ -n "$current" ]; then
        echo "$current" >"$tmpfile"
    fi
    local NL=$'\n'
    if ! quietgrep -xF "$1$NL#$1" "$tmpfile"; then
        ac_clean "$tmpfile"
        return 123
    else
        grep -vxF "$1$NL#$1" "$tmpfile" | "${crontab[@]}" -
        ac_clean "$tmpfile"
    fi
}
function disable_in_crontab() {
    local -a crontab=(crontab ${2:+-u "$2"})
    local current="$("${crontab[@]}" -l 2>/dev/null)"
    local tmpfile
    ac_set_tmpfile tmpfile
    if [ -n "$current" ]; then
        echo "$current" >"$tmpfile"
    fi
    local NL=$'\n'
    if ! quietgrep -xF "$1$NL#$1" "$tmpfile"; then
        echo "#$1" >>"$tmpfile"
        "${crontab[@]}" "$tmpfile"
    elif quietgrep -xF "#$1" "$tmpfile"; then
        ac_clean "$tmpfile"
        return 123
    else
        <"$tmpfile" awkrun line="$1" '$0 == line { $0 = "#" $0 } { print }' | "${crontab[@]}" -
        ac_clean "$tmpfile"
    fi
}
function enable_in_crontab() {
    local -a crontab=(crontab ${2:+-u "$2"})
    local current="$("${crontab[@]}" -l 2>/dev/null)"
    local tmpfile
    ac_set_tmpfile tmpfile
    if [ -n "$current" ]; then
        echo "$current" >"$tmpfile"
    fi
    local NL=$'\n'
    if ! quietgrep -xF "$1$NL#$1" "$tmpfile"; then
        echo "$1" >>"$tmpfile"
        "${crontab[@]}" "$tmpfile"
    elif quietgrep -xF "$1" "$tmpfile"; then
        ac_clean "$tmpfile"
        return 123
    else
        <"$tmpfile" awkrun line="$1" '$0 == "#" line { sub(/^#/, "") } { print }' | "${crontab[@]}" -
        ac_clean "$tmpfile"
    fi
}
function ctnow() {
    date +"%-M %-H %-d %-m %u"
}
__CTRESOLVE_CTNOW=""
function ctresolve() {
    local -a ctnow
    if [ -n "$__CTRESOLVE_CTNOW" ]; then
        eval "ctnow=($__CTRESOLVE_CTNOW)"
    else
        eval "ctnow=($(ctnow))"
    fi
    filter_conf | awkrun -f ctnow[@] '
function ctmatch_one(ctval, ref,              parts, part, i, j, start, end, step, ok) {
  ok = 0
  split(ctval, parts, /,/)
  for(i = 1; i <= length(parts); i++) {
    part = parts[i]
    start = -1; end = -1; step = 1
    pos = index(part, "/")
    if (pos != 0) {
      step = substr(part, pos + 1) + 0
      part = substr(part, 1, pos - 1)
    }
    pos = index(part, "-")
    if (pos != 0) {
      start = substr(part, 1, pos - 1) + 0
      end = substr(part, pos + 1) + 0
    } else {
      start = part + 0
      end = start
    }
    for (j = start; j <= end; j += step) {
      if (j == ref) {
        ok = 1
        break
      }
    }
    if (ok) break
  }
  return ok
}
function ctmatch_all(M, H, dom, mon, dow, refM, refH, refdom, refmon, refdow,               Mok, Hok, domok, monok, dowok) {
    gsub(/\*/, "0-59", M)
    Mok = ctmatch_one(M, refM)

    gsub(/\*/, "0-23", H)
    Hok = ctmatch_one(H, refH)

    gsub(/\*/, "1-31", dom)
    domok = ctmatch_one(dom, refdom)

    gsub(/\*/, "1-12", mon)
    monok = ctmatch_one(mon, refmon)

    gsub(/\*/, "1-7", dow)
    dowok = ctmatch_one(dow, refdow)

    return Mok && Hok && monok && (domok || dowok)
}
function print_cmd(cmd) {
  print "__ctexec " quote_value(cmd)
}

BEGIN {
  refM = ctnow[1]; refH = ctnow[2]; refdom = ctnow[3]; refmon = ctnow[4]; refdow = ctnow[5]
  ctref = refM " " refH " " refdom " " refmon " " refdow
  print "## now: " ctref

  ctline_run = 0
  ctline_run_one_match = 0
  match_indented = 0
}

/^(export[ \t]+)?[a-zA-Z_][a-zA-Z0-9_]*[-+%#?]=/ {
  ctline_run = 0; ctline_run_one_match = 0; match_indented = 0

  match($0, /^(export[ \t]+)?([a-zA-Z_][a-zA-Z0-9_]*)([-+%#?])=(.*)$/, parts)
  name = parts[2]
  type = parts[3]
  value = parts[4]
  if (type == "+" || type == "%") {
    print "uaddpath " value " " name
  } else if (type == "#") {
    print "uinspath " value " " name
  } else if (type == "-") {
    print "udelpath " value " " name
  } else if (type == "?") {
    print "[ -n \"$" name "\" ] || " name "=" value
  }
  print "export " name
  next
}
/^(export[ \t]+)?[a-zA-Z_][a-zA-Z0-9_]*=/ {
  ctline_run = 0; ctline_run_one_match = 0; match_indented = 0

  sub(/^export[ \t]+/, "", $0)
  print "export " $0
  next
}
/^\$.+/ {
  ctline_run = 0; ctline_run_one_match = 0; match_indented = 0

  if ($0 ~ /^\$\{([ \t]*(#.*)?)?$/) {
    getline
    while ($0 !~ /^\$\}([ \t]*(#.*)?)?$/) {
      print
      if (getline <= 0) break
    }
  } else {
    sub(/^\$/, "", $0)
    print
  }
  next
}

/^[ \t]*[-0-9/*,]+[ ]*[-0-9/*,]+[ ]*[-0-9/*,]+[ ]*[-0-9/*,]+[ ]*[-0-9/*,]+/ {
  match_indented = 0

  M = $1; H = $2; dom = $3; mon = $4; dow = $5
  ctline = M " " H " " dom " " mon " " dow

  sub(/^[ \t]*[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]*/, "", $0)
  cmd = $0

  match_cur = ctmatch_all(M, H, dom, mon, dow, refM, refH, refdom, refmon, refdow)
  if (match_cur) print "## match: " ctline

  if (cmd == "") {
    ctline_run = 1
    if (match_cur) ctline_run_one_match = 1
    if (ctline_run_one_match) match_indented = 1

  } else {
    if (ctline_run && match_cur) ctline_run_one_match = 1
    if (ctline_run && ctline_run_one_match) {
      print_cmd(cmd)
      match_indented = 1
    }

    if (!ctline_run && match_cur) {
      print_cmd(cmd)
      match_indented = 1
    }

    ctline_run = 0
    ctline_run_one_match = 0
  }

  next
}
/^[ \t]+/ {
  ctline_run = 0; ctline_run_one_match = 0

  if (match_indented) {
    sub(/^[ \t]+/, "", $0)
    print_cmd($0)
  }

  next
}
{
  print "__cterror " quote_value("ligne de format incorrect: " $0)
}
'
}


function get_default_crontabdir_prefix() {
    if check_sysinfos -s darwin; then
        if check_sysinfos -d 10.6+; then
            echo /var/at/tabs
        else
            echo /var/cron/tabs
        fi
    elif check_sysinfos -s linux; then
        if check_sysinfos -d debianlike; then
            echo /var/spool/cron/crontabs
        elif check_sysinfos -d redhatlike; then
            echo /var/spool/cron
        fi
    fi
}

__crontab_prefixes=
function __compute_crontab_prefixes() {
    [ -n "$__crontab_prefixes" ] && return
    CRONTABDIR="${CRONTABDIR:-$(get_default_crontabdir_prefix)}"
    __crontab_prefixes=1
}

UTOOLS_PREFIXES=("${UTOOLS_PREFIXES[@]}" CRONTABDIR)

function compute_crontab_prefixes() {
    __compute_crontab_prefixes
}

function recompute_crontab_prefixes() {
    __crontab_prefixes=
    __compute_crontab_prefixes
}

function get_CRONTABDIR_prefix() {
    __compute_crontab_prefixes
    echo "$CRONTABDIR"
}
##@inc]crontab

action=add_to_crontab
actionopt=-a
user=root
hosts=()
ctline=
time=
dom=
month=
cmdfile=
cmd=
hostsfiles=()
increment=auto
adelay="$DEFAULT_ADELAY"
undoscript=
dundoscript=1
fake=
autoclean=
parse_opts "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    -a '$action=add_to_crontab; actionopt=-a' \
    -r '$action=remove_from_crontab; actionopt=-r' \
    -u: user= \
    -h:,-H: hosts \
    -t: time= \
    --dom: dom= \
    --month: month= \
    -s: cmdfile= \
    -S: cmd= \
    -f: hostsfiles \
    -d increment=1 \
    -n increment= \
    --add: adelay= \
    --us: '$set@ undoscript; dundoscript=' \
    --fake fake=1 \
    --autoclean: autoclean= \
    @ args -- "$@" && set -- "${args[@]}" || die "$args"

array_fix_paths hosts
if [ "$action" != "add_to_crontab" ]; then
    undoscript=
fi
if [ -n "$cmdfile" -a -z "$cmd" ]; then
    cmd="$(<"$cmdfile")" || die
fi
[ -n "$cmdfile" ] && cmdfile="$(basename "$cmdfile")"
if [ -n "$dundoscript" -a "$action" == "add_to_crontab" ]; then
    if [ -n "${hosts[*]}" -o -n "${hostsfiles[*]}" ]; then
        undoscript="undo-ucrontab.sh"
    fi
fi


function update_undoscript() {
    local undoscript="$1" user="$2" host="$3" ctline="$4"

    [ -n "$undoscript" ] || return
    [ -n "$fake" ] && undoscript="fake-$undoscript"

    [ -z "$fake" ] && estep "Maj de $undoscript"
    if [ ! -f "$undoscript" ]; then
        cat >"$undoscript" <<EOF
allok=1
function __autoclean() { [ -n "\$allok" ] && /bin/rm -f "\$0"; }
trap __autoclean 1 3 15 EXIT

EOF
        chmod +x "$undoscript"
    fi

    local -a undocmd
    undocmd=("$script" -r -u "$user")
    [ -n "$undocmd" ] && {
        undocmd=("${undocmd[@]}" -s "$cmdfile" -S "")
        [ -n "$cmdfile" ] && ctline="$(update_cmd "$ctline" "$cmdfile")"
    }
    [ -n "$host" ] && undocmd=("${undocmd[@]}" -H "$host")
    undocmd=("${undocmd[@]}" "$ctline")
    echo "$(quoted_args "${undocmd[@]}") || allok=" >>"$undoscript"
}

function get_time() {
    awk '{print $2 ":" $1 }' <<<"$1"
}

function update_time() {
    local time="$1" offset="$2"
    local hours minutes

    time="${time//./:}"
    if [[ "$time" == *:* ]]; then
        hours="${time%%:*}"
        minutes="${time#*:}"
    else
        hours="$time"
        minutes=0
    fi
    hours="${hours:-7}"
    minutes="${minutes:-0}"

    if [ -n "$offset" ]; then
        hours=$(($hours * 60 + $minutes + $offset))
        minutes=$(($hours % 60))
        hours=$(($hours / 60))
    fi

    echo "$hours:$minutes"
}

function update_ctline() {
    local ctline="$1" time="$2" offset="$3"
    local hours minutes

    time="$(update_time "$time" "$offset")"
    splitpair "$time" hours minutes

    awkrun minutes="$minutes" hours="$hours" dom="$dom" month="$month" '{$1=minutes; $2=hours; $3=dom; $4=month; $5="*"; print}' <<<"$ctline"
}

function update_cmd() {
    local ctline="$1" cmd="$2"
    awkrun cmd="$cmd" '{$0 = $1 " " $2 " " $3 " " $4 " " $5 " " cmd; print}' <<<"$ctline"
}



function do_local() {
    if [ "$user" != "root" -a "$user" == "$USER" ]; then
        user=
    fi
    [ -n "$cmdfile" ] || cmdfile=custom-script

    local r=0
    local tmpcmd="$TMPDIR/ucrontab-$(basename "$cmdfile")"
    if [ -n "$cmd" ]; then
        echo "\
$cmd"'
/bin/rm -f "$0"; exit 0' >"$tmpcmd"
        chmod +x "$tmpcmd"
        ctline="$(update_cmd "$ctline" "$tmpcmd")"
    fi

    if [ -n "$fake" ]; then
        if [ -n "$cmd" ]; then
            eecho "$action $(quoted_args "$(update_cmd "$ctline" "$tmpcmd:")")
$(sed 's/^/    /g' <<<"$cmd")"
        else
            eecho "$action $(quoted_args "$ctline")"
        fi
    elif "$action" "$ctline" "$user"; then
        estep "$action $ctline"
        update_undoscript "$undoscript" "$user" "" "$ctline"
    else
        r=$?
        if [ $r -eq 123 ]; then
            r=0
            if [ "$action" == "add_to_crontab" ]; then
                ewarn "La ligne '$ctline' existe déjà dans crontab"
            elif [ "$action" == "remove_from_crontab" ]; then
                ewarn "La ligne '$ctline' a déjà été supprimée de crontab"
            fi
        else
            eerror "Une erreur s'est produite"
        fi
    fi

    if [ -n "$autoclean" ]; then
        if [ "$autoclean" == "$scriptname" ]; then
            [ -z "$fake" ] && autoclean "$script"
        else
            eerror "Invalid autoclean option"
        fi
    fi

    return $r
}

function do_remote() {
    local r=0
    [ -n "$cmd" -a -z "$cmdfile" ] && cmdfile=custom-script
    for host in "${hosts[@]}"; do
        if [ "$host" == "." -o "$host" == "localhost" ]; then
            do_local
            continue
        fi

        if [[ "$host" == *@* ]]; then
            ssh_user="${host%%@*}"
            host="${host#*@}"
        else
            ssh_user="$user"
        fi
        ssh_cmd="$(quoted_args chmod +x "$remotename"); $(quoted_args "./$remotename" --autoclean "$remotename" "$actionopt" -u "$user" --dom "$dom" --month "$month" ${cmd:+-s "$cmdfile" -S "$cmd"} "$ctline"); true"

        [ -z "$fake" ] && etitle -s "$host"
        ok=
        if [ -n "$fake" ]; then
            if [ -n "$cmd" ]; then
                eecho "[$host] $action $(quoted_arg "$(update_cmd "$ctline" "$cmdfile:")")
$(sed 's/^/    /g' <<<"$cmd")"
            else
                eecho "[$host] $action $(quoted_arg "$ctline")"
            fi
            ok=1
        elif scp -o ConnectTimeout=5 -q "$script" "$ssh_user@$host:$remotename"; then
            if ssh -o ConnectTimeout=5 -qt "$ssh_user@$host" "$ssh_cmd"; then
                ok=1
            else
                r=$?
            fi
        else
            r=$?
        fi
        if [ -n "$ok" ]; then
            update_undoscript "$undoscript" "$user" "$ssh_user@$host" "$ctline"
            if [ -n "$increment" ]; then
                aoffset=$(($aoffset + $adelay))
                ctline="$(update_ctline "$ctline" "$time" "$aoffset")"
            fi
        else
            eerror "Une erreur s'est produite. Cet hôte a été ignoré"
        fi
        [ -z "$fake" ] && eend
    done
    return $r
}

if [ -z "$dom" -o -z "$month" ]; then
    tomorrow="$(parse_date +1)"
    [ -n "$dom" ] || dom="${tomorrow%%/*}"
    [ -n "$month" ] || { month="${tomorrow#*/}"; month="${month%/*}"; }
fi
DEFAULT_CTLINE="0 7 $dom $month * /sbin/shutdown -h now"
ctline="$1"
if [ "${ctline#halt}" != "$ctline" ]; then
    if [ "${ctline#halt@}" != "$ctline" ]; then
        time="${ctline#halt@}"
    fi
    ctline="$DEFAULT_CTLINE"
    [ "$increment" == "auto" ] && increment=1
fi
if [ -n "$hostsfiles" ]; then
    [ -n "$ctline" ] || ctline="$DEFAULT_CTLINE"
else
    [ -n "$ctline" ] || die "Vous devez spécifier la ligne de crontab"
fi
[ -n "$time" ] && ctline="$(update_ctline "$ctline" "$time")"
[ -z "$time" ] && time="$(get_time "$ctline")"
[ "$increment" == "auto" ] && increment=
remotename="$scriptname.$$"
aoffset=0

if [ -n "$hostsfiles" ]; then
    orig_ctline="$ctline"
    orig_cmdfile="$cmdfile"
    orig_cmd="$cmd"
    increment= # incrémentation spécifique dans cette section

    first_host=1
    adelay="${adelay:-$DEFAULT_ADELAY}"
    gdelay=
    function start_group() {
        if [ -n "$gdelay" ]; then
            time="$(update_time "$time" $(($aoffset + $gdelay)))"
        fi
        adelay="${1:-$DEFAULT_ADELAY}"
        gdelay="${2:-$DEFAULT_GDELAY}"
        aoffset=0
        first_host=1
    }
    function do_host() {
        hosts=("$1")
        ctline="$orig_ctline"
        cmdfile="$orig_cmdfile"
        cmd="$orig_cmd"
        if [ -n "$2" ]; then
            if [ "${2#<}" != "$2" ]; then
                cmdfile="${2#<}"
                cmd="$(<"$cmdfile")" || return 1
            else
                cmdfile=
                cmd=
                ctline="$(update_cmd "$ctline" "$2")"
            fi
        fi

        if [ -n "$first_host" ]; then
            first_host=
        else
            aoffset=$(($aoffset + $adelay))
        fi
        ctline="$(update_ctline "$ctline" "$time" "$aoffset")"
        do_remote
    }
    appended_hostsfiles=()
    function do_include() {
        array_add appended_hostsfiles "$1"
    }

    r=0
    while [ -n "${appended_hostsfiles[*]}" -o -n "${hostsfiles[*]}" ]; do
        for hostsfile in "${hostsfiles[@]}"; do
            [ -f "$hostsfile" ] || die "$hostsfile: fichier introuvable"
            eval "$(<"$hostsfile" filter_conf -m | awkrun -f FS=: '
$1 == "@group" {
  adelay = $2
  gdelay = $3
  print "start_group " quote_value(adelay) " " quote_value(gdelay)
  next
}
$1 == "@include" {
  append = $2
  print "do_include " quote_value(append)
  next
}
{
  host = $1
  cmd = $2
  print "do_host " quote_value(host) " " quote_value(cmd)
}
')" || r=$?
        done
        hostsfiles=("${appended_hostsfiles[@]}")
        appended_hostsfiles=()
    done
    exit $r

else
    if [ -n "${hosts[*]}" ]; then
        do_remote; exit $?
    else
        do_local; exit $?
    fi
fi
