diff options
author | Oliver Eikemeier <eik@FreeBSD.org> | 2004-07-06 12:41:03 +0000 |
---|---|---|
committer | Oliver Eikemeier <eik@FreeBSD.org> | 2004-07-06 12:41:03 +0000 |
commit | 193ffbdfe83678690f5ed7a289fa511b66006f83 (patch) | |
tree | 27e1d2160ad77adae34ea49e01db91210533114c /ports-mgmt/portmk/scripts | |
parent | 4e3013cd8d46bc12b506ff9bfcb16ae14bc6cad1 (diff) | |
download | ports-193ffbdfe83678690f5ed7a289fa511b66006f83.tar.gz ports-193ffbdfe83678690f5ed7a289fa511b66006f83.zip |
Add devel/portmk, a place where bsd.port.mk development can happen.
Notes
Notes:
svn path=/head/; revision=113054
Diffstat (limited to 'ports-mgmt/portmk/scripts')
-rw-r--r-- | ports-mgmt/portmk/scripts/distfiles.sh | 1038 | ||||
-rw-r--r-- | ports-mgmt/portmk/scripts/ranksites-fping.pl | 139 | ||||
-rw-r--r-- | ports-mgmt/portmk/scripts/ranksites-geoip.pl | 390 |
3 files changed, 1567 insertions, 0 deletions
diff --git a/ports-mgmt/portmk/scripts/distfiles.sh b/ports-mgmt/portmk/scripts/distfiles.sh new file mode 100644 index 000000000000..994d40433bba --- /dev/null +++ b/ports-mgmt/portmk/scripts/distfiles.sh @@ -0,0 +1,1038 @@ +#!/bin/sh -e +# +# Copyright (c) 2004 Oliver Eikemeier. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright notice +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the author nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ +# +# MAINTAINER= eik@FreeBSD.org +# +# These variables are referenced and must be exported from the Makefile: +# +# DISABLE_SIZE +# DISTFILES +# DISTINFO_ALGORITHMS +# DISTINFO_LABEL +# DIST_SUBDIR +# ECHO_MSG +# FETCH_AFTER_ARGS +# FETCH_BEFORE_ARGS +# FETCH_CMD +# FETCH_ENV +# FETCH_SYMLINK_DISTFILES +# IGNOREFILES +# LOCALBASE +# MASTER_SITES +# MASTER_SITE_BACKUP +# MASTER_SITE_OVERRIDE +# MASTER_SORT_AWK +# MASTER_SORT_CMD +# MASTER_SORT_ENV +# MK_FILE +# NO_SIZE +# PATCHFILES +# PATCH_SITES +# PERL5 +# VALID_ALGORITHMS +# +# These variables are user settable: +# +# DISABLE_SIZE +# NO_CHECKSUM +# FETCH_REGET +# + +# utilities + +LOCALBASE="${LOCALBASE:-/usr/local}" + +AWK=/usr/bin/awk +CAT=/bin/cat +CUT=/usr/bin/cut +EXPR=/bin/expr +FETCH=/usr/bin/fetch +GREP=/usr/bin/grep +LS=/bin/ls +MD5=/sbin/md5 +MKDIR='/bin/mkdir -p' +MKTEMP=/usr/bin/mktemp +PERL5="${PERL5:-/usr/bin/perl}" +RM=/bin/rm +[ -x /sbin/rmd160 ] && RMD160=/sbin/rmd160 +SED=/usr/bin/sed +SETENV=/usr/bin/env +[ -x /sbin/sha1 ] && SHA1=/sbin/sha1 +SORT=/usr/bin/sort +TR=/usr/bin/tr +WC=/usr/bin/wc + +if [ -x /usr/bin/openssl ]; then + OPENSSL=/usr/bin/openssl +elif -x "$LOCALBASE/bin/openssl" ];then + OPENSSL="$LOCALBASE/bin/openssl" +fi + +# global constants + +MK_FILE_ENDMARKER='^\.include[ ]*(<bsd\.port(\.post)?\.mk>|"\${MASTERDIR}\/Makefile")$' + +FETCH_REGET="${FETCH_REGET:-1}" + +### utility functions ### + +### +# do_hash is a wrapper for md5/openssl/digest to calculate MD5/SHA1/RMD160 hashes +### + +do_hash() +{ + local alg + alg="$1" + shift + + case "$alg" in + [Mm][Dd]5) + if [ $# -eq 0 ]; then + $MD5 + else + $MD5 -- "$@" + fi;; + [Ss][Hh][Aa]1) + if [ -n "$SHA1" ]; then + echo $SHA1 + if [ $# -eq 0 ]; then + $SHA1 + else + $SHA1 -- "$@" + fi + else + if [ $# -eq 0 ]; then + "${OPENSSL:-true}" sha1 + else + "${OPENSSL:-true}" sha1 ./"$@" | + $SED -En -e 's/^[[:alnum:]]+ *\((\.\/)?(.*)\) *= *([[:xdigit:]]+)$/SHA1 (\2) = \3/p' + fi + fi;; + [Rr][Mm][Dd]160) + if [ -n "$RMD160" ]; then + if [ $# -eq 0 ]; then + $RMD160 + else + $RMD160 -- "$@" + fi + else + if [ $# -eq 0 ]; then + "${OPENSSL:-true}" rmd160 + else + "${OPENSSL:-true}" rmd160 ./"$@" | + $SED -En -e 's/^[[:alnum:]]+ *\((\.\/)?(.*)\) *= *([[:xdigit:]]+)$/RMD160 (\2) = \3/p' + fi + fi;; + [Ss][Ii][Zz][Ee]) + if [ $# -eq 0 ]; then + $WC -c + else + while [ $# -gt 0 ]; do + # avoid hassle with CLICOLOR_FORCE + $LS -ALdfln -- "$1" | $AWK '{ print "SIZE ('"$1"') = " $5 }' + shift + done + fi;; + *) + return 1;; + esac +} + +### +# extract_sum extracts all checksums for a file in distinfo +### + +extract_sum() +{ + local algorithms pattern + algorithms=`echo -n "$1" | $TR -s ' \t\n' '|'` + pattern=`echo "$2$3" | $SED -e 's;[/.[\(*+?{|^$];\\\\&;g'` + # distfiles match [a-zA-Z0-9.,_/@&%?=+-]+ + + [ $# -eq 3 ] || return 1 + + if [ -f "$MD5_FILE" ]; then + $SED -En -e '/^('"$algorithms"') *\('"$pattern"'\) *= */s//\1=/p' "$MD5_FILE" + elif $GREP -qs "^#:distinfo${DISTINFO_LABEL:+\.$DISTINFO_LABEL}$" "$MK_FILE"; then + $SED -En -e ' + 1,/'"$MK_FILE_ENDMARKER"'/d + /^#/!q + /^#:distinfo'"${DISTINFO_LABEL:+.$DISTINFO_LABEL}"'$/,/^#:/ { + s/^#('"$algorithms"') *\('"$pattern"'\) *= */\1=/ + t match + b nomatch + :match + H + :nomatch + } + $ { + g + p + } + ' "$MK_FILE" + else + for alg in $1; do + for sum in `eval echo \\$DISTINFO_$alg`; do + if [ "${sum%:*}" = "$3" ]; then + echo "$alg=${sum##*:}" + fi + done + done + fi +} + +### +# chksumfiles calculates CKSUMFILES = DISTFILES + PATCHFILES - IGNOREFILES +### + +chksumfiles() +{ + echo "$IGNOREFILES" '<>' "$DISTFILES" "$PATCHFILES" | + $TR -s ' \t' '\n' | $AWK ' + BEGIN { isignore=1 } + /^$/ { next } + /^<>$/ { isignore=0; next } + { + if (isignore !=0) { + ignore[$0]=1 + } else if (!($0 in ignore)) { + sub(/:[^:]+$/, "") + print + } + } + ' +} + +### fetching distfiles ### + +### +# fetch_xxx are wrappers for fetch +### + +setup_fetch_cmd() +{ + [ -z "$fetch_cmd" ] || return 0 + + case "${FETCH_CMD%% *}" in + */curl) + fetch_cmd=fetch_curl;; + */wget) + fetch_cmd=fetch_wget;; + *) + fetch_cmd=fetch_fetch;; + esac +} + +fetch_curl() +{ + local cksize + + cksize= + if [ -n "$3" ]; then + cksize=" --max-filesize $3" + fi + + $SETENV $FETCH_ENV $FETCH_CMD $FETCH_BEFORE_ARGS$cksize \ + $4 -o "$2" "$1" $FETCH_AFTER_ARGS +} + +fetch_fetch() +{ + local cksize + + case "$2" in + */*) + [ -d "${file%/*}" ] || $MKDIR "${file%/*}";; + esac + + symlink= + if [ -n "$FETCH_SYMLINK_DISTFILES" ]; then + symlink=" -l" + fi + + cksize= + if [ -n "$3" -a "$OSVERSION" -ge 480000 ]; then + cksize=" -S $3" + fi + + $SETENV $FETCH_ENV $FETCH_CMD $FETCH_BEFORE_ARGS$symlink$cksize \ + $4 -o "$2" "$1" $FETCH_AFTER_ARGS +} + +fetch_wget() +{ + case "$4" in + file:*) + fetch_fetch "$@" || return 1 + return 0;; + esac + + case "$2" in + */*) + [ -d "${file%/*}" ] || $MKDIR "${file%/*}";; + esac + + $SETENV $FETCH_ENV $FETCH_CMD $FETCH_BEFORE_ARGS \ + $4 -O "$2" "$1" $FETCH_AFTER_ARGS +} + +### +# get_master_sites returns a list of $1_SITES for groups $2 +### + +get_master_sites() +{ + [ $# -eq 2 ] || return 1 + + # fun with awk + for group in $2; do + eval echo "\"\${$1_SITE_SUBDIR}\"" "'<>'" "\"\${$1_SITES}\"" | + $TR -s ' \t' '\n' | + $AWK ' + BEGIN { + issubdir=1 + subdirs=0 + } + /^$/ { next } + /^<>$/ { + issubdir=0 + if (subdirs == 0) + subdir[subdirs++]="" + next + } + { + if ($0 ~ /\/:[^\/:]+$/) { + if ($0 !~ /\/:([^\/:]*,)*'"$group"'(,[^\/:]*)*$/) + next + sub(/\/:[^\/:]+$/, issubdir != 0 ? "" : "/") + } else if ("'"$group"'" != "DEFAULT") { + next + } + } + { + if (issubdir != 0) + subdir[subdirs++]=($0 == "." ? "" : $0 "/") + else + for (i in subdir) { + site=$0 + gsub(/%SUBDIR%\//, subdir[i], site) + print site + } + } + '; + done | + $AWK '{ if ($0 in done) next; done[$0]=1 } { print }' +} + +### +# get_master_sites_sorted returns a sorted list of $1_SITES for groups $2 +### + +get_master_sites_sorted() +{ + get_master_sites "$@" | + if [ -n "$MASTER_SORT_CMD" ]; then + $SETENV $MASTER_SORT_ENV $MASTER_SORT_CMD | $TR -s '\n' ' ' + elif [ -z "$KEEP_MASTER_SITE_ORDER" ]; then + $AWK 'BEGIN { srand() } { print rand() "\t" $0 }' | + $SORT -n | $CUT -f 2 | $TR -s '\n' ' ' | + $AWK "$MASTER_SORT_AWK" + else + $TR -s '\n' ' ' | + $AWK "$MASTER_SORT_AWK" + fi +} + +### +# fetch_file tries to fetch one file from {MASTER,PATCH}_SITES +### + +fetch_file() +{ + [ $# -eq 5 ] || return 1 + + fetch_reget="${FETCH_REGET}" + SORTED_MASTER_SITES_TMP=`get_master_sites_sorted "$1" "$2"` + for site in $_MASTER_SITE_OVERRIDE \ + $SORTED_MASTER_SITES_TMP $_MASTER_SITE_BACKUP; do + $ECHO_MSG ">> Attempting to fetch from $site${4:+ (${4#*=} bytes)}." + case "$site" in + *%FILE%*) + # this expression uses ctrl-A as delimiters + url=`echo "$site" | $SED -E -e 's/$; s%FILE%'"$file"'g'`;; + *) + url="$site$file";; + esac + if $fetch_cmd "$url" "$3" "$4"; then + [ -f "$file" ] || continue + [ -z "$5" ] && return 0 + for cksum2 in $5; do + case "${cksum2#*=}" in + IGNORE) + return 0;; + *) + CKSUM=`do_hash "${cksum2%%=*}" < "$file"` + if [ "${cksum2#*=}" = "$CKSUM" ]; then + $ECHO_MSG ">> Checksum OK (${cksum2%%=*}) for $file." + return 0 + fi;; + esac + done + $ECHO_MSG ">> Checksum mismatch for $_file." + if [ "$fetch_reget" -gt 0 ]; then + $ECHO_MSG "===> Refetch for $fetch_reget more times." + $RM -f "$file" + fetch_reget=$(($fetch_reget-1)) + else + $ECHO_MSG ">> To get this file from more mirrors," \ + "type \"make FETCH_REGET=99 [other args]\"." + $ECHO_MSG "===> Giving up on fetching $_file." + return 1 + fi + fi + done + $ECHO_MSG ">> Couldn't fetch it - please try to retrieve this" + $ECHO_MSG ">> file manually into $_DISTDIR and try again." + return 1 +} + +### +# do_fetch tries to fetch DISTFILES and PATCHFILES +### + +do_fetch() +{ + local _DISTDIR + local DIR + local file + local select + + setup_fetch_cmd + + _DISTDIR="$DISTDIR${DIST_SUBDIR:+/$DIST_SUBDIR}" + DIR="${DIST_SUBDIR:+$DIST_SUBDIR/}" + + for fileset in MASTER PATCH; do + case "$fileset" in + MASTER) + files="$DISTFILES";; + PATCH) + files="$PATCHFILES";; + *) + return 1;; + esac + for _file in $files; do + + file=`echo "$_file" | $SED -E -e 's/:[^:]+$//'` + select=`echo "$_file" | $SED -En -e 'y/,/ /; s/.*:([^:]+)$/\1/p'` + [ -n "$select" ] || select="DEFAULT" + + if [ -z "$NO_CHECKSUM" ]; then + CKSUM2=`extract_sum "$VALID_ALGORITHMS" "$DIR" "$file"` + if [ -z "$CKSUM2" ]; then + $ECHO_MSG ">> No checksum entry for $DIR$file." + $ECHO_MSG ">> Make sure the Makefile and distinfo file ($MD5_FILE) are" + $ECHO_MSG ">> up to date. If you are absolutely sure you want to override" + $ECHO_MSG ">> this check, type \"make NO_CHECKSUM=yes [other args]\"." + return 1 + fi + chkfile=true + for ignore in $IGNOREFILES; do + if [ "$file" = "$ignore" ]; then + chkfile=false + fi + done + else + CKSUM2= + chkfile=false + fi + + if [ -f "$_DISTDIR/$file" ]; then + fileexists=true + else + fileexists=false + if [ -L $file ]; then + $ECHO_MSG ">> $_DISTDIR/$file is a broken symlink." + $ECHO_MSG ">> Perhaps a filesystem (most likely a CD) isn't mounted?" + $ECHO_MSG ">> Please correct this problem and try again." + return 1 + fi + fi + + fetchfile=true + if $fileexists; then + if [ -n "$CKSUM2" ]; then + for cksum2 in $CKSUM2; do + case "${cksum2#*=}" in + IGNORE) + if $chkfile; then + $ECHO_MSG ">> Checksum for $file is set to IGNORE in distinfo file" + $ECHO_MSG " even though the file is not in the "'$'"{IGNOREFILES} list." + return 1 + fi + fetchfile=false + break;; + *) + if ! $chkfile; then + $ECHO_MSG ">> Checksum for $file is not set to IGNORE in distinfo file" + $ECHO_MSG " even though the file is in the "'$'"{IGNOREFILES} list." + return 1 + fi + CKSUM=`do_hash "${cksum2%%=*}" < "$_DISTDIR/$file"` + if [ "${cksum2#*=}" = "$CKSUM" ]; then + $ECHO_MSG ">> Checksum OK (${cksum2%%=*}) for $file." + fetchfile=false + break + fi;; + esac + done + if $fetchfile; then + $ECHO_MSG ">> Checksum mismatch for $file." + fi + else + fetchfile=false + fi + else + if [ -n "$CKSUM2" ]; then + for cksum2 in $CKSUM2; do + case "${cksum2#*=}" in + IGNORE) + if $chkfile; then + $ECHO_MSG ">> Checksum for $file is set to IGNORE in distinfo file" + $ECHO_MSG " even though the file is not in the "'$'"{IGNOREFILES} list." + return 1 + fi + break;; + *) + if ! $chkfile; then + $ECHO_MSG ">> Checksum for $file is not set to IGNORE in distinfo file" + $ECHO_MSG " even though the file is in the "'$'"{IGNOREFILES} list." + return 1 + fi;; + esac + done + fi + $ECHO_MSG ">> $file doesn't seem to exist in $_DISTDIR." + fi + + if $fetchfile; then + if ! { [ -d "$_DISTDIR" ] || $MKDIR "$_DISTDIR"; }; then + $ECHO_MSG ">> Cannot create $_DISTDIR." + return 1 + fi + if [ ! -w "$_DISTDIR" ]; then + $ECHO_MSG ">> $_DISTDIR is not writable by you; cannot fetch." + return 1 + fi + if [ -z "$NO_CHECKSUM" -a -z "$DISABLE_SIZE" ]; then + CKSIZE=`extract_sum 'SIZE' "$DIR" "$file"` + else + CKSIZE= + fi + cd "$_DISTDIR" + if ! fetch_file "$fileset" "$select" "$file" "${CKSIZE#*=}" "$CKSUM2"; then + return 1 + fi + fi + done + done +} + +### missing size ### + +### +# print_missing_size prints a list of all files that are not in DISTDIR +### + +print_missing_size() +{ + local _DISTDIR + local DIR + local file + local select + + CKSUMFILES="${CKSUMFILES:-`chksumfiles`}" + + DIR="${DIST_SUBDIR:+$DIST_SUBDIR/}" + + for _file in $CKSUMFILES; do + file="$DIR$_file" + [ -f "$DISTDIR/$file" ] && continue + CKSIZE=`extract_sum 'SIZE' "$DIR" "$_file"` + if [ -n "${CKSIZE#*=}" ]; then + echo "${CKSIZE#*=} $file" + else + echo "0 $file" + fi + done + + for _file in $IGNOREFILES; do + file="$DIR$_file" + [ -f "$DISTDIR/$file" ] && continue + echo "0 $file" + done +} + +### fetch all ## + +### +# do_fetch_all tries to fetch all files from *every* site +### + +do_fetch_all() +{ + local DIR + local file + local select + + setup_fetch_cmd + + _FAILED_SITES= + DIR="${DIST_SUBDIR:+$DIST_SUBDIR/}" + + for fileset in MASTER PATCH; do + case "$fileset" in + MASTER) + files="$DISTFILES";; + PATCH) + files="$PATCHFILES";; + *) + return 1;; + esac + + for _file in $files; do + file=`echo "$_file" | $SED -E -e 's/:[^:]+$//'` + select=`echo "$_file" | $SED -En -e 'y/,/ /; s/.*:([^:]+)$/\1/p'` + [ -n "$select" ] || select="DEFAULT" + + CKSUM2=`extract_sum "$VALID_ALGORITHMS" "$DIR" "$file"` + if [ -z "$CKSUM2" ]; then + $ECHO_MSG ">> No checksum recorded for $DIR$file." + return 1 + fi + CKSIZE=`extract_sum 'SIZE' "$DIR" "$file"` + + $ECHO_MSG ">> Verifying availability of file $file." + MASTER_SITES_TMP=`get_master_sites "$fileset" "$select"` + for site in $MASTER_SITES_TMP; do + $ECHO_MSG ">> Attempting to fetch from $site${CKSIZE:+ (${CKSIZE#*=} bytes)}." + case "$site" in + *%FILE%*) + # this expression uses ctrl-A as delimiters + url=`echo "$site" | $SED -E -e 's/$; s%FILE%'"$file"'g'`;; + *) + url="$site$file";; + esac + if [ -z "$NO_CHECKSUM" ]; then + for cksum2 in $CKSUM2; do + _FETCH_RESULT=`{ if ! $fetch_cmd "$url" "-" "${CKSIZE#*=}"; then \ + echo "FAILED: $$?" >&3; fi | do_hash "${cksum2%%=*}"; } 3>&1`; + case "$_FETCH_RESULT" in + FAILED:*) + $ECHO_MSG ">> Fetch from $site failed." + _FAILED_SITES="${_FAILED_SITES:+$_FAILED_SITES }$url";; + *) + case "${cksum2#*=}" in + IGNORE) + $ECHO_MSG ">> Checksum IGNORED for $file.";; + "$_FETCH_RESULT") + $ECHO_MSG ">> Checksum OK (${cksum2%%=*}) for $file.";; + *) + $ECHO_MSG ">> Checksum mismatch (${cksum2%%=*}) for $file." + _FAILED_SITES="${_FAILED_SITES:+$_FAILED_SITES }$url";; + esac;; + esac + break + done + else + if _FETCH_RESULT=`$SETENV $FETCH_ENV $FETCH -s "$url"`; then + if [ -z "$DISABLE_SIZE" -a -n "${CKSIZE#*=}" ]; then + if [ "${CKSIZE#*=}" = "$_FETCH_RESULT" ]; then + $ECHO_MSG ">> Size OK (${CKSIZE#*=}) for $file." + else + $ECHO_MSG ">> Size mismatch ($_FETCH_RESULT) for $file." + _FAILED_SITES="${_FAILED_SITES:+$_FAILED_SITES }$url" + fi + else + $ECHO_MSG ">> Found $file." + fi + else + echo ">> Fetch from $site failed." + _FAILED_SITES="${_FAILED_SITES:+$_FAILED_SITES }$url" + fi + fi + done + done + done + if [ -z "$_FAILED_SITES" ]; then + echo ">> All files are fetchable." + else + echo ">> The following files did not fetch correctly:" + echo "$_FAILED_SITES" | ${TR} ' ' '\n' | ${SED} -e 's/^/ - /' + fi +} + +### +# do_fetch_list generates a list of files to fetch +### + +do_fetch_list() +{ + local _DISTDIR + local DIR + local file + local select + + _DISTDIR="$DISTDIR${DIST_SUBDIR:+/$DIST_SUBDIR}" + DIR="${DIST_SUBDIR:+$DIST_SUBDIR/}" + + for fileset in MASTER PATCH; do + case "$fileset" in + MASTER) + files="$DISTFILES";; + PATCH) + files="$PATCHFILES";; + *) + return 1;; + esac + + for _file in $files; do + + file=`echo "$_file" | $SED -E -e 's/:[^:]+$//'` + select=`echo "$_file" | $SED -En -e 'y/,/ /; s/.*:([^:]+)$/\1/p'` + [ -n "$select" ] || select="DEFAULT" + + if [ ! -f "$_DISTDIR/$file" ]; then + SORTED_MASTER_SITES_TMP=`get_master_sites_sorted "$fileset" "$select"` + for site in $_MASTER_SITE_OVERRIDE \ + $SORTED_MASTER_SITES_TMP $_MASTER_SITE_BACKUP; do + case "$site" in + *%FILE%*) + # this expression uses ctrl-A as delimiters + url=`echo "$site" | $SED -E -e 's/$; s%FILE%'"$file"'g'`;; + *) + url="$site$file";; + esac + if [ -n "$FETCH_ENV" ]; then + echo -n "$SETENV $FETCH_ENV " + fi + echo -n "$FETCH_CMD $FETCH_BEFORE_ARGS" \ + "-o '$file' '$url' $FETCH_AFTER_ARGS || " + done + echo "echo '$file not fetched'" + fi + done + + done +} + +### distinfo ### + +### +# make_tmpsum generates a temporary distinfo file +### + +make_tmpsum() +{ + local NO_CHECKSUM DISABLE_SIZE + + NO_CHECKSUM=true + DISABLE_SIZE=true + + do_fetch || return 1 + + CKSUMFILES="${CKSUMFILES:-`chksumfiles`}" + + if ! TMPMD5_FILE=`$MKTEMP -q "$MD5_FILE.XXXXXX"`; then + echo ">> makesum: Can't create temporary checksum file" + return 1 + fi + + cd "$DISTDIR" + DIR="${DIST_SUBDIR:+$DIST_SUBDIR/}" + + MY_ALGS="$DISTINFO_ALGORITHMS"; + [ -z "$NO_SIZE" ] && MY_ALGS="$MY_ALGS SIZE" + + # faster, but not the same sort order as the `classic' distinfo + #for alg in $MY_ALGS; do + # do_hash "$alg" `echo "$CKSUMFILES" | $SED -e "s^$DIR"` >> "$TMPMD5_FILE" + #done + + for _file in $CKSUMFILES; do + file="$DIR$_file" + if [ -r "$file" ]; then + for alg in $MY_ALGS; do + do_hash "$alg" "$file" >> "$TMPMD5_FILE" + done + else + $ECHO_MSG ">> $file is not in $DISTDIR" + $RM "$TMPMD5_FILE" + return 1 + fi + done + for _file in $IGNOREFILES; do + file="$DIR$_file" + echo "MD5 ($file) = IGNORE" >> "$TMPMD5_FILE" + done +} + +### +# replace_distinfo adds or replaces a distinfo entry in MK_FILE +### + +replace_distinfo() +{ + [ $# -eq 1 -a -f "$1" ] || return 1 + + if ! TMPMK_FILE=`$MKTEMP -q "$MK_FILE.XXXXXX"`; then + $ECHO_MSG ">> makesum: Can't create temporary Makefile" + return 1 + fi + if ! $AWK -v MD5_FILE="$1" ' + BEGIN { seen=0; ignore=0; first=1 } + /'"$MK_FILE_ENDMARKER"'/ { seen=NR } + NR == 1, seen != 0 { print; next } + !/^#/ { exit 1 } + /^#:/ { ignore=0 } + /^#:distinfo'"${DISTINFO_LABEL:+\.$DISTINFO_LABEL}"'$/ { + if (first) + while ((getline md5_line < MD5_FILE) > 0) { + if (first) { + print "#:distinfo'"${DISTINFO_LABEL:+\.$DISTINFO_LABEL}"'" + first=0 + } + print "#" md5_line + } + ignore=1 + } + ignore == 0 { print } + END { + if (seen == 0) + exit 1 + if (first) + while ((getline md5_line < MD5_FILE) > 0) { + if (first) { + print "#:distinfo'"${DISTINFO_LABEL:+\.$DISTINFO_LABEL}"'" + first=0 + } + print "#" md5_line + } + } + ' "$MK_FILE" > "$TMPMK_FILE"; then + $ECHO_MSG ">> Parse error: $MK_FILE, end of file not found" + $RM "$TMPMK_FILE" + return 1 + fi + $CAT "$TMPMK_FILE" > "$MK_FILE" + $RM "$TMPMK_FILE" +} + +### +# replace_distinfo2 adds or replaces a distinfo entry in MK_FILE +### + +replace_distinfo2() +{ + [ $# -eq 1 -a -f "$1" ] || return 1 + + if [ ! -x "$PERL5" ]; then + $ECHO_MSG ">> makesum: perl 5 required, please install lang/perl" + return 1 + fi + + #XXX TODO: honor status of $ECHO_MSG in `die' + if ! $PERL5 -w -e ' + use strict; + srand(); + my $marker="##-MARKER_".rand()."-##"; + my $valid_algs=join "|", "SIZE", split " ", $ARGV[3]; + my $distsubdir=$ARGV[1] ? "$ARGV[1]/" : ""; + my $distlabel=$ARGV[2] ? "$ARGV[2]_" : ""; + my %distinfo; + + open DISTINFO, "<$ARGV[0]" + or die ">> migratesum2: error reading $ARGV[0]\n"; + while(<DISTINFO>) { + push @{$distinfo{$1}{$2}}, $3 + if /^(\w+) *\($distsubdir(.*)\) *= *([\da-f]+)$/o + } + close DISTINFO; + my $makefile; + open MAKEFILE, "<$ARGV[4]" + or die ">> migratesum2: error reading $ARGV[4]\n"; + { + local $/; + $makefile = <MAKEFILE>; + } + close MAKEFILE; + my $newinfo; + foreach my $key (split " ", $ARGV[3]) { + next + if !$distinfo{$key}; + my @chksum = (); + foreach my $file (sort keys %{$distinfo{$key}}) { + push @chksum, map "$file:$_", @{$distinfo{$key}{$file}}; + } + $newinfo .= "DISTINFO_$distlabel$key+=\t"; + $newinfo .= join " \\\n\t\t", "", @chksum; + $newinfo .= "\n"; + } + $makefile =~ s/^DISTINFO_$distlabel(?:$valid_algs)[+:!?]?=.*(?:\\\n.*)*[^\\\n]\n/$marker\n/mg || + $makefile =~ s/^(COMMENT[+:!?]?=.*(?:\\\n.*)*[^\\\n])\n+/$1\n\n$marker\n\n/m || + die ">> migratesum2: error parsing $ARGV[4]\n"; + + $makefile =~ s/^$marker\n/$newinfo/m; + $makefile =~ s/^$marker\n//mg; + + open MAKEFILE, ">$ARGV[5]" + or die ">> migratesum2: error writing $ARGV[4]\n"; + print MAKEFILE $makefile; + close MAKEFILE; + ' "$1" "$DIST_SUBDIR" "$DISTINFO_LABEL" "$VALID_ALGORITHMS SIZE" "$MK_FILE" "$MK_FILE"; then + return 1 + fi +} + + +### +# do_makesum (re-)calculates distinfo +### + +do_makesum() +{ + local algorithms + algorithms=`echo -n "$VALID_ALGORITHMS SIZE" | $TR -s ' \t\n' '|'` + + make_tmpsum || return 1 + + if [ -f "$MD5_FILE" ]; then + $CAT "$TMPMD5_FILE" > "$MD5_FILE" + elif $GREP -qs "^#:distinfo${DISTINFO_LABEL:+\.$DISTINFO_LABEL}$" "$MK_FILE"; then + replace_distinfo "$TMPMD5_FILE" + elif $GREP -Eqs "^DISTINFO${DISTINFO_LABEL:+_$DISTINFO_LABEL}_($algorithms)[+:!?]?=" "$MK_FILE"; then + replace_distinfo2 "$TMPMD5_FILE" + elif [ -s "$TMPMD5_FILE" ]; then + $CAT "$TMPMD5_FILE" > "$MD5_FILE" + fi + + $RM "$TMPMD5_FILE" +} + +### +# do_migratemakesum integrates distinfo into the port's Makefile +### + +do_migratesum() +{ + if [ ! -f "$MD5_FILE" ]; then + $ECHO_MSG ">> migratesum: no $MD5_FILE" + return 1 + fi + + if replace_distinfo "$MD5_FILE"; then + $RM "$MD5_FILE" + echo ">> Done." + else + return 1 + fi +} + +### +# do_migratemakesum2 integrates distinfo into the port's Makefile +### + +do_migratesum2() +{ + if [ ! -f "$MD5_FILE" ]; then + $ECHO_MSG ">> migratesum2: no $MD5_FILE" + return 1 + fi + + if replace_distinfo2 "$MD5_FILE"; then + $RM "$MD5_FILE" + echo ">> Done." + else + return 1 + fi +} + +### +# main +### + +opt_fetch_list=false +opt_makesum=false +opt_migratesum=false +opt_migratesum2=false +opt_fetch=false +opt_fetch_all=false +opt_missing_size=false + +while getopts "LmMNfFS" opt; do + case "$opt" in + L) opt_fetch_list=true;; + m) opt_makesum=true;; + M) opt_migratesum=true;; + N) opt_migratesum2=true;; + f) opt_fetch=true;; + F) opt_fetch_all=true;; + S) opt_missing_size=true;; + ?) echo "Usage: $0 -LmMfFS"; exit 1;; + esac +done + +shift $(($OPTIND-1)) + +$opt_fetch_list && + { do_fetch_list || exit 1; } + +$opt_fetch && + { do_fetch || exit 1; } + +$opt_makesum && + { do_makesum || exit 1; } + +$opt_migratesum && + { do_migratesum || exit 1; } + +$opt_migratesum2 && + { do_migratesum2 || exit 1; } + +$opt_fetch_all && + { do_fetch_all || exit 1; } + +$opt_missing_size && + { print_missing_size || exit 1; } + +exit 0 diff --git a/ports-mgmt/portmk/scripts/ranksites-fping.pl b/ports-mgmt/portmk/scripts/ranksites-fping.pl new file mode 100644 index 000000000000..db399548b22c --- /dev/null +++ b/ports-mgmt/portmk/scripts/ranksites-fping.pl @@ -0,0 +1,139 @@ +#!/usr/bin/perl -w +# +# Copyright (c) 2004 Oliver Eikemeier. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright notice +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the author nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ +# +# MAINTAINER= eik@FreeBSD.org +# + +require 5.005; +use strict; + +my $dbdir = $ENV{RANKDIR} ? $ENV{RANKDIR} : '/var/db/distrank'; + +my $fping = $ENV{FPING} ? $ENV{FPING} : '/usr/local/sbin/fping'; + +-x $fping + or die "fping required\n"; + +-d $dbdir || mkdir $dbdir, 0777 + or die "Can't create $dbdir\n"; + +my $rankfile = "$dbdir/ranks-fping"; + +my $now = time; + +my %distance; + +if (-r $rankfile) { + open RANKS, "<$rankfile"; + while (<RANKS>) { + chomp; + my ($host, $d, $e) = split; + $distance{$host} = [$d, $e] + if defined $e && $e >= $now; + } + close RANKS; +} + +my %mastersites; +my %newdistance; + +my $distgood = 0; +my $distdefault = 5000; +my $distbad = 10000; + +my $expgood = $now + 14 * 86400; +my $expdefault = $now + 7 * 86400; + +my $hostcount = 0; + +while (<>) { + chomp; + next + if exists $mastersites{$_}; + if (m'^(?:ftp|https?)://(?:[^/]*@)?([^/:]+\.[^/:]+)(?::\d+)?(?:/|$)'i) { + my $host = lc $1; + $mastersites{$_} = $host; + if (!defined $distance{$host}) { + $distance{$host} = [$distdefault, $expdefault]; + $newdistance{$host} = undef + } + $hostcount++; + } elsif (m'^file:'i) { + $mastersites{$_} = 'FILE'; + } else { + $mastersites{$_} = 'UNKNOWN'; + } +} + +if (%newdistance && $hostcount > 1) { + if (!open FPING, '-|') { + if (!open FPINGIN, '|-') { + open STDERR, '>&STDOUT'; + exec $fping, '-q', '-C', '3'; + die + } + foreach (keys %newdistance) { + print FPINGIN $_, "\n"; + } + close FPINGIN; + exit; + } + + while(<FPING>) { + /([^\s:]+)\s*:\s*([\s\d.-]*)/ or next; + my $sum = 0.0; + my $num = 0; + foreach my $val (split ' ', $2) { + $val ne '-' || next; + $sum += $val; + $num++; + } + if ($num > 0) { + $distance{$1} = [$sum/$num, $expgood]; + } + } + close FPING; + + open RANKS, ">$rankfile"; + while (my ($host, $val) = each %distance) { + printf RANKS "%s\t%.2f\t%d\n", $host, $val->[0], $val->[1] + if defined $val; + } + close RANKS; +} + +$distance{FILE} = [$distgood, 0]; +$distance{UNKNOWN} = [$distbad, 0]; + +foreach (sort {$distance{$mastersites{$a}}->[0] <=> $distance{$mastersites{$b}}->[0]} keys %mastersites) { + print $_, "\n"; +} diff --git a/ports-mgmt/portmk/scripts/ranksites-geoip.pl b/ports-mgmt/portmk/scripts/ranksites-geoip.pl new file mode 100644 index 000000000000..4631ff6038a3 --- /dev/null +++ b/ports-mgmt/portmk/scripts/ranksites-geoip.pl @@ -0,0 +1,390 @@ +#!/usr/bin/perl -w +# +# Copyright (c) 2004 Oliver Eikemeier. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright notice +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the author nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ +# +# MAINTAINER= eik@FreeBSD.org +# + +require 5.005; +use strict; +use Geo::IP; +use constant PI => 3.14159265358979323846; + +my $home = $ENV{CC_HOME} ? lc $ENV{CC_HOME} : 'eu'; + +my $dbdir = $ENV{RANKDIR} ? $ENV{RANKDIR} : '/var/db/distrank'; + +-d $dbdir || mkdir $dbdir, 0777 or die "Can't create $dbdir\n"; + +my $rankfile = "$dbdir/ranks-geoip"; + +my $now = time; + +my %distance; + +if (-r $rankfile) { + open RANKS, "<$rankfile"; + while (<RANKS>) { + chomp; + my ($host, $d, $e) = split; + $distance{$host} = [$d, $e] + if defined $e && $e >= $now; + } + close RANKS; +} + +my %mastersites; +my %newdistance; + +my $distgood = -1; +my $distdefault = PI/2; +my $distbad = 2; + +my $expgood = $now + 14 * 86400; +my $expdefault = $now + 7 * 86400; + +my $hostcount = 0; + +while (<>) { + chomp; + next + if exists $mastersites{$_}; + if (m'^(?:ftp|https?)://(?:[^/]*@)?([^/:]+\.[^/:]+)(?::\d+)?(?:/|$)'i) { + my $host = lc $1; + $mastersites{$_} = $host; + if (!defined $distance{$host}) { + $distance{$host} = [$distdefault, $expdefault]; + $newdistance{$host} = undef + } + $hostcount++; + } elsif (m'^file:'i) { + $mastersites{$_} = 'FILE'; + } else { + $mastersites{$_} = 'UNKNOWN'; + } +} + +# calculate_distance and the associated table is from Geo::Mirror, and therefore +# Copyright (c) 2002, T.J. Mather, tjmather@tjmather.com, New York, NY, USA + +my (%lat, %lon); + +sub getlatlon { + my ($cc) = @_; + my ($lat_cc, $lon_cc) = ($lat{$cc}, $lon{$cc}); + + # Convert all the degrees to radians + $lat_cc *= PI/180 + if defined $lat_cc; + $lon_cc *= PI/180 + if defined $lon_cc; + return ($lat_cc, $lon_cc); +} + +if (%newdistance && $hostcount > 1) { + while (<main::DATA>) { + my ($country, $lat, $lon) = split(':'); + + $lat{$country} = $lat; + $lon{$country} = $lon; + } + close main::DATA; + + my $gi = Geo::IP->new(GEOIP_MEMORY_CACHE); + + my ($lat_home, $lon_home) = getlatlon($home); + + foreach (keys %newdistance) { + my $dist; + my $cc = lc $gi->country_code_by_name($_); + my ($lat_cc, $lon_cc) = getlatlon($cc) + if defined $cc; + + # Find the deltas + my $delta_lat = $lat_cc - $lat_home; + my $delta_lon = $lon_cc - $lon_home; + + # Find the Great Circle distance + my $temp = sin($delta_lat/2.0)**2 + cos($lat_home) * cos($lat_cc) * sin($delta_lon/2.0)**2; + $dist = atan2(sqrt($temp),sqrt(1-$temp)); + + $distance{$_} = [$dist, $expgood] + if defined $dist; + } + + open RANKS, ">$rankfile"; + while (my ($host, $val) = each %distance) { + printf RANKS "%s\t%.4f\t%d\n", $host, $val->[0], $val->[1] + if defined $val; + } + close RANKS; +} + +$distance{FILE} = [$distgood, 0]; +$distance{UNKNOWN} = [$distbad, 0]; + +foreach (sort {$distance{$mastersites{$a}}->[0] <=> $distance{$mastersites{$b}}->[0]} keys %mastersites) { + print $_, "\n"; +} + +__END__ +af:33:65 +al:41:20 +dz:28:3 +as:-14:-170 +ad:42:1 +ao:-12:18 +ai:18:-63 +aq:-90:0 +ag:17:-61 +ar:-34:-64 +am:40:45 +aw:12:-69 +au:-27:133 +at:47:13 +az:40:47 +bs:24:-76 +bh:26:50 +bd:24:90 +bb:13:-59 +by:53:28 +be:50:4 +bz:17:-88 +bj:9:2 +bm:32:-64 +bt:27:90 +bo:-17:-65 +ba:44:18 +bw:-22:24 +bv:-54:3 +br:-10:-55 +io:-6:71 +vg:18:-64 +bg:43:25 +bf:13:-2 +bi:-3:30 +kh:13:105 +cm:6:12 +ca:60:-95 +cv:16:-24 +ky:19:-80 +cf:7:21 +td:15:19 +cl:-30:-71 +cn:35:105 +cx:-10:105 +cc:-12:96 +co:4:-72 +km:-12:44 +cd:0:25 +cg:-1:15 +ck:-21:-159 +cr:10:-84 +ci:8:-5 +hr:45:15 +cu:21:-80 +cy:35:33 +cz:49:15 +dk:56:10 +dj:11:43 +dm:15:-61 +do:19:-70 +ec:-2:-77 +eg:27:30 +sv:13:-88 +gq:2:10 +er:15:39 +ee:59:26 +et:8:38 +fk:-51:-59 +fo:62:-7 +fj:-18:175 +fi:64:26 +fr:46:2 +gf:4:-53 +pf:-15:-140 +ga:-1:11 +gm:13:-16 +ge:42:43 +de:51:9 +eu:48:10 +gh:8:-2 +gi:36:-5 +gr:39:22 +gl:72:-40 +gd:12:-61 +gp:16:-61 +gu:13:144 +gt:15:-90 +gn:11:-10 +gw:12:-15 +gy:5:-59 +ht:19:-72 +hm:-53:72 +va:41:12 +hn:15:-86 +hk:22:114 +hu:47:20 +is:65:-18 +in:20:77 +id:-5:120 +ir:32:53 +iq:33:44 +ie:53:-8 +il:31:34 +it:42:12 +jm:18:-77 +sj:71:-8 +jp:36:138 +jo:31:36 +ke:1:38 +ki:1:173 +kp:40:127 +kr:37:127 +kw:29:45 +kg:41:75 +lv:57:25 +lb:33:35 +ls:-29:28 +lr:6:-9 +ly:25:17 +li:47:9 +lt:56:24 +lu:49:6 +mo:22:113 +mk:41:22 +mg:-20:47 +mw:-13:34 +my:2:112 +mv:3:73 +ml:17:-4 +mt:35:14 +mh:9:168 +mq:14:-61 +mr:20:-12 +mu:-20:57 +yt:-12:45 +mx:23:-102 +fm:6:158 +mc:43:7 +mn:46:105 +ms:16:-62 +ma:32:-5 +mz:-18:35 +na:-22:17 +nr:-0:166 +np:28:84 +nl:52:5 +an:12:-68 +nc:-21:165 +nz:-41:174 +ni:13:-85 +ne:16:8 +ng:10:8 +nu:-19:-169 +nf:-29:167 +mp:15:145 +no:62:10 +om:21:57 +pk:30:70 +pw:7:134 +pa:9:-80 +pg:-6:147 +py:-23:-58 +pe:-10:-76 +ph:13:122 +pn:-25:-130 +pl:52:20 +pt:39:-8 +pr:18:-66 +qa:25:51 +re:-21:55 +ro:46:25 +ru:60:100 +rw:-2:30 +sh:-15:-5 +kn:17:-62 +lc:13:-60 +pm:46:-56 +vc:13:-61 +ws:-13:-172 +sm:43:12 +st:1:7 +sa:25:45 +sn:14:-14 +sc:-4:55 +sl:8:-11 +sg:1:103 +sk:48:19 +si:46:15 +sb:-8:159 +so:10:49 +za:-29:24 +gs:-54:-37 +es:40:-4 +lk:7:81 +sd:15:30 +sr:4:-56 +sj:78:20 +sz:-26:31 +se:62:15 +ch:47:8 +sy:35:38 +tj:39:71 +tz:-6:35 +th:15:100 +tg:8:1 +tk:-9:-172 +to:-20:-175 +tt:11:-61 +tn:34:9 +tr:39:35 +tm:40:60 +tc:21:-71 +tv:-8:178 +ug:1:32 +ua:49:32 +ae:24:54 +gb:54:-2 +us:38:-97 +uy:-33:-56 +uz:41:64 +vu:-16:167 +ve:8:-66 +vn:16:106 +vi:18:-64 +wf:-13:-176 +eh:24:-13 +ye:15:48 +yu:44:21 +zm:-15:30 +zw:-20:30 +tw:23:121 |