suite de la migration des fonctions
This commit is contained in:
parent
e4ce6c5d18
commit
5e130acb93
174
lib/ulib/base
174
lib/ulib/base
|
@ -35,7 +35,7 @@ fi
|
||||||
##@include base.array
|
##@include base.array
|
||||||
##@include base.compat
|
##@include base.compat
|
||||||
uprovide base
|
uprovide base
|
||||||
urequire base.init base.core base.string base.quote base.array base.compat
|
urequire base.init base.core base.string base.quote base.split base.array base.compat
|
||||||
|
|
||||||
## Informations sur l'hôte sur lequel tourne ce script
|
## Informations sur l'hôte sur lequel tourne ce script
|
||||||
# Type de système
|
# Type de système
|
||||||
|
@ -98,178 +98,6 @@ function quoted_sargs() {
|
||||||
done
|
done
|
||||||
rawecho "$s"
|
rawecho "$s"
|
||||||
}
|
}
|
||||||
function first_char() {
|
|
||||||
# retourner le premier caractère de la chaine $1
|
|
||||||
rawecho "${1:0:1}"
|
|
||||||
}
|
|
||||||
function last_char() {
|
|
||||||
# retourner le dernier caractère de la chaine $1
|
|
||||||
rawecho "${1: -1:1}"
|
|
||||||
}
|
|
||||||
function first_chars() {
|
|
||||||
# retourner tous les caractères de la chaine $1, excepté le dernier
|
|
||||||
rawecho "${1:0:$((${#1}-1))}"
|
|
||||||
}
|
|
||||||
function last_chars() {
|
|
||||||
# retourner tous les caractères de la chaine $1, excepté le premier
|
|
||||||
rawecho "${1:1}"
|
|
||||||
}
|
|
||||||
function first_char_is() {
|
|
||||||
# Tester si le premier caractère de la chaine $1 est $2
|
|
||||||
[ "${1:0:1}" == "$2" ]
|
|
||||||
}
|
|
||||||
function last_char_is() {
|
|
||||||
# Tester si le dernier caractère de la chaine $1 est $2
|
|
||||||
[ "${1:$((-1)):1}" == "$2" ]
|
|
||||||
}
|
|
||||||
function beginswith() {
|
|
||||||
# Tester si la chaine $1 commence par le wildcard $2
|
|
||||||
eval '[ "${1#'"$(quote_arg "$2")"'}" != "$1" ]'
|
|
||||||
}
|
|
||||||
function endswith() {
|
|
||||||
# Tester si la chaine $1 se termine par le wildcard $2
|
|
||||||
eval '[ "${1%'"$(quote_arg "$2")"'}" != "$1" ]'
|
|
||||||
}
|
|
||||||
function splitfsep() {
|
|
||||||
# Découper $1 de la forme "first[SEPsecond]" entre first, qui est placé dans la
|
|
||||||
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
|
||||||
# est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP.
|
|
||||||
if [[ "$1" == *"$2"* ]]; then
|
|
||||||
set_var "${3:-first}" "${1%%$2*}"
|
|
||||||
set_var "${4:-second}" "${1#*$2}"
|
|
||||||
else
|
|
||||||
set_var "${3:-first}" "$1"
|
|
||||||
set_var "${4:-second}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
function splitfsep2() {
|
|
||||||
# Découper $1 de la forme "[firstSEP]second" entre first, qui est placé dans la
|
|
||||||
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
|
||||||
# est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP.
|
|
||||||
if [[ "$1" == *"$2"* ]]; then
|
|
||||||
set_var "${3:-first}" "${1%%$2*}"
|
|
||||||
set_var "${4:-second}" "${1#*$2}"
|
|
||||||
else
|
|
||||||
set_var "${3:-first}"
|
|
||||||
set_var "${4:-second}" "$1"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
function splitlsep() {
|
|
||||||
# Découper $1 de la forme "first[SEPsecond]" entre first, qui est placé dans la
|
|
||||||
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
|
||||||
# est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP.
|
|
||||||
if [[ "$1" == *"$2"* ]]; then
|
|
||||||
set_var "${3:-first}" "${1%$2*}"
|
|
||||||
set_var "${4:-second}" "${1##*$2}"
|
|
||||||
else
|
|
||||||
set_var "${3:-first}" "$1"
|
|
||||||
set_var "${4:-second}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
function splitlsep2() {
|
|
||||||
# Découper $1 de la forme "[firstSEP]second" entre first, qui est placé dans la
|
|
||||||
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
|
||||||
# est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP.
|
|
||||||
if [[ "$1" == *"$2"* ]]; then
|
|
||||||
set_var "${3:-first}" "${1%$2*}"
|
|
||||||
set_var "${4:-second}" "${1##*$2}"
|
|
||||||
else
|
|
||||||
set_var "${3:-first}"
|
|
||||||
set_var "${4:-second}" "$1"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
function splitvar() {
|
|
||||||
# Découper $1 de la forme name[=value] entre le nom, qui est placé dans la
|
|
||||||
# variable $2(=name) et la valeur, qui est placée dans la variable $3(=value)
|
|
||||||
splitfsep "$1" = "${2:-name}" "${3:-value}"
|
|
||||||
}
|
|
||||||
function splitname() {
|
|
||||||
# Découper $1 de la forme basename[.ext] entre le nom de base du fichier, qui
|
|
||||||
# est placé dans la variable $2(=basename) et l'extension, qui est placée dans
|
|
||||||
# la variable $3(=ext)
|
|
||||||
# Attention, si $1 est un chemin, le résultat risque d'être faussé. Par exemple,
|
|
||||||
# 'splitname a.b/c' ne donne pas le résultat escompté.
|
|
||||||
splitlsep "$1" . "${2:-basename}" "${3:-ext}"
|
|
||||||
}
|
|
||||||
function splithost() {
|
|
||||||
# Découper $1 de la forme hostname[.domain] entre le nom d'hôte, qui est placé
|
|
||||||
# dans la variable $2(=hostname) et le domaine, qui est placée dans la variable
|
|
||||||
# $3(=domain)
|
|
||||||
splitfsep "$1" . "${2:-hostname}" "${3:-domain}"
|
|
||||||
}
|
|
||||||
function splituserhost() {
|
|
||||||
# Découper $1 de la forme [user@]host entre le nom de l'utilisateur, qui est placé
|
|
||||||
# dans la variable $2(=user) et le nom d'hôte, qui est placée dans la variable
|
|
||||||
# $3(=host)
|
|
||||||
splitfsep2 "$1" @ "${2:-user}" "${3:-host}"
|
|
||||||
}
|
|
||||||
function splitpair() {
|
|
||||||
# Découper $1 de la forme first[:second] entre la première valeur, qui est placé
|
|
||||||
# dans la variable $2(=src) et la deuxième valeur, qui est placée dans la variable
|
|
||||||
# $3(=dest)
|
|
||||||
splitfsep "$1" : "${2:-src}" "${3:-dest}"
|
|
||||||
}
|
|
||||||
function splitproxy() {
|
|
||||||
# Découper $1 de la forme http://[user:password@]host[:port]/ entre les valeurs
|
|
||||||
# $2(=host), $3(=port), $4(=user), $5(=password)
|
|
||||||
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
|
|
||||||
|
|
||||||
set_var "${2:-host}" "$__sp_host"
|
|
||||||
set_var "${3:-port}" "$__sp_port"
|
|
||||||
set_var "${4:-user}" "$__sp_user"
|
|
||||||
set_var "${5:-password}" "$__sp_password"
|
|
||||||
}
|
|
||||||
function spliturl() {
|
|
||||||
# Découper $1 de la forme scheme://[user:password@]host[:port]/path entre les
|
|
||||||
# valeurs $2(=scheme), $3(=user), $4(=password), $5(=host), $6(=port), $7(=path)
|
|
||||||
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
|
|
||||||
|
|
||||||
set_var "${2:-scheme}" "$__su_scheme"
|
|
||||||
set_var "${3:-user}" "$__su_user"
|
|
||||||
set_var "${4:-password}" "$__su_password"
|
|
||||||
set_var "${5:-host}" "$__su_host"
|
|
||||||
set_var "${6:-port}" "$__su_port"
|
|
||||||
set_var "${7:-path}" "$__su_path"
|
|
||||||
}
|
|
||||||
|
|
||||||
## variables scalaires
|
|
||||||
function set_var_cmd() {
|
|
||||||
echo "$1=$(quoted_arg "$2")"
|
|
||||||
}
|
|
||||||
function set_var() {
|
|
||||||
eval "$(set_var_cmd "$@")"
|
|
||||||
}
|
|
||||||
function set_var_literal() {
|
|
||||||
eval "$1=$2"
|
|
||||||
}
|
|
||||||
|
|
||||||
## variables tableaux
|
## variables tableaux
|
||||||
function set_array_cmd() {
|
function set_array_cmd() {
|
||||||
|
|
|
@ -11,6 +11,9 @@ function rawecho_() { recho_ "$@"; }
|
||||||
function quote_arg() { _qval "$@"; }
|
function quote_arg() { _qval "$@"; }
|
||||||
function quoted_arg() { qvalm "$@"; }
|
function quoted_arg() { qvalm "$@"; }
|
||||||
function quoted_args() { qvals "$@"; }
|
function quoted_args() { qvals "$@"; }
|
||||||
|
function set_var() { setv "$@"; }
|
||||||
|
function set_var_cmd() { echo_setv "$@"; }
|
||||||
|
function set_var_literal() { eval "$1=$2"; }
|
||||||
|
|
||||||
# base.quote
|
# base.quote
|
||||||
function quote_awk() { _qawk "$@"; }
|
function quote_awk() { _qawk "$@"; }
|
||||||
|
|
|
@ -119,6 +119,15 @@ function _setv() {
|
||||||
local __s_var="$1"; shift
|
local __s_var="$1"; shift
|
||||||
eval "$__s_var=\"$(_qval "$*")\""
|
eval "$__s_var=\"$(_qval "$*")\""
|
||||||
}
|
}
|
||||||
|
function echo_setv() {
|
||||||
|
# Afficher la commande qui serait lancée par setv "$@"
|
||||||
|
local __s_var="$1"; shift
|
||||||
|
if [[ "$__s_var" == *=* ]]; then
|
||||||
|
set -- "${__s_var#*=}" "$@"
|
||||||
|
__s_var="${__s_var%%=*}"
|
||||||
|
fi
|
||||||
|
echo "$__s_var=\"$(_qval "$*")\""
|
||||||
|
}
|
||||||
function setx() {
|
function setx() {
|
||||||
# syntaxe 1: setx var cmd
|
# syntaxe 1: setx var cmd
|
||||||
# initialiser la variable $1 avec le résultat de la commande "$2..@"
|
# initialiser la variable $1 avec le résultat de la commande "$2..@"
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
## Fonctions de base: analyse et découpage de valeurs
|
||||||
|
##@cooked nocomments
|
||||||
|
uprovide base.split
|
||||||
|
urequire base.core
|
||||||
|
|
||||||
|
function splitfsep() {
|
||||||
|
# Découper $1 de la forme "first[SEPsecond]" entre first, qui est placé dans la
|
||||||
|
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
||||||
|
# est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP.
|
||||||
|
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() {
|
||||||
|
# Découper $1 de la forme "[firstSEP]second" entre first, qui est placé dans la
|
||||||
|
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
||||||
|
# est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP.
|
||||||
|
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() {
|
||||||
|
# Découper $1 de la forme "first[SEPsecond]" entre first, qui est placé dans la
|
||||||
|
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
||||||
|
# est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP.
|
||||||
|
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() {
|
||||||
|
# Découper $1 de la forme "[firstSEP]second" entre first, qui est placé dans la
|
||||||
|
# variable $3(=first) et second, qui est placée dans la variable $4(=second). $2
|
||||||
|
# est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP.
|
||||||
|
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() {
|
||||||
|
# Découper $1 de la forme name[=value] entre le nom, qui est placé dans la
|
||||||
|
# variable $2(=name) et la valeur, qui est placée dans la variable $3(=value)
|
||||||
|
splitfsep "$1" = "${2:-name}" "${3:-value}"
|
||||||
|
}
|
||||||
|
function splitname() {
|
||||||
|
# Découper $1 de la forme basename[.ext] entre le nom de base du fichier, qui
|
||||||
|
# est placé dans la variable $2(=basename) et l'extension, qui est placée dans
|
||||||
|
# la variable $3(=ext)
|
||||||
|
# Attention, si $1 est un chemin, le résultat risque d'être faussé. Par exemple,
|
||||||
|
# 'splitname a.b/c' ne donne pas le résultat escompté.
|
||||||
|
splitlsep "$1" . "${2:-basename}" "${3:-ext}"
|
||||||
|
}
|
||||||
|
function splithost() {
|
||||||
|
# Découper $1 de la forme hostname[.domain] entre le nom d'hôte, qui est placé
|
||||||
|
# dans la variable $2(=hostname) et le domaine, qui est placée dans la variable
|
||||||
|
# $3(=domain)
|
||||||
|
splitfsep "$1" . "${2:-hostname}" "${3:-domain}"
|
||||||
|
}
|
||||||
|
function splituserhost() {
|
||||||
|
# Découper $1 de la forme [user@]host entre le nom de l'utilisateur, qui est placé
|
||||||
|
# dans la variable $2(=user) et le nom d'hôte, qui est placée dans la variable
|
||||||
|
# $3(=host)
|
||||||
|
splitfsep2 "$1" @ "${2:-user}" "${3:-host}"
|
||||||
|
}
|
||||||
|
function splitpair() {
|
||||||
|
# Découper $1 de la forme first[:second] entre la première valeur, qui est placé
|
||||||
|
# dans la variable $2(=src) et la deuxième valeur, qui est placée dans la variable
|
||||||
|
# $3(=dest)
|
||||||
|
splitfsep "$1" : "${2:-src}" "${3:-dest}"
|
||||||
|
}
|
||||||
|
function splitproxy() {
|
||||||
|
# Découper $1 de la forme http://[user:password@]host[:port]/ entre les valeurs
|
||||||
|
# $2(=host), $3(=port), $4(=user), $5(=password)
|
||||||
|
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() {
|
||||||
|
# Découper $1 de la forme scheme://[user:password@]host[:port]/path entre les
|
||||||
|
# valeurs $2(=scheme), $3(=user), $4(=password), $5(=host), $6(=port), $7(=path)
|
||||||
|
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"
|
||||||
|
}
|
|
@ -115,6 +115,7 @@ function strrepl() {
|
||||||
cmd="$cmd"'$pattern/$repl}"'
|
cmd="$cmd"'$pattern/$repl}"'
|
||||||
eval "$cmd"
|
eval "$cmd"
|
||||||
}
|
}
|
||||||
|
|
||||||
function isnum() {
|
function isnum() {
|
||||||
# retourner vrai si $1 est une valeur numérique entière (positive ou négative)
|
# retourner vrai si $1 est une valeur numérique entière (positive ou négative)
|
||||||
[ ${#1} -gt 0 ] || return 1
|
[ ${#1} -gt 0 ] || return 1
|
||||||
|
@ -162,3 +163,42 @@ function yesval() {
|
||||||
# afficher une chaine vide
|
# afficher une chaine vide
|
||||||
is_yes "$1" && echo 1
|
is_yes "$1" && echo 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function first_char() {
|
||||||
|
# retourner le premier caractère de la chaine $*
|
||||||
|
local str="$*"
|
||||||
|
echo "${str:0:1}"
|
||||||
|
}
|
||||||
|
function last_char() {
|
||||||
|
# retourner le dernier caractère de la chaine $*
|
||||||
|
local str="$*"
|
||||||
|
echo "${str: -1:1}"
|
||||||
|
}
|
||||||
|
function first_chars() {
|
||||||
|
# retourner tous les caractères de la chaine $*, excepté le dernier
|
||||||
|
local str="$*"
|
||||||
|
recho "${str:0:$((${#1}-1))}"
|
||||||
|
}
|
||||||
|
function last_chars() {
|
||||||
|
# retourner tous les caractères de la chaine $*, excepté le premier
|
||||||
|
local str="$*"
|
||||||
|
recho "${str:1}"
|
||||||
|
}
|
||||||
|
function first_char_is() {
|
||||||
|
# Tester si le premier caractère de la chaine $1 est $2
|
||||||
|
[ "${1:0:1}" == "$2" ]
|
||||||
|
}
|
||||||
|
function last_char_is() {
|
||||||
|
# Tester si le dernier caractère de la chaine $1 est $2
|
||||||
|
[ "${1:$((-1)):1}" == "$2" ]
|
||||||
|
}
|
||||||
|
function beginswith() {
|
||||||
|
# Tester si la chaine $1 commence par le wildcard $2
|
||||||
|
local str="$1" pattern="$2"
|
||||||
|
eval '[ "${str#$pattern}" != "$str" ]'
|
||||||
|
}
|
||||||
|
function endswith() {
|
||||||
|
# Tester si la chaine $1 se termine par le wildcard $2
|
||||||
|
local str="$1" pattern="$2"
|
||||||
|
eval '[ "${str%$pattern}" != "$str" ]'
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue