16 -> 8 -> sigmoid), trained offline and embedded as a zlib+base64 blob (PHP gzuncompress reads zlib). It runs ONLY on a post and ONLY AFTER the rate limit, so it can never be spun up to burn CPU, and it FAILS OPEN: a missing or corrupt blob scores 0.0 and blocks nothing. The threshold is deliberately high (0.95) with very generous margins, so only blatant scam / incitement trips it, never an ordinary job or resume. The blob is FROZEN for mirror byte-parity; improve it later through the mirror-update path, never by hand-editing this line. */ define('NSW_MLP_THRESHOLD',0.95); define('NSW_MLP_BLOB','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'); function nsw_mlp_tokens($text){$text=function_exists('mb_substr')?mb_substr((string)$text,0,8000,'UTF-8'):substr((string)$text,0,8000);/* bag-of-words over a ~240-word vocab: capping the scanned text bounds the work and changes no verdict */$t=function_exists('mb_strtolower')?mb_strtolower($text,'UTF-8'):strtolower($text);return preg_split('/[^\p{L}\p{N}]+/u',$t,-1,PREG_SPLIT_NO_EMPTY)?:[];} function nsw_nn_score_mlp($text){static$m=null,$loaded=false;if(!$loaded){$loaded=true;$j=@gzuncompress(base64_decode(NSW_MLP_BLOB));if($j!==false){$d=json_decode($j,true);if(is_array($d)&&isset($d['vocab'],$d['w1'],$d['b1'],$d['w2'],$d['b2'],$d['w3'],$d['b3']))$m=$d;}}if($m===null)return 0.0;$vocab=$m['vocab'];$H1=count($m['b1']);$H2=count($m['b2']);$x=[];foreach(nsw_mlp_tokens($text)as$w){if(isset($vocab[$w]))$x[$vocab[$w]]=1.0;}$h1=$m['b1'];foreach($x as$j=>$xv){$row=$m['w1'][$j];for($i=0;$i<$H1;$i++)$h1[$i]+=$xv*$row[$i];}for($i=0;$i<$H1;$i++)if($h1[$i]<0)$h1[$i]=0.0;$h2=$m['b2'];for($i=0;$i<$H1;$i++){$hi=$h1[$i];if($hi==0.0)continue;$row=$m['w2'][$i];for($k=0;$k<$H2;$k++)$h2[$k]+=$hi*$row[$k];}for($k=0;$k<$H2;$k++)if($h2[$k]<0)$h2[$k]=0.0;$z=$m['b3'][0];for($k=0;$k<$H2;$k++)$z+=$h2[$k]*$m['w3'][$k];return 1.0/(1.0+exp(-$z));} /* ── DATA DIR & PATHS (one base dir; .htaccess-guarded) ── */ function nsw_base(){static$b=null;if($b!==null)return$b;$c=[];if(getenv('NSW_DATA_DIR'))$c[]=rtrim(getenv('NSW_DATA_DIR'),"/\\");$c[]='/var/lib/nosignup/work';$c[]=__DIR__.DIRECTORY_SEPARATOR.'.nsw-data';$c[]=rtrim(sys_get_temp_dir(),"/\\").DIRECTORY_SEPARATOR.'nsw-data';/* sys_get_temp_dir() = the universal NO-PERMISSION fallback: PHP guarantees a writable temp on every host */foreach($c as$d){if($d===''||(!is_dir($d)&&!@mkdir($d,0755,true)&&!is_dir($d)))continue;$h=$d.DIRECTORY_SEPARATOR.'.htaccess';if((file_exists($h)&&is_writable($d))||@file_put_contents($h,"Require all denied\nDeny from all\n")!==false){$b=$d;return$b;}/* the .htaccess write doubles as the real writability probe */}$b=sys_get_temp_dir();return$b;/* last-ditch: raw temp, which always exists */} function nsw_shards(){return nsw_base().DIRECTORY_SEPARATOR.'shards';} /* PUBLIC STATIC SURFACE — write this node's listings to ONE static file (nsw.txt) in the webroot, plus a one-line CORS .htaccess. WHY: a bot-walled free host (InfinityFree's aes.js) blocks our DYNAMIC ?api= endpoint for outside browsers but waves STATIC files straight through — so the static dump is how a walled node stays readable by the swarm. The .htaccess flags the dump public (a static file can't set its own header); it is wrapped in so a host WITHOUT mod_headers ignores it instead of 500-ing. Both files are PUBLIC by design (the listings) and regenerable — delete them and the next post/visit rebuilds them. */ function nsw_write_static(){$dir=__DIR__;$jobs=array();$res=array(); foreach(glob(nsw_shards().DIRECTORY_SEPARATOR.'*'.DIRECTORY_SEPARATOR.'*.job.txt')?:array() as$f){$c=trim((string)@file_get_contents($f));if($c!=='')$jobs[]=$c;} foreach(glob(nsw_shards().DIRECTORY_SEPARATOR.'*'.DIRECTORY_SEPARATOR.'*.resume.txt')?:array() as$f){$c=trim((string)@file_get_contents($f));if($c!=='')$res[]=$c;} @file_put_contents($dir.DIRECTORY_SEPARATOR.'nsw.txt','{"jobs":['.implode(',',$jobs).'],"resumes":['.implode(',',$res).'],"ts":'.time().'}',LOCK_EX); $ht=$dir.DIRECTORY_SEPARATOR.'.htaccess';$cur=is_file($ht)?(string)@file_get_contents($ht):''; if(strpos($cur,'# nsw-cors')===false)@file_put_contents($ht,$cur."\n# nsw-cors (lets any browser read the PUBLIC static dump cross-origin; a static file can't set its own header)\n\n\nHeader set Access-Control-Allow-Origin \"*\"\n\n\n",LOCK_EX);} function nsw_static_tick(){$f=__DIR__.DIRECTORY_SEPARATOR.'nsw.txt';if(!is_file($f)||(time()-(int)@filemtime($f))>30)nsw_write_static();}/* throttled: rebuild at most every 30s on a normal page load */ function nsw_ratedir(){if(DIRECTORY_SEPARATOR==='/'&&is_dir('/dev/shm')&&is_writable('/dev/shm')){$d='/dev/shm/nosignup_work_ip';if((is_dir($d)||@mkdir($d,0700,true))&&is_writable($d))return$d;}return nsw_base().DIRECTORY_SEPARATOR.'ip_posts';} /* ── REQUEST HELPERS (json out · parity hash · sanitize · tiles) ── */ function nsw_json_out($d,$c=200){http_response_code($c);header('Content-Type: application/json; charset=utf-8');header('X-NSW-Backend: file-shard');header('X-NSW-Data-Dir: '.nsw_base());echo json_encode($d);exit;} /* PARITY hash for the mirror-trust check — hashes this file NORMALIZED: strip a UTF-8 BOM, fold CRLF/CR → LF, drop trailing whitespace per line, collapse to exactly one final newline. So behaviour-neutral DEPLOY artifacts (a stray trailing newline, CRLF from a text-mode upload, a BOM) NEVER break parity between nodes running identical code — only a real code change does (you can't hide behaviour in whitespace). A node must normalize+hash a PEER'S fetched ?src=1 bytes ITSELF and compare to its own nsw_norm_hash(); never trust the peer's self-reported header. */ function nsw_norm_hash(){$s=(string)@file_get_contents(__FILE__);if(substr($s,0,3)==="\xEF\xBB\xBF")$s=substr($s,3);$s=str_replace(["\r\n","\r"],"\n",$s);$s=preg_replace('/[ \t]+\n/',"\n",$s);$s=rtrim($s,"\n")."\n";return hash('sha256',$s);} /* sanitize for STORAGE: trim + UTF-8-safe length cap only — stored RAW. json_encode keeps the dump valid JSON, and EVERY client render path MUST esc() (the browser is the trust boundary, the same rule the mirror layer already relies on). So we never double-encode, and never lose "<3" / "< $20" / apostrophes the way strip_tags+htmlspecialchars did. */ function nsw_san($s,$m=2000){$s=trim((string)($s??''));return function_exists('mb_substr')?mb_substr($s,0,$m,'UTF-8'):substr($s,0,$m);} function nsw_tile_ok($t){return$t&&preg_match('/^-?\d{1,3}(?:\.5)?_-?\d{1,3}(?:\.5)?$/',$t);} /* CANONICAL 0.5° CELL STRING — every node (and the JS in fmtHalf) MUST format a half-degree value identically or shard dir names / cross-node dedup drift: whole → "40", half → "40.5", "-73.5". */ function nsw_half($v){$v=floor((float)$v*2)/2;return $v==(int)$v?(string)(int)$v:(string)$v;} /* Cells are 0.5° (~55.5km). The slider notch (1-7) is in DEGREES (~111km each), so one notch = TWO sub-tiles: expand ±2·notch cells, stepping 0.5°. (4·notch+1)² cells — cheap is_dir() stats. */ function nsw_tiles($tile,$r){$p=explode('_',$tile);$lat=(float)$p[0];$lon=(float)$p[1];$n=2*(int)$r;$out=[];for($dy=-$n;$dy<=$n;$dy++)for($dx=-$n;$dx<=$n;$dx++)$out[]=nsw_half($lat+$dy*0.5).'_'.nsw_half($lon+$dx*0.5);return$out;} /* ── RATE LIMIT (per browser-id, capped per IP) ── */ /* per-IP limiter keyed by a client browser-id ($uid). ONE file per IP (md5(ip).txt, JSON inside) holding {jobs:{uid:ts,...},resumes:{uid:ts,...}}. Two rules per type per NSW_RATE_WINDOW: a uid may post once (reason 'soon'); an IP may present at most NSW_MAX_IDS_PER_IP distinct uids (reason 'busy'). Records on submit. Returns ['wait'=>0] when allowed, else ['wait'=>seconds,'reason'=>...]. */ function nsw_rate_check($ip,$type,$uid){$dir=nsw_ratedir();if(!is_dir($dir))@mkdir($dir,0700,true);$now=time();if(mt_rand(1,20)===1)foreach(glob($dir.DIRECTORY_SEPARATOR.'*.txt')?:[]as$g)if(@filemtime($g)<$now-NSW_RATE_WINDOW)@unlink($g);/* GC: a rate file untouched for one full window is stale */$f=$dir.DIRECTORY_SEPARATOR.md5($ip).'.txt';$all=is_file($f)?(json_decode(@file_get_contents($f),true)?:[]):[];if(!is_array($all))$all=[];$m=(isset($all[$type])&&is_array($all[$type]))?$all[$type]:[];foreach($m as$k=>$ts){if(!is_int($ts)||$now-$ts>=NSW_RATE_WINDOW)unset($m[$k]);}/* drop ids whose 5-min window lapsed */$r=['wait'=>0,'reason'=>''];if(isset($m[$uid]))$r=['wait'=>max(1,($m[$uid]+NSW_RATE_WINDOW)-$now),'reason'=>'soon'];/* this browser-id already posted this type */elseif(count($m)>=NSW_MAX_IDS_PER_IP)$r=['wait'=>max(1,(min($m)+NSW_RATE_WINDOW)-$now),'reason'=>'busy'];/* too many distinct ids from this IP */else{$m[$uid]=$now;$all[$type]=$m;@file_put_contents($f,json_encode($all),LOCK_EX);}/* persist ONLY when recording — a blocked hit changes nothing worth writing (no write-amplification on a flood) */return $r;} /* ── ADAPTIVE BROWSE THROTTLE ── a browse globs a whole region, so cap it per IP per window and SCALE the cap to this mirror's spare power: idle box → lenient (NSW_BROWSE_MAX); loaded box → fewer (down to NSW_BROWSE_MIN), so users wait LONGER exactly when we're short on power. Self-protecting per mirror — load spreads across the network, so we throttle on THIS box's CPU, not on user count. sys_getloadavg is POSIX-only → where it's unavailable (e.g. Windows) we fall back to the lenient cap. Same per-IP file. */ function nsw_load_factor(){if(!function_exists('sys_getloadavg'))return -1.0;$l=@sys_getloadavg();if(!is_array($l)||!isset($l[0]))return -1.0;$n=1;$ci=@file_get_contents('/proc/cpuinfo');if($ci!==false){$c=substr_count($ci,'processor');if($c>0)$n=$c;}return $l[0]/$n;/* 1-min load per core: 0 idle, ~1 fully busy */} function nsw_browse_check($ip){$dir=nsw_ratedir();if(!is_dir($dir))@mkdir($dir,0700,true);$now=time();if(mt_rand(1,30)===1)foreach(glob($dir.DIRECTORY_SEPARATOR.'*.txt')?:[]as$g)if(@filemtime($g)<$now-NSW_RATE_WINDOW)@unlink($g);$f=$dir.DIRECTORY_SEPARATOR.md5($ip).'.txt';$all=is_file($f)?(json_decode(@file_get_contents($f),true)?:[]):[];if(!is_array($all))$all=[];$b=array_values(array_filter((isset($all['browse'])&&is_array($all['browse']))?$all['browse']:[],fn($t)=>is_int($t)&&$now-$t=$cap){sort($b);$wait=($b[0]+NSW_RATE_WINDOW)-$now;return $wait>0?$wait:1;}$b[]=$now;$all['browse']=$b;@file_put_contents($f,json_encode($all),LOCK_EX);return 0;} /* ── STORAGE (ids · region shards) ── */ function nsw_new_id($ip){return time().'_'.sprintf('%08x',crc32($ip.microtime()));} function nsw_mkdir($p){if(!is_dir($p))@mkdir($p,0755,true);return is_dir($p);} /* one file per posting, type IN the name: shards/{tile}/{id}.job.txt | {id}.resume.txt so a browse can pull the right type by filename glob without reading every file. */ function nsw_store($type,$tile,$id,$data){$s=rtrim($type,'s');$p=nsw_shards()."/$tile/";if(!nsw_mkdir($p))return false;$j=json_encode($data,JSON_INVALID_UTF8_SUBSTITUTE);/* malformed bytes → U+FFFD instead of false: a record must never silently store empty and vanish */if($j===false)return false;$ok=@file_put_contents($p.$id.'.u0.d0.'.$s.'.txt',$j,LOCK_EX)!==false;if($ok&&!empty($data['remote'])){$a=nsw_shards().'/'.NSW_REMOTE_TILE.'/';if(nsw_mkdir($a))@file_put_contents($a.$id.'.u0.d0.'.$s.'.txt',$j,LOCK_EX);}return$ok;} /* ── ACCESS LOG (append-only KYC) ── */ function nsw_logdir(){$d=nsw_base().DIRECTORY_SEPARATOR.'kyc';if(!is_dir($d))@mkdir($d,0700,true);return$d;} /* ── COMMUNITY VOTES (downvotes remove a post — up/down counts live IN the shard filename; a vote is an atomic rename; per-IP-per-post dedup in the RAM rate file) ── */ function nsw_downvote_threshold(){$dir=nsw_logdir();$day=date('Y-m-d');$b=0;foreach(glob($dir.DIRECTORY_SEPARATOR.$day.'*.log.txt')?:[]as$f)$b+=(int)@filesize($f);return max(NSW_DOWNVOTE_MIN,(int)floor($b/NSW_DOWNVOTE_SCALE));}/* scales with the day's activity via KYC-log bytes (a filesize stat, no read) */ function nsw_vote_check($ip){$dir=nsw_ratedir();if(!is_dir($dir))@mkdir($dir,0700,true);$now=time();$f=$dir.DIRECTORY_SEPARATOR.md5($ip).'.txt';$all=is_file($f)?(json_decode(@file_get_contents($f),true)?:[]):[];if(!is_array($all))$all=[];$b=array_values(array_filter((isset($all['vote'])&&is_array($all['vote']))?$all['vote']:[],fn($t)=>is_int($t)&&$now-$t=NSW_VOTE_MAX)return false;$b[]=$now;$all['vote']=$b;@file_put_contents($f,json_encode($all),LOCK_EX);return true;} /* ── MIRROR GOSSIP ── a small, EPHEMERAL set of peer URLs kept in the /dev/shm-preferred rate dir (RAM, forgettable; re-learned from peers). A sample rides every browse dump and the ?api=mirror exchange, so mirror lists spread virulently with NO persistent file and NO outbound call from the web SAPI. Trust is contained by design: only ESC()'d listing DATA ever crosses a mirror boundary, never code. */ function nsw_mirrorfile(){return nsw_ratedir().DIRECTORY_SEPARATOR.'mirrors.txt';} function nsw_mirror_ok($u){$u=trim((string)$u);if($u==='')return null;if(!preg_match('#^https?://#i',$u))$u='https://'.$u;$u=rtrim($u,'/');if(strlen($u)>200)return null;$h=parse_url($u,PHP_URL_HOST);if(!$h||strpos($h,'.')===false)return null;if(preg_match('/^(localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|0\.|169\.254\.|::1)/i',$h))return null;return$u;} function nsw_mirrors_read(){$f=nsw_mirrorfile();if(!is_file($f))return[];$o=[];$now=time();foreach(file($f,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)?:[]as$l){$p=explode("\t",$l);$u=$p[0]??'';$t=(int)($p[1]??0);if($u!==''&&($t===0||$now-$t64)$cur=array_slice($cur,-64,null,true);$out='';foreach($cur as$u=>$t)$out.=$u."\t".$t."\n";@file_put_contents(nsw_mirrorfile(),$out,LOCK_EX);} function nsw_mirrors_sample($n){$u=array_keys(nsw_mirrors_read());if(!$u)return[];shuffle($u);return array_slice($u,0,$n);} /* append-only KYC/access log — ONE json line per post/browse/src; new dated file past 50KB. */ function nsw_log($act,$loc){$dir=nsw_logdir();$now=time();if(mt_rand(1,50)===1)foreach(glob($dir.DIRECTORY_SEPARATOR.'*.log.txt')?:[]as$g)if(@filemtime($g)<$now-NSW_EXPIRY_SEC)@unlink($g);/* interactions are deleted after 32 days */$day=date('Y-m-d');$f=$dir.DIRECTORY_SEPARATOR.$day.'.log.txt';if(is_file($f)&&@filesize($f)>=51200){$n=2;do{$f=$dir.DIRECTORY_SEPARATOR.$day.'_'.$n.'.log.txt';$n++;}while(is_file($f)&&@filesize($f)>=51200);}$line=json_encode(['ts'=>time(),'ip'=>$_SERVER['REMOTE_ADDR']??'','xff'=>$_SERVER['HTTP_X_FORWARDED_FOR']??'','ua'=>substr($_SERVER['HTTP_USER_AGENT']??'',0,300),'lang'=>$_SERVER['HTTP_ACCEPT_LANGUAGE']??'','referer'=>substr($_SERVER['HTTP_REFERER']??'',0,300),'act'=>$act,'loc'=>$loc])."\n";@file_put_contents($f,$line,FILE_APPEND|LOCK_EX);} /* ── REGION DUMP (dumb switchboard) ── */ /* DUMB SWITCHBOARD: gather the region's raw files and hand them over untouched. NO server-side filtering, ranking, or re-encoding — the browser does ALL of that. We only (1) pick files by region folder + type-in-name, (2) dedup by id (from the filename), (3) lazy-delete >32d files, (4) order newest-first by id (id starts with the unix post-time). Returns raw JSON strings. */ function nsw_listings($type,$tile,$radius,$with_remote){ $s=rtrim($type,'s');$now=time();$byId=[];$cp=explode('_',$tile);$clat=(float)$cp[0];$clon=(float)$cp[1]; /* (1) everything inside the CHOSEN radius (non-remote) */ foreach(nsw_tiles($tile,$radius) as$t){$dir=nsw_shards()."/$t/";if(!is_dir($dir))continue; foreach(glob($dir.'*.'.$s.'.txt')?:[]as$f){ if(@filemtime($f)<$now-NSW_EXPIRY_SEC){@unlink($f);continue;} $b=basename($f);$dot=strpos($b,'.');$id=$dot!==false?substr($b,0,$dot):$b; if(!isset($byId[$id]))$byId[$id]=$f;}} /* (2) sparse region → expand with NO distance bound to back-fill the nearest 10 ("best we've got"). Scan only POPULATED tiles (a dir exists only where someone posted), nearest-first, read until 10. */ if(count($byId)<10){$dirs=[]; foreach(glob(nsw_shards().'/*',GLOB_ONLYDIR)?:[]as$d){$n=basename($d); if($n===NSW_REMOTE_TILE||!preg_match('/^-?\d+(?:\.5)?_-?\d+(?:\.5)?$/',$n))continue; $np=explode('_',$n);$tl=(float)$np[0];$tn=(float)$np[1];$ch=max(abs($tl-$clat),abs($tn-$clon)); if($ch<=$radius)continue;$dirs[]=[$ch,$d];} usort($dirs,fn($a,$b)=>$a[0]<=>$b[0]); foreach($dirs as$dd){if(count($byId)>=10)break; foreach(glob($dd[1].'/*.'.$s.'.txt')?:[]as$f){ if(@filemtime($f)<$now-NSW_EXPIRY_SEC){@unlink($f);continue;} $b=basename($f);$dot=strpos($b,'.');$id=$dot!==false?substr($b,0,$dot):$b; if(!isset($byId[$id])){$byId[$id]=$f;if(count($byId)>=10)break;}}}} /* (3) remote (location-independent) listings — always included when asked, never counted toward the 10 */ if($with_remote){$dir=nsw_shards().'/'.NSW_REMOTE_TILE.'/';if(is_dir($dir)) foreach(glob($dir.'*.'.$s.'.txt')?:[]as$f){ if(@filemtime($f)<$now-NSW_EXPIRY_SEC){@unlink($f);continue;} $b=basename($f);$dot=strpos($b,'.');$id=$dot!==false?substr($b,0,$dot):$b; if(!isset($byId[$id]))$byId[$id]=$f;}} krsort($byId); // id = "_" → newest first; the browser sorts by distance $parts=[];foreach($byId as$f){$c=trim((string)@file_get_contents($f));if($c!==''&&$c[0]==='{'&&substr($c,-1)==='}')$parts[]=$c;} return $parts;} /* ── ROUTER (?api=jobs|resumes|post_job|post_resume · ?src=1) ── */ /* ── OPTIONAL JOB SEEDER ── runs on FREE configureless hosts: it PIGGYBACKS on web requests (register_shutdown_function → nsw_seed_tick), so NO cron and NO CLI are needed (CLI `php index.php seed` still works). Reads public job pages with a built-in schema.org JobPosting reader (pure PHP, NO AI/Ollama). Outbound via curl → file_get_contents → fsockopen (all blocked = the node stays a pure mirror). Only while IDLE, ONE bounded step at a time, file_exists dedup. JOBS ONLY; stores title + short EXCERPT + apply-link. DEMAND-DRIVEN & SELF-CONFIGURING: terms = seed/terms.txt ∪ demand.txt (what users searched, via ?api=demand) → no users = no crawl. Search engine defaults to keyless DuckDuckGo HTML (override: seed.conf `search=`); a job's tile comes from its OWN jobLocation.geo (else _remote) — NO templates/locs files. Optional seed.conf keys: search, idle_secs, max_load, odds, links_per, ua, enabled. All config is EXTERNAL, so index.php stays byte-identical across mirrors. */ function nsw_seed_dir(){$d=nsw_base().DIRECTORY_SEPARATOR.'seed';if(!is_dir($d))@mkdir($d,0700,true);return$d;}/* no own .htaccess — the data-dir root deny-all already covers it recursively (Apache) */ function nsw_seed_lines($f){$p=nsw_seed_dir().DIRECTORY_SEPARATOR.$f;if(!is_file($p))return[];$o=[];foreach(file($p,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)?:[] as$l){$l=trim($l);if($l!==''&&$l[0]!=='#')$o[]=$l;}return$o;} function nsw_seed_conf($k,$d){foreach(nsw_seed_lines('seed.conf') as$l){$p=explode('=',$l,2);if(count($p)===2&&trim($p[0])===$k)return trim($p[1]);}return$d;} function nsw_seed_busy(){$stem=nsw_logdir().DIRECTORY_SEPARATOR.date('Y-m-d');$n=0;foreach(glob($stem.'*.log.txt')?:[] as$f){$m=@filemtime($f);if($m>$n)$n=$m;}if($n&&(time()-$n)<(int)nsw_seed_conf('idle_secs',45))return true;$lf=nsw_load_factor();return($lf>=0&&$lf>(float)nsw_seed_conf('max_load',0.75));} /* dependence-less fetch: curl → allow_url_fopen → raw fsockopen. If ALL outbound is blocked → null (this host can't crawl; it stays a pure mirror — the one hard floor no code can fix). */ function nsw_seed_get($url,$ua){ if(function_exists('curl_init')){$ch=curl_init($url);curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_FOLLOWLOCATION=>true,CURLOPT_MAXREDIRS=>4,CURLOPT_TIMEOUT=>12,CURLOPT_USERAGENT=>$ua,CURLOPT_ENCODING=>'']);$b=curl_exec($ch);$c=(int)curl_getinfo($ch,CURLINFO_HTTP_CODE);curl_close($ch);if($b!==false&&$c<400)return substr($b,0,600000);} if(ini_get('allow_url_fopen')){$ctx=stream_context_create(['http'=>['method'=>'GET','header'=>"User-Agent: $ua\r\nAccept-Encoding: identity\r\n",'timeout'=>12,'follow_location'=>1,'max_redirects'=>4,'ignore_errors'=>true],'ssl'=>['verify_peer'=>false,'verify_peer_name'=>false]]);$b=@file_get_contents($url,false,$ctx);if($b!==false&&$b!=='')return substr($b,0,600000);} return nsw_seed_sock($url,$ua); } function nsw_seed_sock($url,$ua){if(!function_exists('fsockopen'))return null;$p=parse_url($url);if(!$p||!isset($p['host']))return null;$host=$p['host'];$https=(($p['scheme']??'http')==='https');$port=$p['port']??($https?443:80);$path=($p['path']??'/').(isset($p['query'])?'?'.$p['query']:'');$fp=@fsockopen(($https?'ssl://':'').$host,$port,$e,$es,12);if(!$fp)return null;@stream_set_timeout($fp,12);@fwrite($fp,"GET $path HTTP/1.0\r\nHost: $host\r\nUser-Agent: $ua\r\nAccept-Encoding: identity\r\nConnection: close\r\n\r\n");$r='';while(!feof($fp)){$r.=fread($fp,8192);if(strlen($r)>1000000)break;}fclose($fp);$pos=strpos($r,"\r\n\r\n");if($pos===false)return null;if(preg_match('#^HTTP/\d\.\d\s+(\d+)#',$r,$m)&&(int)$m[1]>=400)return null;return substr($r,$pos+4,600000);} function nsw_seed_robots($url,$ua){static$c=[];$p=parse_url($url);if(!$p||!isset($p['scheme'],$p['host']))return false;$host=$p['scheme'].'://'.$p['host'];$path=$p['path']??'/';if(!array_key_exists($host,$c)){$rb=nsw_seed_get($host.'/robots.txt',$ua);$dis=[];if($rb!==null){$apply=false;foreach(preg_split('/\r?\n/',$rb) as$ln){$ln=trim($ln);if($ln===''||$ln[0]==='#')continue;$kv=explode(':',$ln,2);if(count($kv)<2)continue;$k=strtolower(trim($kv[0]));$v=trim($kv[1]);if($k==='user-agent')$apply=($v==='*');elseif($k==='disallow'&&$apply&&$v!=='')$dis[]=$v;}}$c[$host]=$dis;}foreach($c[$host] as$d)if(strpos($path,$d)===0)return false;return true;} function nsw_seed_absurl($h,$base){if(preg_match('#^https?://#i',$h))return$h;$p=parse_url($base);if(!$p||!isset($p['scheme'],$p['host']))return null;$r=$p['scheme'].'://'.$p['host'].(isset($p['port'])?':'.$p['port']:'');if(substr($h,0,2)==='//')return$p['scheme'].':'.$h;if($h!==''&&$h[0]==='/')return$r.$h;return$r.'/'.ltrim($h,'/');} function nsw_seed_links($html,$base){if(!preg_match_all('~]*href=([\'"])([^\'"#\s]+)~i',$html,$m))return[];$o=[];foreach($m[2] as$h){$u=nsw_seed_absurl(html_entity_decode($h,ENT_QUOTES,'UTF-8'),$base);if($u&&preg_match('/[?&]uddg=([^&]+)/',$u,$dm))$u=urldecode($dm[1]);/* DuckDuckGo HTML wraps results in /l/?uddg= — unwrap it */if($u&&preg_match('#^https?://#i',$u))$o[$u]=1;}return array_keys($o);} function nsw_seed_jsonld($html){if(!preg_match_all('#]*type=[\'"]application/ld\+json[\'"][^>]*>(.*?)#is',$html,$m))return[];$out=[];foreach($m[1] as$blob){$d=json_decode(trim($blob),true);if(!is_array($d))continue;$items=isset($d[0])?$d:((isset($d['@graph'])&&is_array($d['@graph']))?$d['@graph']:[$d]);foreach($items as$it)if(is_array($it))$out[]=$it;}return$out;} function nsw_seed_category($t){$t=' '.strtolower($t).' ';$map=['construction_trades'=>'carpenter|plumber|electrician|welder|mason|roofer|hvac|construction|labou?r|trades?','healthcare'=>'nurse|caregiver|medical|dental|therapist|healthcare|pharmac|clinic|hospital','engineering_technology'=>'engineer|developer|software|programmer|technician|devops|sysadmin|data scien','education_training'=>'teacher|tutor|instructor|professor|educat|trainer','logistics_transportation'=>'driver|warehouse|logistic|delivery|courier|forklift|truck|shipping','marketing_sales'=>'sales|marketing|advertis|retail|cashier','business_finance'=>'account|finance|bookkeep|analyst|banker','administration'=>'admin|assistant|clerk|reception|secretary','legal_government'=>'lawyer|legal|paralegal|attorney|government','arts'=>'artist|music|photograph|design|video|actor|writer'];foreach($map as$c=>$re)if(preg_match('#'.$re.'#',$t))return$c;return'miscellaneous';} function nsw_seed_have($hex){return(bool)glob(nsw_shards().DIRECTORY_SEPARATOR.'*'.DIRECTORY_SEPARATOR.'*_'.$hex.'*.job.txt');} function nsw_seed_clamp($s,$n){$s=trim((string)$s);return function_exists('mb_substr')?mb_substr($s,0,$n,'UTF-8'):substr($s,0,$n);} function nsw_seed_tile($loc,$remote){return($remote||$loc[1]===null||$loc[2]===null)?NSW_REMOTE_TILE:(nsw_half($loc[1]).'_'.nsw_half($loc[2]));} function nsw_seed_put($f,$url,$loc,$remote){$cats=['business_finance','administration','marketing_sales','engineering_technology','healthcare','education_training','construction_trades','arts','logistics_transportation','legal_government','miscellaneous'];$pts=['remote_bounty','remote_hourly','inperson_bounty','inperson_hourly','no_pay',''];$hex=substr(sha1($url),0,8);if(nsw_seed_have($hex))return'dup';$tile=nsw_seed_tile($loc,$remote);$id=((!empty($f['posted'])&&$f['posted']>0)?(int)$f['posted']:time()).'_'.$hex;/* id timestamp = the job's datePosted when known → SAME id on every node → cross-node dedup */$desc="\xF0\x9F\xA4\x96 Auto-imported \xC2\xB7 Apply: $url\n\n".nsw_seed_clamp($f['description']??'',1900);$rec=['id'=>$id,'tile'=>$tile,'title'=>nsw_seed_clamp($f['title']??'',120),'category'=>in_array($f['category']??'',$cats,true)?$f['category']:'miscellaneous','pay_type'=>in_array($f['pay_type']??'',$pts,true)?$f['pay_type']:'','pay_amount'=>nsw_seed_clamp($f['pay_amount']??'',80),'description'=>nsw_seed_clamp($desc,2000),'contact_email'=>'','contact_phone'=>'','remote'=>(bool)$remote,'timestamp'=>time()];return nsw_store('job',$tile,$id,$rec)?'wrote':'err';} function nsw_seed_extract($html){foreach(nsw_seed_jsonld($html) as$it){$ty=$it['@type']??'';if(is_array($ty))$ty=implode(',',$ty);if(stripos((string)$ty,'JobPosting')===false)continue;$title=trim((string)($it['title']??''));$desc=trim(preg_replace('/\s+/',' ',html_entity_decode(strip_tags((string)($it['description']??'')),ENT_QUOTES|ENT_HTML5,'UTF-8')));if($title===''||$desc==='')continue;$remote=stripos((string)($it['jobLocationType']??''),'TELECOMMUTE')!==false;$amt='';$hourly=false;$bs=$it['baseSalary']??null;if(is_array($bs)){$cur=(string)($bs['currency']??'');$v=$bs['value']??null;if(is_array($v)){$val=$v['value']??($v['minValue']??'');$unit=(string)($v['unitText']??'');}else{$val=$v;$unit='';}if($val!==null&&$val!==''){$amt=trim(($cur?$cur.' ':'').$val.($unit?' / '.strtolower($unit):''));$hourly=stripos($unit,'HOUR')!==false;}}$pt=$amt===''?'':(($remote?'remote_':'inperson_').($hourly?'hourly':'bounty'));$ex=((function_exists('mb_strlen')?mb_strlen($desc,'UTF-8'):strlen($desc))>200)?nsw_seed_clamp($desc,200)."\xE2\x80\xA6":$desc;/* store only a short EXCERPT + apply link, never the full text (copyright/ToS) */$posted=strtotime((string)($it['datePosted']??''));$lat=$lon=null;$jl=$it['jobLocation']??null;if(is_array($jl)){$j0=isset($jl[0])?$jl[0]:$jl;if(is_array($j0)&&isset($j0['geo'])&&is_array($j0['geo'])){if(is_numeric($j0['geo']['latitude']??null))$lat=(float)$j0['geo']['latitude'];if(is_numeric($j0['geo']['longitude']??null))$lon=(float)$j0['geo']['longitude'];}}return['job'=>true,'title'=>$title,'description'=>$ex,'pay_type'=>$pt,'pay_amount'=>$amt,'category'=>nsw_seed_category($title.' '.$desc),'remote'=>$remote,'posted'=>($posted?:0),'lat'=>$lat,'lon'=>$lon];}return['job'=>false];} /* SELF-CONFIG: terms = base seed/terms.txt ∪ demand.txt (what users actually searched — demand-driven, so a node with no users crawls nothing). Search engine defaults to keyless DuckDuckGo HTML; no templates/locs needed — a job's tile comes from its OWN jobLocation.geo (else _remote). All seed/* files are OPTIONAL. */ function nsw_seed_inputs(){$terms=array_values(array_unique(array_merge(nsw_seed_lines('terms.txt'),nsw_seed_lines('demand.txt'))));return[$terms,nsw_seed_conf('search','https://html.duckduckgo.com/html/?q={q}'),nsw_seed_conf('ua','nsw-seed/1.0 (+nosignup.work; respectful job indexer)'),(int)nsw_seed_conf('links_per',12)];} function nsw_seed_enabled(){if(!function_exists('curl_init')&&!ini_get('allow_url_fopen')&&!function_exists('fsockopen'))return false;if(nsw_seed_conf('enabled','1')==='0')return false;list($terms)=nsw_seed_inputs();return!empty($terms);} function nsw_seed_step($deadline){list($terms,$search,$ua,$lp)=nsw_seed_inputs();if(!$terms)return;$q=$terms[(int)floor(time()/120)%count($terms)];/* which term to search is DERIVED FROM THE CLOCK (~1 per 2 min) — no cursor file, sweeps over time, forgettable */$surl=str_replace('{q}',rawurlencode($q.' jobs'),$search);$html=nsw_seed_get($surl,$ua);if($html===null)return;foreach(array_slice(nsw_seed_links($html,$surl),0,$lp) as$url){if(time()>=$deadline)break;$hex=substr(sha1($url),0,8);if(nsw_seed_have($hex))continue;if(!nsw_seed_robots($url,$ua))continue;$page=nsw_seed_get($url,$ua);if($page===null)continue;$f=nsw_seed_extract($page);if(!is_array($f)||empty($f['job'])||trim($f['title']??'')===''||trim($f['description']??'')==='')continue;$remote=!empty($f['remote'])||!isset($f['lat'])||$f['lat']===null||$f['lon']===null;nsw_seed_put($f,$url,['',$f['lat']??null,$f['lon']??null],$remote);}} function nsw_seed_tick(){if(mt_rand(1,max(1,(int)nsw_seed_conf('odds',12)))!==1)return;if(!nsw_seed_enabled())return;if(nsw_seed_busy())return;$fin=function_exists('fastcgi_finish_request');if($fin)@fastcgi_finish_request();@ignore_user_abort(true);@set_time_limit($fin?40:10);nsw_seed_step(time()+($fin?25:6));/* NO lock file: the idle-gate (kyc mtime) already serializes ticks, and the file_exists dedup makes a rare double-run harmless (just redundant fetches) */} function nsw_seed_run($selftest){if($selftest){fwrite(STDOUT,'selftest: '.nsw_seed_put(['title'=>'SELFTEST seeded carpenter','description'=>'Synthetic seeder self-test job — safe to ignore; it auto-expires.','category'=>'construction_trades','pay_type'=>'inperson_hourly','pay_amount'=>'$20/hr'],'https://selftest.local/job/'.microtime(true),['Test City',30,-97],false)."\n");return;}while(true){if(nsw_seed_busy()){sleep(3);continue;}if(!nsw_seed_enabled()){fwrite(STDERR,"seeder idle — no demand yet (no users have searched) and no seed/terms.txt; outbound: ".((function_exists('curl_init')||ini_get('allow_url_fopen')||function_exists('fsockopen'))?'ok':'BLOCKED')."\n");sleep(10);continue;}nsw_seed_step(time()+25);sleep(2);}} /* CLI entry — `php index.php seed` (or seed-selftest). DORMANT on the web (PHP_SAPI is never 'cli' there). */ if(PHP_SAPI==='cli'){$cmd=$argv[1]??'';if($cmd==='seed')nsw_seed_run(false);elseif($cmd==='seed-selftest')nsw_seed_run(true);else fwrite(STDERR,"nosignup.work seeder — usage: php index.php seed | seed-selftest\n");exit;} /* WEB PIGGYBACK (free configureless hosts): on a small fraction of WEB requests, if idle + enabled, do ONE bounded seed step AFTER the response (fastcgi_finish_request where available) — so the seeder runs with NO cron and NO CLI. Dormant until the node has demand (a user searched) or a seed/terms.txt. */ register_shutdown_function('nsw_seed_tick'); if(isset($_GET['api'])){ $api=$_GET['api']; if($api==='jobs'||$api==='resumes'){ $tile=$_GET['tile']??'';if(!nsw_tile_ok($tile))nsw_json_out(['error'=>'bad tile'],400); $radius=max(1,min(7,(int)($_GET['radius']??1)));$remote=!empty($_GET['remote'])&&$_GET['remote']!=='0'; $ip=$_SERVER['REMOTE_ADDR']??'0.0.0.0';$bw=nsw_browse_check($ip);if($bw>0)nsw_json_out(['error'=>'rate_limited','retry_after'=>$bw,'reason'=>'busy'],429);/* adaptive per-IP browse cap (scales with spare power) — shed BEFORE the region glob */ nsw_log('browse_'.$api,'tile='.$tile.' r='.$radius.' remote='.($remote?'1':'0')); $parts=nsw_listings($api,$tile,$radius,$remote); /* one efficient response: raw region files concatenated into a JSON array (no per-record re-encode) + gzip if the client supports it. The browser counts/sorts/filters it all. */ @ob_start('ob_gzhandler'); header('Content-Type: application/json; charset=utf-8');header('X-NSW-Backend: file-shard');header('Access-Control-Allow-Origin: *');/* public region dump — allow a browser on another node to read it cross-origin so it can mirror the network */ echo '{"total":'.count($parts).',"listings":['.implode(',',$parts).'],"mirrors":'.json_encode(nsw_mirrors_sample(6)).'}';exit;} if($api==='post_job'){ if($_SERVER['REQUEST_METHOD']!=='POST')nsw_json_out(['error'=>'POST only'],405); $ip=$_SERVER['REMOTE_ADDR']??'0.0.0.0'; $tile=$_POST['tile']??'';if(!nsw_tile_ok($tile))nsw_json_out(['error'=>'bad tile'],400); $cats=['business_finance','administration','marketing_sales','engineering_technology','healthcare','education_training','construction_trades','arts','logistics_transportation','legal_government','miscellaneous']; $pay_types=['remote_bounty','remote_hourly','inperson_bounty','inperson_hourly','no_pay']; $cat=in_array($_POST['category']??'',$cats,true)?$_POST['category']:''; $pay_type=in_array($_POST['pay_type']??'',$pay_types,true)?$_POST['pay_type']:''; $pay_amount=trim((string)($_POST['pay_amount']??'')); /* pay amount is required EXCEPT when the poster picked "No Pay" (volunteer/unpaid gigs) */ if(empty($_POST['title'])||empty($_POST['details'])||($pay_type!=='no_pay'&&$pay_amount==='')||(trim((string)($_POST['email']??''))===''&&trim((string)($_POST['phone']??''))==='')) nsw_json_out(['error'=>'missing required fields (title, details, a contact email or phone, and pay unless No Pay)'],400); $uid=preg_replace('/[^a-zA-Z0-9_-]/','',(string)($_POST['uid']??''));if(strlen($uid)<8||strlen($uid)>64)$uid='ip';/* no/garbage id => share one strict per-IP slot */ $rl=nsw_rate_check($ip,'jobs',$uid);if($rl['wait']>0)nsw_json_out(['error'=>'rate_limited','retry_after'=>$rl['wait'],'reason'=>$rl['reason']],429);/* AFTER validation (a typo mustn't burn a slot); per-id cooldown + per-IP id cap, trips on submit */ /* frozen spam/malice node — AFTER the rate limit so a flood can't spin the classifier; the slot is already spent, which is the point (processing spam must cost the spammer their turn) */ if(nsw_nn_score_mlp(($_POST['title']??'').' '.($_POST['details']??'').' '.($_POST['pay_amount']??'').' '.($_POST['category']??''))>=NSW_MLP_THRESHOLD){nsw_log('post_job_flagged','tile='.$tile);nsw_json_out(['error'=>'content_flagged'],422);} $id=nsw_new_id($ip);$remote=(!empty($_POST['remote'])&&$_POST['remote']!=='0')||strpos($pay_type,'remote')===0; $data=['id'=>$id,'tile'=>$tile,'title'=>nsw_san($_POST['title'],120),'category'=>$cat,'pay_type'=>$pay_type,'pay_amount'=>nsw_san($pay_amount,80),'description'=>nsw_san($_POST['details'],2000),'contact_email'=>nsw_san($_POST['email']??'',200),'contact_phone'=>nsw_san($_POST['phone']??'',40),'remote'=>$remote,'timestamp'=>time()]; if(!nsw_store('jobs',$tile,$id,$data))nsw_json_out(['error'=>'storage not writable'],500); nsw_log('post_job',"shards/$tile/$id.job.txt"); nsw_write_static();/* refresh the public static dump so a new post is immediately visible to outside browsers, even on a bot-walled host */ nsw_json_out(['ok'=>true,'id'=>$id]);} if($api==='post_resume'){ if($_SERVER['REQUEST_METHOD']!=='POST')nsw_json_out(['error'=>'POST only'],405); $ip=$_SERVER['REMOTE_ADDR']??'0.0.0.0'; $tile=$_POST['tile']??'';if(!nsw_tile_ok($tile))nsw_json_out(['error'=>'bad tile'],400); if(empty($_POST['name'])||empty($_POST['email'])||empty($_POST['experience']))nsw_json_out(['error'=>'missing required fields (name, email, experience)'],400); $uid=preg_replace('/[^a-zA-Z0-9_-]/','',(string)($_POST['uid']??''));if(strlen($uid)<8||strlen($uid)>64)$uid='ip';/* no/garbage id => share one strict per-IP slot */ $rl=nsw_rate_check($ip,'resumes',$uid);if($rl['wait']>0)nsw_json_out(['error'=>'rate_limited','retry_after'=>$rl['wait'],'reason'=>$rl['reason']],429);/* AFTER validation; per-id cooldown + per-IP id cap, trips on submit */ if(nsw_nn_score_mlp(($_POST['name']??'').' '.($_POST['experience']??'').' '.($_POST['wanted']??'').' '.($_POST['education']??'').' '.($_POST['resume_text']??''))>=NSW_MLP_THRESHOLD){nsw_log('post_resume_flagged','tile='.$tile);nsw_json_out(['error'=>'content_flagged'],422);} $id=nsw_new_id($ip);$remote=!empty($_POST['remote'])&&$_POST['remote']!=='0'; $data=['id'=>$id,'tile'=>$tile,'name'=>nsw_san($_POST['name'],120),'email'=>nsw_san($_POST['email'],200),'phone'=>nsw_san($_POST['phone']??'',40),'min_salary'=>nsw_san($_POST['min_salary']??'',80),'education'=>nsw_san($_POST['education']??'',300),'experience'=>nsw_san($_POST['experience'],8000),'wanted'=>nsw_san($_POST['wanted']??'',300),'resume_text'=>nsw_san($_POST['resume_text']??'',8000),'remote'=>$remote,'timestamp'=>time()]; if(!nsw_store('resumes',$tile,$id,$data))nsw_json_out(['error'=>'storage not writable'],500); nsw_log('post_resume',"shards/$tile/$id.resume.txt"); nsw_write_static();/* refresh the public static dump so a new post is immediately visible to outside browsers, even on a bot-walled host */ nsw_json_out(['ok'=>true,'id'=>$id]);} if($api==='capacity'){header('Access-Control-Allow-Origin: *');$x=@disk_free_space(nsw_base());nsw_json_out(['ok'=>true,'free'=>($x===false?null:(int)$x),'tiles'=>count(glob(nsw_shards().'/*',GLOB_ONLYDIR)?:[]),'parity'=>nsw_norm_hash()]);} /* DEMAND FEEDBACK — a browse keyword the user searched for. Recorded (deduped, capped, sanitized) into seed/demand.txt so the OPTIONAL seeder folds real demand into its search terms. Tiny local file write, no outbound calls, not logged (keeps the KYC log clean). Harmless if no seeder runs. */ if($api==='demand'){$q=trim(preg_replace('/\s+/',' ',preg_replace('/[\x00-\x1f<>]+/',' ',(string)($_GET['q']??''))));$ln=function_exists('mb_strlen')?mb_strlen($q,'UTF-8'):strlen($q);if($q!==''&&$ln>=2&&$ln<=40){$ql=function_exists('mb_strtolower')?mb_strtolower($q,'UTF-8'):strtolower($q);$df=nsw_seed_dir().DIRECTORY_SEPARATOR.'demand.txt';$ls=is_file($df)?(file($df,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)?:[]):[];$has=false;foreach($ls as$l){if((function_exists('mb_strtolower')?mb_strtolower(trim($l),'UTF-8'):strtolower(trim($l)))===$ql){$has=true;break;}}if(!$has){$ls[]=$q;if(count($ls)>300)$ls=array_slice($ls,-300);@file_put_contents($df,implode("\n",$ls)."\n",LOCK_EX);}}http_response_code(204);exit;} if($api==='mirror'){header('Access-Control-Allow-Origin: *');$m=$_POST['m']??($_GET['m']??'');nsw_mirrors_add(is_array($m)?$m:preg_split('/[\s,]+/',(string)$m));nsw_json_out(['ok'=>true,'mirrors'=>nsw_mirrors_sample(8)]);} if($api==='model'){header('Access-Control-Allow-Origin: *');header('Content-Type: application/json; charset=utf-8');$j=@gzuncompress(base64_decode(NSW_MLP_BLOB));echo($j!==false?$j:'null');exit;}/* the frozen spam MLP, inflated, so the BROWSER can run the same filter on mirror-merged listings */ if($api==='vote'){header('Access-Control-Allow-Origin: *');/* CORS: a browser routes a vote to the node that HOSTS the listing (its u/d count lives in THAT node's filename) */ if($_SERVER['REQUEST_METHOD']!=='POST')nsw_json_out(['error'=>'POST only'],405); $ip=$_SERVER['REMOTE_ADDR']??'0.0.0.0'; $id=preg_replace('/[^0-9a-f_]/','',(string)($_POST['id']??''));if(strlen($id)<10||strlen($id)>40)nsw_json_out(['error'=>'bad id'],400); $vdir=(($_POST['dir']??'')==='up')?1:((($_POST['dir']??'')==='down')?-1:0);if($vdir===0)nsw_json_out(['error'=>'bad dir'],400); $tile=$_POST['tile']??'';if(!nsw_tile_ok($tile))nsw_json_out(['error'=>'bad tile'],400); $stype=(($_POST['type']??'')==='resume')?'resume':((($_POST['type']??'')==='job')?'job':'');if($stype==='')nsw_json_out(['error'=>'bad type'],400); if(!nsw_vote_check($ip))nsw_json_out(['error'=>'rate_limited','retry_after'=>NSW_RATE_WINDOW,'reason'=>'busy'],429); /* COUNTS LIVE IN THE FILENAME: {id}.u{up}.d{down}.{stype}.txt — a vote is an atomic rename, NO votes/ file. Per-IP-per-post dedup (so a downvote = a person, not a click) lives in the /dev/shm-preferred rate file (RAM, forgettable). */ $rf=nsw_ratedir().DIRECTORY_SEPARATOR.md5($ip).'.txt';$ra=is_file($rf)?(json_decode(@file_get_contents($rf),true)?:[]):[];if(!is_array($ra))$ra=[];$vp=(isset($ra['vp'])&&is_array($ra['vp']))?$ra['vp']:[]; $cur=null;foreach([$tile,NSW_REMOTE_TILE] as$tt){$g=glob(nsw_shards()."/$tt/$id.u*.d*.$stype.txt");if($g){$cur=$g[0];break;}} if($cur===null)nsw_json_out(['error'=>'gone'],404); $up=0;$down=0;if(preg_match('/\.u(\d+)\.d(\d+)\.'.$stype.'\.txt$/',basename($cur),$mm)){$up=(int)$mm[1];$down=(int)$mm[2];} if(in_array($id,$vp,true))nsw_json_out(['ok'=>true,'up'=>$up,'down'=>$down,'dup'=>true]); if($vdir>0)$up++;else $down++; $vp[]=$id;if(count($vp)>200)$vp=array_slice($vp,-200);$ra['vp']=$vp;@file_put_contents($rf,json_encode($ra),LOCK_EX); if($down-$up>=nsw_downvote_threshold()){foreach(glob(nsw_shards()."/$tile/$id.u*.d*.$stype.txt")?:[]as$x)@unlink($x);foreach(glob(nsw_shards().'/'.NSW_REMOTE_TILE."/$id.u*.d*.$stype.txt")?:[]as$x)@unlink($x);nsw_log('removed_by_downvote',"$tile/$id d=$down u=$up");nsw_json_out(['ok'=>true,'removed'=>true]);} @rename($cur,dirname($cur).DIRECTORY_SEPARATOR."$id.u$up.d$down.$stype.txt"); foreach(glob(nsw_shards().'/'.NSW_REMOTE_TILE."/$id.u*.d*.$stype.txt")?:[]as$rg)@rename($rg,nsw_shards().'/'.NSW_REMOTE_TILE."/$id.u$up.d$down.$stype.txt"); nsw_json_out(['ok'=>true,'up'=>$up,'down'=>$down]);} nsw_json_out(['error'=>'unknown api'],400);} if(isset($_GET['src'])){nsw_log('src','index.php');header('Access-Control-Allow-Origin: *');header('Access-Control-Expose-Headers: X-NSW-Parity-SHA256, X-NSW-Source-SHA256');/* CORS so a browser on ANOTHER node can fetch+hash our source for the parity/malice check */header('Content-Type: text/plain; charset=utf-8');header('Content-Disposition: attachment; filename="index.php"');header('X-NSW-Source-SHA256: '.hash_file('sha256',__FILE__));header('X-NSW-Parity-SHA256: '.nsw_norm_hash());/* ^ exact bytes (debug) vs normalized parity (what mirrors compare — tolerant of formatting) */header('Content-Length: '.filesize(__FILE__));readfile(__FILE__);exit;} nsw_static_tick();/* a normal page load → (re)write the public static dump + CORS .htaccess (throttled) so outside browsers can read this node even on a bot-walled free host */ ?> No Signup Work

NOSIGNUP·WORK

Open-source · Jobs & Resumes

Built to be difficult to kill.

What this is

  • Anyone can post.
  • No accounts.
  • No moderation.
  • Everything you do here is deleted after 32 days.
  • Listings can't be edited; enough downvotes remove one early.

⚠️ Before you enter

  • Site is provided as-is
  • No warranty/liability
  • Contact happens off-platform.
  • Verify who you deal with.

No Signup Work — Open GNU License 2026 · Made with AI (ChatGPT, Claude, DeepSeek, Grok)

×
<
>
📩 Applicants send their résumé & why they’d be a good fit to — email or phone, at least one:
⏱ You can make one post or browse request every 5 minutes.
⚠️ After “Submit”, a job can’t be edited.
It’s auto-deleted after 32 days — or sooner if downvoted enough.
⏱ You can make one post or browse request every 5 minutes.
⚠️ After “Submit”, a résumé can’t be edited.
It’s auto-deleted after 32 days — or sooner if downvoted enough.
<
>
👆 Tap the map to set your area
Tip: Google “My lat long”, paste the numbers here.
📍 Radius ~111km 🔍 Zoom 1 drop a point first
Selected tile:

Host a Mirror

Drop this one file into any PHP-enabled hosting, then give us its URL or IP — it joins the network of mirrors. The more mirrors, the harder this is to take down.

↓ Download index.php

On submit, your browser checks the mirror live — reachable, serving listings, and running the same code (a parity hash that ignores harmless formatting: line endings, a trailing newline, a BOM) — and tells you the result before staging it. A mismatched, blocked, or unreachable host is rejected with the reason. Just don’t change the code itself.

🔗

About “mirrored” listings

Listings marked 🔗 Mirrored from … are not hosted by us. Your browser pulled them live, just now, from another nosignup node and is showing them as a courtesy. We don’t store them — leave this page and they’re gone from here.

They exist only while that other node keeps them public. To change or remove a mirrored listing, contact the node shown on it — not us. We’re only a temporary window onto it.

Heads up: to show these, your browser contacts those other nodes directly, so each one may see and log your request (like visiting any website). They’re nodes you added under “Help the network”.

32d files, orders newest-first by id, and the handler concatenates the RAW file contents into {"total":N,"listings":[ ,,… ]} — gzipped (ob_gzhandler) — in ONE response. The browser counts, sorts, filters, and ranks it all. There is NO server-side keyword param and NO pagination — it sends the whole region every time. STORAGE (no database; flat text shards + an append log — TWO folders) Data dir, first WRITABLE wins (the deny-all .htaccess write IS the writability probe, so a dir that EXISTS but can't be written is skipped, not wrongly accepted): 1. env NSW_DATA_DIR (set on real hosts to live OUTSIDE the webroot) 2. /var/lib/nosignup/work (NOTE: on Windows this resolves to C:\var\... and usually wins locally; on Linux it is not writable by the web user) 3. /.nsw-data (works anywhere; a deny-all .htaccess is written for Apache. On nginx you MUST point NSW_DATA_DIR off the webroot.) 4. sys_get_temp_dir()/nsw-data (UNIVERSAL no-permission fallback — PHP always has a writable temp, so the file runs on the most locked-down host with ZERO setup. Ephemeral, but a never-broken last resort.) TWO folders under the data dir (votes are NOT a folder — counts live in the shard filename): (1) shards/ — region sharding. One listing = one file; the TYPE and the community VOTE COUNTS are IN THE NAME: shards/{tile}/{id}.u{up}.d{down}.job.txt (a vote = atomic rename; no votes/ file) (flat per tile, both types mixed). A browse globs *.job.txt or *.resume.txt, so it pulls the right type BY FILENAME without opening the wrong files. Content is JSON (the .txt is cosmetic). Remote listings are ALSO copied to shards/_remote/{id}.{job|resume}.txt so "include remote" reaches them anywhere. Lazy expiry: a file older than NSW_EXPIRY_DAYS (32) is unlinked inline when its region is gathered. Posters cannot edit/remove a listing once it is up. (2) kyc/ — an append-only access log. nsw_log() writes ONE JSON line per post / browse / src download {ts, ip, xff, ua, lang, referer, act, loc}; loc is the exact shard file (posts) or the region (browses). File is named {date}.log.txt and rotates to {date}_2.log.txt … once it passes 50KB. Log files older than 32 days are lazily GC'd (~1/50 calls), so "everything you do here is deleted after 32 days" is true. WRITE-ONLY — the app never reads it back; it's for later use. (Votes are NOT a folder — up/down counts live in the shard filename; see COMMUNITY VOTES below.) EVERYTHING THIS FILE WRITES (keep it minimal — do not add more): - shards/{tile}/{id}.u{up}.d{down}.{job|resume}.txt listings; vote counts ARE the name (+ _remote copies) - kyc/{date}.log.txt the append-only access/KYC log (50KB roll, 32d GC) - .htaccess one-time data-dir guard (root .htaccess covers subdirs on Apache) - ip_posts/md5(ip).txt ONE file/IP (JSON inside, like listings): post + 'browse' + 'vote' counters AND the 'vp' per-post vote-dedup set. - ip_posts/mirrors.txt the GOSSIP set (url⇥ts, cap 64). All ip_posts/* prefer /dev/shm (RAM, forgettable); GC'd. - seed/demand.txt OPTIONAL seeder: keywords users searched (via ?api=demand). No cursor/lock files — the term is clock-derived, idle-gate serializes. The kyc log is the ONLY persistent log. No sessions, no cookies, no database. NOTE: the kyc log stores client IPs (real logging). The gate honestly says interactions are deleted after 32 days — keep that true (the GC above) and don't claim "no logs". RATE LIMIT (per browser-id, capped per IP) Each browser holds a persistent id in localStorage (nsw_uid, client-generated, no cookie — same idea as nosignup.chat's session myId) and sends it as POST `uid`. nsw_rate_check($ip, $type,$uid) keeps ONE file per IP (md5(ip).txt — JSON inside, {jobs:{uid:ts,...},resumes:{...}}) and applies TWO rules per type per NSW_RATE_WINDOW (300s): (1) per-id — a uid may post once per window (reason 'soon'); (2) per-IP — at most NSW_MAX_IDS_PER_IP (10) DISTINCT ids per window (reason 'busy'), so several people on one shared/library/office IP each get a slot, while a client that clears its id to rotate just burns into the per-IP cap. A missing/garbage uid is sanitized to a single strict per-IP slot ('ip'). TRIPS ON SUBMIT (recorded before the spam node) — a flood costs the spammer a slot. Returns ['wait'=>sec,'reason'=>...]; blocked POST → HTTP 429 {error: "rate_limited",retry_after,reason} → client #nsw-banner countdown (wording differs by reason). Checked AFTER field validation (a typo must not burn a slot) and BEFORE the spam node. Lazily GCs its own rate files. Tune NSW_MAX_IDS_PER_IP up for mobile/CGNAT, down for stricter anti-spam. BROWSE IS adaptively hard-limited per IP (nsw_browse_check, in the router): a browse globs a whole region, so it's shed BEFORE the glob with HTTP 429 {reason:'busy'} when over cap. The cap SCALES with THIS box's spare power — idle → NSW_BROWSE_MAX(8) per 300s; loaded → down to NSW_BROWSE_MIN(1), via max(MIN, min(MAX, round(MAX/(1+load)))) where load = 1-min loadavg per core (sys_getloadavg; POSIX-only, Windows/unknown → lenient MAX). Stored in the SAME per-IP file as posts ('browse' bucket). The client ALSO caches each region's dump for one window, so normal browsing rarely trips it. SPAM / MALICE NODE (server AND client — the SAME frozen model) SERVER: nsw_nn_score_mlp() — frozen embedded MLP (see header block). Runs on each POST after the rate limit; score >= NSW_MLP_THRESHOLD (0.95) → HTTP 422 {error:"content_flagged"}, client shows the #nsw-banner. Fails OPEN (no/!corrupt blob => 0.0). So blatant spam is never STORED. CLIENT: ?api=model serves the inflated model; the browser runs a JS port (spamScore — VERIFIED byte-equal to PHP) on EVERY listing it renders — LOCAL and MIRROR-MERGED. Mirror listings bypass the server scorer, so this is the ONLY filter they get: a hostile mirror can't show you scam jobs/resumes. Also fails open (no model => 0). COMMUNITY VOTES / DOWNVOTE-REMOVAL + ★ FAVORITES (dual-purpose ▲/▼) ?api=vote POST {id,tile,type,dir}: the ▲/▼ on a card. COUNTS LIVE IN THE SHARD FILENAME ({id}.u{up}.d{down}.{type}.txt) — a vote is an atomic rename, NO votes/ file. Per-IP-per-post dedup ("a downvote = a person") lives in the /dev/shm-preferred rate file (`vp` key, RAM/forgettable). It DELETES the listing (its shard(s)+_remote, logged 'removed_by_downvote') once (down − up) reaches the activity-scaled threshold = max(NSW_DOWNVOTE_MIN(5), today-KYC-bytes/NSW_DOWNVOTE_SCALE(200000)); a saved post's upvote offsets one (so it needs 6). Per-IP flood cap NSW_VOTE_MAX(30). ▼ = community FLAG (one-shot per browser; dedup via localStorage nsw_voted; on removal toasts + drops the card). ▲ = SAVE THIS to your favorites (helps YOU) AND a one-time community upvote (helps the post survive). Saving stores the FULL listing object in localStorage (nsw_fav_jobs / nsw_fav_resumes, cap 150, _mirror stripped) so it survives the post leaving your region; ▲ again un-saves. The server upvote fires once per id (gated by nsw_upvoted). Access saved items via the "★ Saved (N)" pill in each browse panel — it flips the carousel SOURCE from the live region to your favorites (filters/sort/search still apply). ▲/▼ render on LOCAL cards only (mirrored cards can't be saved/voted). Abuse model "good enough", NOT Sybil-proof. The frozen MLP does NOT use votes yet. FILTER & SORT (client-side, no network hit) — "⚙ Filter & Sort" label opens a checkbox-hack panel (#toggleJobsFilter / #toggleResumesFilter, scoped inside the browse container so its `~` reaches the sibling .filter-panel). applyView(src,opts) is the pipeline: source (region OR ★saved) → facet filters (jobs: category, min-pay, posted-within, remote-only, hide-unpaid · resumes: min-pay-wanted, posted-within, open-to-remote) → rankBy(keyword) → sort (new/relevant · nearest by tile distance · best pay via payNum()). applyJobsKeyword/applyResumesKeyword keep their old names so every existing call site (fetch, mergeMirrors, vote-removal) still drives the same render. FORMS (both Post-a-Job and Leave-a-Resume) No "Start Over" button (removed) — postForm() clears the fields itself on success via a clearFn (clearJobForm / clearResumeForm). Submit is full-width at the bottom; the permanence warning is below Submit. Job title field is just "Job title" (the "describe the job" textarea covers what's needed). There is NO "contact me before starting" opt-in (removed) — a job needs only email-OR-phone so applicants can reach the poster. COMPACT, mobile-first: ONE field per line (no side-by-side → NO horizontal scroll; the only rule is "no horizontal bars"). Vertical scroll IS allowed (overflow-y:auto, visible bar). Tight .3vh gaps, minimal padding, THICK visible borders (2.5px) doing the visual work. Textareas small (vh-based). All sizes %/vh/clamp. BROWSE INTERACTION Carousel set + order are FIXED after a region loads; they only change when the map region changes or the filter changes. The arrows AND left/right swipe just move the index through that fixed list (addSwipe: swipe left = next, right = prev; horizontal-dominant only). When the map "Save & Close"s and a Browse panel is open, that panel RE-FETCHES so the carousel reflects the new location/radius/remote (the map-toggle change handler). Empty region → EMPTY_MSG ("No results."), no demo cards. RÉSUMÉ FIELDS (Indeed-like, kept casual for non-technical / older users) Stored: name, email, phone, min_salary, education, experience, wanted, resume_text, remote, tile. REQUIRED = name + email + experience (the "Submit" warning sits BELOW the buttons, shortened). "wanted" = the jobs the worker IS LOOKING FOR (a powerful searchable field — employers find workers by desired job). Card body = experience; details show 💼wanted / 🎓education / 💰pay / 📍location. JOB PAY pay_type whitelist = remote_bounty | remote_hourly | inperson_bounty | inperson_hourly | no_pay (or blank). Pay amount is REQUIRED unless pay_type is "no_pay" (volunteer/unpaid gigs). Cards show "🤝 No pay / volunteer" for no_pay. KEYWORDS / SEARCH (do ALL the work in the browser) There is NO keyword INPUT field on the forms — EVERY field is searchable, so a separate one is redundant. The only keyword box is the BROWSE search (a single-line ). The query is split into terms on ANY non-letter/number char (TERM_SEP, unicode-aware) so commas, slashes, pipes — anything — work as separators. rankBy() builds recText(l) (every string field joined) and counts TOTAL term occurrences; most hits float to the top, ties keep recency (newest, since the server already ordered newest-first). All client-side; the server never filters or ranks. Résumé "wanted" = jobs the worker is looking for; it's just another searchable field. TILE / MAP tile = a 0.5°×0.5° (~55.5km) CELL, snapped via floor(lat*2)/2 and formatted canonically by nsw_half / JS fmtHalf (whole → "40", half → "40.5") so a cell string == its shard dir on every node. The map canvas is 720x360 (2px per degree → a cell is 1px). Radius 1-7 widens the search ring; each notch is in DEGREES and spans TWO 0.5° cells, so nsw_tiles expands ±2·notch cells and the slider LABELS it in km as "~N x 111 km" (KM_PER_DEG = 111 km/°; the "~" is on purpose — it's approximate, longitude shrinks toward the poles). Client cheb/d2 compare tile-vector DEGREES directly against the notch, so cheb° <= notch == within 2·notch cells. The animated 60vw "Map" button opens the canvas picker (checkbox #toggleMapMenu). tile/radius/remote persist. A pulsing #mapHint ("👆 Tap the map to set your area") invites the first tap and is hidden by setPointLaid() once a point exists. GO-TO-COORDINATES (no external geocoder): TWO inputs, latitude + longitude; "Go" enables only when BOTH are valid numbers in range. Drops the point and pans/zooms to it. There is NO city-name search (users google "town lat long" and paste the two numbers — stated under the inputs). CAPITALS list is still used for the on-map dots. Do NOT add a network geocode. BROWSING (carousel) — chosen-radius, nearest-N auto-expand (UNBOUNDED back-fill) bulkUrl() fetches the CHOSEN radius (getRadius(), all=1) — NOT a fixed widest ring. The SERVER (nsw_listings) returns everything inside that radius; if that's < 10 it back-fills the nearest ones with NO distance bound, scanning POPULATED tiles nearest-first until it has 10 ("best we've got, sorry"). Client-side, pickRegion() decides what to show: if the chosen radius already holds >= NEAREST_N (10) listings it shows that chosen-radius set (recency order); if it is sparse it AUTO-EXPANDS and shows the NEAREST_N closest by distance (nearest first), and the pager appends " · nearest". Remote (location-independent) listings are kept in FULL whenever "include remote" is on — the nearest-N trim applies to local ones only. An empty region shows EMPTY_MSG ("Nothing found…") — there are NO demo/example cards (empty is empty). The keyword box then re-ranks whatever set is showing via rankBy() (whole-record hit-count; see KEYWORDS / SEARCH above; never discards). ENTRANCE GATE (#nsw-gate) — modeled on nosignup.chat Shown on EVERY entrance, with NO persistence (chat uses a JS flag, not localStorage; do NOT add an "already agreed" skip). It is the hub: stacked liability one-liners, the licence/credit line, and two buttons that open checkbox-hack overlays OVER the gate (z 10001 > 10000): Donate (#toggleDonate) -> the donate modal: Bitcoin / Monero / Litecoin addresses (shared with nosignup.chat), click-to-copy, plus the ?src=1 download. Help the network (#toggleMirror) -> the Host-a-Mirror modal. There is no mirror/donate button on the home screen and no per-page footer; the gate is the only path to those modals (it returns on every reload). MIRRORS / DECENTRALIZATION ?src=1 serves THIS file verbatim with TWO headers: X-NSW-Source-SHA256 (exact bytes, debug) and X-NSW-Parity-SHA256 (nsw_norm_hash — the one that matters). Submitted mirror URLs live client-side (localStorage "nosignup_pending_mirrors", FIFO 64) AND GOSSIP: every browse dump carries a "mirrors" sample (server keeps an EPHEMERAL set in the tmpfs rate dir; ?api=mirror exchange), clients learn + re-share so lists spread virulently — fileless, NO web-SAPI outbound. PARITY RULE: a mirror is trusted only if it runs the same CODE, checked via the NORMALIZED parity hash (nsw_norm_hash ignores BOM / CRLF / trailing whitespace / trailing-newline count) so behaviour-neutral deploy artifacts don't fragment the network — only a real code change breaks parity. A node must normalize+hash a peer's fetched ?src=1 bytes ITSELF (never trust the peer's header). The canonical file still SHOULD be LF-only with no BOM and no PHP close tag (see EOF), but a mirror that drifts on those alone still passes parity. RESOURCE SHARING — model (a) BY DECISION: reads / disk / compute are ALREADY shared (each node stores only ITS OWN posts; the client ADAPTIVELY merges sibling dumps at read time — reputation-ordered, AIMD concurrency, value-stopped, see ADAPTIVE FAN-OUT below). There is NO background replication of OTHERS' posts. AUTHOR-PUSH (2026-06-20): on a successful post the poster's browser re-submits the SAME listing to its parity-VERIFIED mirrors (the author multi-homing their OWN post — not a courier relaying others', so nothing to forge). This is how a node behind an aes.js anti-bot wall (free hosts — usable by direct visitors but NOT readable cross-origin, CONFIRMED 2026-06-20 against an InfinityFree/openresty host) still gets its posts into the swarm. Each target spam-filters + rate-limits it; copies collapse on read via a content fingerprint (contentKey/dedupListings). Still ephemeral — every copy self-expires on its own clock. ?api=capacity (free disk + tile count + parity, CORS) is the placement PROBE for any future capacity-aware push (power-of-two-choices on advertised room); it does NOT replicate today. CONTAINMENT (why a hostile mirror can't poison the swarm): only ESCAPED DATA crosses mirror boundaries, NEVER code. mergeMirrors fetches a peer's dump and renders it through the single esc() path, so a tampered mirror can inject listing TEXT (escaped → no XSS) but cannot run code on the canonical site or any other mirror. Tampering is detectable (parity hash above); a bad mirror only harms ITS OWN visitors. You CANNOT stop someone editing code on a box they own — and you don't need to. ADAPTIVE FAN-OUT + MALICE DETECTION (built): mergeMirrors has NO fixed mirror count and NO fixed per-peer cap. The browser reads sibling dumps DIRECTLY (never via a relay, so nothing is forged in transit), ordered by a LEARNED reputation (localStorage nsw_mirror_rep: yield, latency, spam-fraction, parity), with concurrency that floats to the network's capacity (AIMD, ceiling derived from hardwareConcurrency) and a VALUE-BASED stop (halt when a fresh mirror adds < COVER_EPS of what you've already gathered — diminishing returns, so it scales to ANY swarm size with no magic number; COVER_EPS is the one knob = the user's "good enough"). TRUST and MALICE are the SAME reputation: - PARITY: before trusting a peer the browser hashes ITS ?src=1 AND its OWN with the same normalizer and compares (verifyParity, re-checked every PARITY_TTL). MATCH -> trusted, contributes UNCAPPED. MISMATCH -> EXILED (filtered out of the ordering, never queried until it matches again). CAN'T-VERIFY (peer lacks the ?src=1 CORS header / insecure context / dead) -> lenient: merged under the legacy max(PEER_FLOOR,20%) flood cap, exactly as before, so a not-yet-upgraded swarm keeps working in rollout. - A spammy or off-region mirror (caught by the client MLP + region scope) accrues a bad score, sinks in the ordering, and is naturally EXILED by never being reached again — the chat-style "natural exile". CONTAINMENT REMAINS the real guarantee: parity proves a peer's SOURCE matches, NOT its RUNTIME — a mirror can serve clean code and run dirty (nothing stops that on hardware you don't own). So malice detection RAISES the bar against forks/tampering; the floor is still that only ESCAPED DATA crosses, spam-filtered and reputation-bounded. Any failure in the adaptive path falls back to the simple capped merge (mergeMirrorsBasic), and local listings always render first — so this can never break browse. DEFERRED (calibrate against a real 2nd mirror): (1) the on-screen coverage meter — surface the value-stop as a live "~N% of regional listings · keep looking" control so COVER_EPS becomes a USER choice, not just a constant; (2) a gossiped holdings-CENTROID (one self-computed lat/lon riding each gossiped URL) to warm-start ordering for never-seen mirrors — forgery-safe (it only affects query ORDER, confirmed by the actual fetch). The AIMD/EWMA factors and COVER_EPS are first-cut values to tune once a live mirror exists (InfinityFree). Parity needs HTTPS (crypto.subtle) on both nodes. LAYOUT FACTS (do not "fix" these by accident) - Home = four 50% x 50% quadrant tiles, no gap. 1.5s AFTER the visitor ACCEPTS the entrance gate (JS adds body.nsw-entered — NOT on page load), they each ease over 5s to 90% toward their OWN corner (@keyframes nsw-shrink-quad, per-quadrant transform-origin), opening a central CROSS of bare field reserved for a FUTURE donation-funded "cross-ad". Each tile is rounded on its INNER corner and carries a pure-CSS hue wash + faint geometric texture + a thematic line-icon (inline SVG ::before) encoding OBJECT+ACTION: briefcase=jobs / ID-card=résumé · magnifier=browse / plus=post / up-arrow=leave. Tile rules are scoped .btn-label.X so the Back buttons aren't hit. - Navigation is a PURE-CSS checkbox hack: hidden toggles reveal the four panels and the map / mirror / donate overlays. JS NEVER shows or hides panels. The toggles MUST stay directly before the elements their "~" selectors target — DOM order is load-bearing. - Cards and forms span --col (90%). The four pinned 16.5% corner Back buttons start big (so they're easy to find) then SHRINK to 60% toward their own corner after 3s (@keyframes nsw-shrink-back), so they stop covering card content. Each is rounded on its inner corner. The browse search row STACKS vertically — a transparent full-width input with a small transparent filter pill below it — at --col (90%) width. - Forms are one field per line (NO side-by-side → no horizontal scroll); vertical scroll is allowed. No ad-slot side columns — the future ad is the central CROSS opened by the quadrant shrink (above). - Résumé preview scrolls vertically; long résumés are not clipped. - The .LeftArrow / .RightArrow are wide tap targets with a smooth eased nudge; left/right SWIPE on a carousel = prev/next (addSwipe). - z-index ladder: donate & mirror overlays 10001 (ABOVE the gate) > gate 10000 > toast 9999 > rate banner 9998 > map overlay 2000 > corner Back 30 > top/map bar 15 > panels 10 > home tiles 1 > cycling background 0. HARDWARE / ANDROID BACK (backNav IIFE) Each panel/overlay open pushes one history entry; popstate closes the topmost open layer (donate, mirror, map, then the four panels) instead of leaving the page. In-app Back/Close labels and the post-success auto-close pop their entry via history.back(), guarded by a "suppress" flag and history.state.nsw, so the history depth never drifts. localStorage KEYS (UI / client state ONLY — never listing data) nsw_tile, nsw_radius, nsw_remote (map state); nsw_uid (per-browser rate-limit id); nsw_voted (ids downvoted/flagged, capped 300); nsw_upvoted (ids upvoted once, capped 300); nsw_fav_jobs / nsw_fav_resumes (★ saved FULL listing objects, cap 150 each — the only keys that hold listing data, and only the user's own chosen saves); nosignup_pending_mirrors (FIFO 64); nsw_mirror_rep (learned per-mirror reputation: yield/latency/spam/parity — drives ordering + exile, capped 256). All go through the STORE shim (probe-once; falls back to in-memory + a loud banner if blocked). EOF The file ends just below with NO closing PHP tag and a single trailing LF, on purpose — so an editor, a CRLF conversion, or a BOM cannot shift bytes and break mirror parity. (Do not write the comment-terminator anywhere in this block except the one that actually closes it.) ================================================================================ */