CoolFace
Apppublic

APProjects/warn-act-notices

sourceHugging Facecc-by-4.0updated 2h agoView on Hugging Face
0likes
watch-now.html429 linesDownload Raw Back to root
1<!doctype html><html lang="en"><head><meta charset="utf-8">2<!-- og:begin -->3<meta property="og:title" content="Watch your employers for layoff notices — free, no signup">4<meta property="og:description" content="Type the companies you care about and see every US WARN Act layoff notice they filed in the last 180 days. 1,764 notices, 1,287 employers, 44 states. Runs in your browser — no account, no email, nothing sent anywhere.">5<meta property="og:url" content="https://approjects-warn-act-notices.static.hf.space/watch-now.html">6<meta property="og:image" content="https://approjects-warn-act-notices.static.hf.space/assets/og-card.png">7<meta name="twitter:card" content="summary_large_image">8<!-- og:end -->9 10<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://cdn.jsdelivr.net; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self' https://app.gumroad.com; upgrade-insecure-requests">11 12<meta name="viewport" content="width=device-width,initial-scale=1">13<title>Watch your employers for layoff notices — free, no signup</title>14<meta name="description" content="Type the companies you care about and see every US WARN Act layoff notice they filed in the last 180 days. 1,764 notices, 1,287 employers, 44 states. Runs in your browser — no account, no email, nothing sent anywhere.">15<link rel="canonical" href="https://approjects-warn-act-notices.static.hf.space/watch-now.html">16<style>17:root{--ink:#1a1a1a;--mute:#5b5b5b;--line:#e2e2e2;--accent:#b02a1f;--blue:#0b5fa5;--wash:#fdf3f2}18*{box-sizing:border-box}19body{font-family:-apple-system,Segoe UI,Helvetica,Arial,sans-serif;max-width:940px;margin:0 auto;padding:1.5rem 1rem 4rem;color:var(--ink);line-height:1.55}20a{color:var(--blue)}21.crumb{font-size:.85rem;color:var(--mute);margin:0 0 1.2rem}22h1{font-size:1.9rem;line-height:1.2;margin:0 0 .6rem}23h2{font-size:1.25rem;margin:2.6rem 0 .7rem}24.lede{font-size:1.06rem;color:#333;max-width:68ch}25.kpis{display:flex;flex-wrap:wrap;gap:12px;margin:1.4rem 0}26.kpi{flex:1 1 150px;border:1px solid var(--line);border-radius:9px;padding:12px 14px;background:#fafafa}27.kpi b{display:block;font-size:1.5rem;line-height:1.15;color:var(--accent)}28.kpi span{font-size:.82rem;color:var(--mute)}29.panel{border:2px solid var(--blue);border-radius:10px;padding:16px;margin:1.6rem 0;background:#f7fbff}30label.fld{display:block;font-weight:600;margin:0 0 .35rem}31textarea{width:100%;min-height:96px;font-size:1.02rem;padding:.6rem .7rem;border:1px solid #9dbcd8;border-radius:7px;font-family:inherit;resize:vertical}32.hint{font-size:.85rem;color:var(--mute);margin:.4rem 0 0}33details.states{margin:1rem 0 0}34details.states summary{cursor:pointer;font-weight:600;min-height:44px;line-height:44px}35.stategrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(165px,1fr));gap:2px 10px;margin:.4rem 0}36.stategrid label{font-size:.9rem;display:flex;align-items:center;gap:6px;min-height:30px}37.btn{display:inline-block;background:var(--accent);color:#fff;text-decoration:none;font-weight:600;padding:13px 22px;min-height:46px;line-height:20px;border:0;border-radius:7px;font-size:1rem;cursor:pointer}38.btn:hover{background:#8e2118}39.btn.ghost{background:#fff;color:var(--accent);border:1px solid var(--accent)}40.row-actions{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:1rem 0 0}41table{border-collapse:collapse;width:100%;margin:1rem 0}42th,td{border:1px solid var(--line);padding:8px 9px;text-align:left;font-size:.92rem;vertical-align:top}43th{background:#f5f5f5}44td.r,th.r{text-align:right}45tr.fresh td{background:#fffbe6}46.tag{display:inline-block;font-size:.72rem;font-weight:700;color:#7a5c00;background:#ffe9a8;border-radius:4px;padding:1px 6px;margin-left:6px;vertical-align:middle}47.hist{display:block;font-size:.8rem;color:var(--mute);margin-top:3px}48#stat{color:var(--mute);font-size:.95rem;margin:.8rem 0}49.empty{border:1px dashed #c9c9c9;border-radius:9px;padding:22px;color:var(--mute);text-align:center}50.upsell{border:2px solid var(--accent);border-radius:10px;padding:16px 18px;margin:1.2rem 0 0;background:var(--wash)}51.upsell p{margin:0 0 .6rem;max-width:70ch}52.upsell .row-actions{margin-top:.8rem}53.sell{border-left:4px solid var(--accent);background:var(--wash);border-radius:0 9px 9px 0;padding:16px 18px;margin:2rem 0}54.sell h2{margin:0 0 .5rem;font-size:1.15rem}55.cmp{width:100%;border-collapse:collapse;margin:.8rem 0}56.cmp td,.cmp th{font-size:.9rem}57footer{margin-top:3rem;padding-top:1.2rem;border-top:1px solid var(--line);font-size:.87rem;color:var(--mute)}58@media (max-width:560px){59 body{padding:1rem .8rem 3rem} h1{font-size:1.5rem}60 th,td{padding:7px 5px;font-size:.85rem}61 .btn{display:block;width:100%;text-align:center}62 .kpi b{font-size:1.25rem}63}64</style></head><body>65<p class="crumb"><a href="https://approjects-warn-act-notices.static.hf.space/">US WARN layoff notices</a> &rsaquo; Watch your employers</p>66 67<h1>Watch your employers for layoff notices</h1>68<p class="lede">Type the companies you care about. This page checks them against every US WARN Act69layoff notice filed in the last 180 days and shows you the matches. <b>No account, no70email address, no checkout</b> &mdash; the matching runs inside your browser and your list is never71sent anywhere.</p>72 73<div class="kpis">74<div class="kpi"><b>1,764</b><span>notices in the last 180 days</span></div>75<div class="kpi"><b>1,287</b><span>distinct employers filing</span></div>76<div class="kpi"><b>169,252</b><span>workers named in them</span></div>77<div class="kpi"><b>44</b><span>states represented</span></div>78</div>79<p class="hint">Counted from the free dataset at build time. Latest notice date in the file: <b>2026-09-23</b>.80The whole archive is 61,431 notices back to 1988.</p>81 82<div class="panel">83<label class="fld" for="terms">Your employers &mdash; one per line</label>84<textarea id="terms" placeholder="Boeing&#10;Kaiser&#10;Rite Aid" autocomplete="off" spellcheck="false"></textarea>85<p class="hint">Case-insensitive, and a name matches on <b>whole words</b>, so <b>Boeing</b> finds86&ldquo;Boeing Commercial Airplanes&rdquo; while <b>Ford</b> does <i>not</i> drag in Stanford, Medford or Rockford87&mdash; which is what a plain text search of the CSV does. This is the same matcher the paid alerts run.</p>88<details class="states"><summary>&hellip; or watch whole states</summary>89<div class="stategrid"><label><input type="checkbox" class="stbox" value="AK"> Alaska</label><label><input type="checkbox" class="stbox" value="AL"> Alabama</label><label><input type="checkbox" class="stbox" value="AR"> Arkansas</label><label><input type="checkbox" class="stbox" value="AZ"> Arizona</label><label><input type="checkbox" class="stbox" value="CA"> California</label><label><input type="checkbox" class="stbox" value="CO"> Colorado</label><label><input type="checkbox" class="stbox" value="CT"> Connecticut</label><label><input type="checkbox" class="stbox" value="DC"> District of Columbia</label><label><input type="checkbox" class="stbox" value="DE"> Delaware</label><label><input type="checkbox" class="stbox" value="FL"> Florida</label><label><input type="checkbox" class="stbox" value="GA"> Georgia</label><label><input type="checkbox" class="stbox" value="HI"> Hawaii</label><label><input type="checkbox" class="stbox" value="IA"> Iowa</label><label><input type="checkbox" class="stbox" value="ID"> Idaho</label><label><input type="checkbox" class="stbox" value="IL"> Illinois</label><label><input type="checkbox" class="stbox" value="IN"> Indiana</label><label><input type="checkbox" class="stbox" value="KS"> Kansas</label><label><input type="checkbox" class="stbox" value="KY"> Kentucky</label><label><input type="checkbox" class="stbox" value="LA"> Louisiana</label><label><input type="checkbox" class="stbox" value="MA"> Massachusetts</label><label><input type="checkbox" class="stbox" value="MD"> Maryland</label><label><input type="checkbox" class="stbox" value="ME"> Maine</label><label><input type="checkbox" class="stbox" value="MI"> Michigan</label><label><input type="checkbox" class="stbox" value="MN"> Minnesota</label><label><input type="checkbox" class="stbox" value="MO"> Missouri</label><label><input type="checkbox" class="stbox" value="MS"> Mississippi</label><label><input type="checkbox" class="stbox" value="MT"> Montana</label><label><input type="checkbox" class="stbox" value="NC"> North Carolina</label><label><input type="checkbox" class="stbox" value="ND"> North Dakota</label><label><input type="checkbox" class="stbox" value="NE"> Nebraska</label><label><input type="checkbox" class="stbox" value="NH"> New Hampshire</label><label><input type="checkbox" class="stbox" value="NJ"> New Jersey</label><label><input type="checkbox" class="stbox" value="NM"> New Mexico</label><label><input type="checkbox" class="stbox" value="NV"> Nevada</label><label><input type="checkbox" class="stbox" value="NY"> New York</label><label><input type="checkbox" class="stbox" value="OH"> Ohio</label><label><input type="checkbox" class="stbox" value="OK"> Oklahoma</label><label><input type="checkbox" class="stbox" value="OR"> Oregon</label><label><input type="checkbox" class="stbox" value="PA"> Pennsylvania</label><label><input type="checkbox" class="stbox" value="RI"> Rhode Island</label><label><input type="checkbox" class="stbox" value="SC"> South Carolina</label><label><input type="checkbox" class="stbox" value="SD"> South Dakota</label><label><input type="checkbox" class="stbox" value="TN"> Tennessee</label><label><input type="checkbox" class="stbox" value="TX"> Texas</label><label><input type="checkbox" class="stbox" value="UT"> Utah</label><label><input type="checkbox" class="stbox" value="VA"> Virginia</label><label><input type="checkbox" class="stbox" value="VT"> Vermont</label><label><input type="checkbox" class="stbox" value="WA"> Washington</label><label><input type="checkbox" class="stbox" value="WI"> Wisconsin</label><label><input type="checkbox" class="stbox" value="WV"> West Virginia</label><label><input type="checkbox" class="stbox" value="WY"> Wyoming</label></div>90</details>91<div class="row-actions">92<button class="btn" id="go" type="button">Show my matches</button>93<button class="btn ghost" id="clear" type="button">Clear</button>94<span class="hint" id="saved"></span>95</div>96</div>97 98<p id="stat"></p>99<div id="results"></div>100 101<div class="sell">102<h2>This page only looks when you open it &mdash; so take the feeds instead</h2>103<p>That is the honest limit of a browser-side tool. After you press <b>Show my matches</b> you can104download an <b>.opml</b> file holding one RSS feed per employer you typed &mdash; free, no account, no105email address &mdash; and your reader checks them for you every morning.</p>106<table class="cmp">107<tr><th></th><th>This page (free)</th><th>WARN Watch ($49/year)</th></tr>108<tr><td>Checks your list</td><td>when you open it, or when your feed reader polls the .opml</td><td>every daily refresh, automatically</td></tr>109<tr><td>Tells you</td><td>on screen, or in your RSS reader</td><td>it comes to you: private alert page + RSS + calendar (.ics) + optional Slack/Discord/Teams</td></tr>110<tr><td>How many terms</td><td>as many as you like</td><td>up to 500 terms plus whole states</td></tr>111<tr><td>History per match</td><td>notice count &amp; first year</td><td>full filing record &mdash; every state, every prior notice, worker totals</td></tr>112<tr><td>Separation reminder</td><td>&mdash;</td><td>again 14 days before the layoff date</td></tr>113</table>114<p><a class="btn" href="https://approj.gumroad.com/l/warn-watch">Get WARN Watch &mdash; $49/year</a></p>115<p class="hint">One-off, no auto-renew, 14-day refund. <a href="https://approjects-warn-act-notices.static.hf.space/watch-sample.html">See a real alert page first</a>116&mdash; no email needed to look.</p>117</div>118 119<h2>How this works</h2>120<p>The file behind this page is <a href="https://approjects-warn-act-notices.static.hf.space/data/watch-recent.json">watch-recent.json</a>, rebuilt121by the same daily pipeline that publishes the122<a href="https://huggingface.co/datasets/APProjects/us-warn-act-layoffs-notices-daily">free dataset</a>123and the <a href="https://github.com/APVentureEngine/warn-act-notices">source repo</a>. Notices come124from official WARN Act filings by 48 state agencies, normalized into one schema; 44 of those125states have at least one notice inside the 180-day window. Your watchlist is126stored in this browser only (localStorage) and mirrored into this page's own URL, so you can bookmark127it or send it to a colleague &mdash; it never touches a server of ours. Any page on this site can128open the tool pre-filled: <code>watch-now.html?q=Boeing|Kaiser</code> or <code>?s=CA,TX</code>.</p>129<p>What is counted: three 1&times;1 images on the public jsDelivr CDN &mdash; one when this page opens, one if130it opened pre-filled from a link, one the first time a non-empty list is matched. That is a daily total per131file, <a href="https://data.jsdelivr.com/v1/stats/packages/gh/APVentureEngine/warn-act-notices@main/files?period=month">published openly by jsDelivr</a>; no cookie, no ID, and never the names you132typed.</p>133<p>Nothing here is legal or financial advice, and a WARN notice is an employer's filing, not a134guarantee that a layoff happened as described. Corrections: open an issue on the135<a href="https://github.com/APVentureEngine/warn-act-notices/issues">source repo</a>.</p>136 137<footer>138<p><a href="https://approjects-warn-act-notices.static.hf.space/">WARN Feed</a> &middot; <a href="https://approjects-warn-act-notices.static.hf.space/search.html">Search all employers</a>139&middot; <a href="https://approjects-warn-act-notices.static.hf.space/sources.html">Where the data comes from</a>140&middot; <a href="https://approjects-warn-act-notices.static.hf.space/privacy.html">Privacy &amp; terms</a></p>141<p>Free data under CC BY 4.0. An independent automated publisher; not affiliated with any government agency.</p>142<p class="beacon-note" style="font-size:.8rem;color:#777">Loads counted anonymously: one 1&times;1 CDN image, no cookies, no personal data (<a href="privacy.html">detail</a>).</p>143</footer>144 145<script>146(function(){147 var DATA=null, LS='warnfeed.watch.v1', LSEEN='warnfeed.watch.seen.v1', DEEP=false, USED=false;148 // c601: FEEDS maps a canonical employer name -> its static RSS feed slug, and a149 // state code -> the per-state feed slug. Loaded separately from DATA so that a150 // missing/old watch-feeds.json degrades to "no subscribe block" instead of151 // breaking the matcher, which is the part people came for.152 var FEEDS=null, LASTFEEDS=[];153 // c601: "new since you last looked" must be read ONCE. render() writes154 // LSEEN=asof when it finishes, so a second render (after the feed map arrives)155 // would otherwise compare against itself and silently drop every NEW badge.156 var SEEN0=null;157 function seen0(){158   if(SEEN0===null){ SEEN0=''; try{SEEN0=localStorage.getItem(LSEEN)||''}catch(e){} }159   return SEEN0;160 }161 function px(u){try{var i=new Image();i.src=u}catch(e){}}162 px('https://cdn.jsdelivr.net/gh/APVentureEngine/warn-act-notices@main/assets/px-tool.png');163 var $=function(id){return document.getElementById(id)};164 function stateBoxes(){return Array.prototype.slice.call(document.querySelectorAll('.stbox'))}165 function readForm(){166   var terms=$('terms').value.split('\n').map(function(s){return s.trim()}).filter(Boolean);167   var sts=stateBoxes().filter(function(b){return b.checked}).map(function(b){return b.value});168   return {t:terms,s:sts};169 }170 function writeForm(w){171   $('terms').value=(w.t||[]).join('\n');172   var set={}; (w.s||[]).forEach(function(c){set[c]=1});173   stateBoxes().forEach(function(b){b.checked=!!set[b.value]});174 }175 function save(w){176   try{localStorage.setItem(LS,JSON.stringify(w))}catch(e){}177   var h='';178   if(w.t&&w.t.length) h+='w='+encodeURIComponent(w.t.join('|'));179   if(w.s&&w.s.length) h+=(h?'&':'')+'s='+w.s.join(',');180   try{history.replaceState(null,'',h?('#'+h):location.pathname)}catch(e){}181   $('saved').textContent=(w.t.length||w.s.length)?'Saved in this browser. Bookmark this page to keep it.':'';182 }183 function load(){184   var w=null, qs=location.search.replace(/^\?/,'');185   if(qs){186     var q={}; qs.split('&').forEach(function(kv){var i=kv.indexOf('=');if(i>0){var k=kv.slice(0,i),v=kv.slice(i+1);q[k]=q[k]?q[k]+'|'+v:v}});187     if(q.q||q.s){188       var dq=function(x){try{return decodeURIComponent(x.replace(/\+/g,' '))}catch(e){return x}};189       w={t:q.q?dq(q.q).split('|').map(function(x){return x.trim()}).filter(Boolean):[],190          s:q.s?dq(q.s).toUpperCase().split(/[,|]/).map(function(x){return x.trim()}).filter(Boolean):[]};191       DEEP=true;192     }193   }194   var h=location.hash.replace(/^#/,'');195   if(!w && h){196     var p={}; h.split('&').forEach(function(kv){var i=kv.indexOf('=');if(i>0)p[kv.slice(0,i)]=kv.slice(i+1)});197     if(p.w||p.s) w={t:p.w?decodeURIComponent(p.w).split('|').filter(Boolean):[],198                      s:p.s?p.s.split(',').filter(Boolean):[]};199   }200   if(!w){ try{w=JSON.parse(localStorage.getItem(LS)||'null')}catch(e){w=null} }201   if(w){ w.t=(w.t||[]).slice(0,500); w.s=(w.s||[]).slice(0,60); }202   return w||{t:[],s:[]};203 }204 function esc(s){return String(s==null?'':s).replace(/[&<>"]/g,function(c){205   return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]})}206 function num(n){return Number(n||0).toLocaleString('en-US')}207 208 // c477 (2026-09-18): WHOLE-TOKEN MATCHING, IDENTICAL TO THE PAID MATCHER.209 // This used to be `company.indexOf(term)>=0`, i.e. a substring grep, and it was210 // measured against the live file on 2026-09-18: "ford" returned 6 rows of which211 // SIX were wrong (Hanford, Medford, Mulford, Stanford x2, Rockford) and none212 // were Ford; "gm" returned GMRI and "Hotel Mgmt"; "intel" returned213 // IntelliPower; "meta" returned EPTAM Metals. So the free tool — the first214 // thing the landing page asks a stranger to do — demonstrated exactly the215 // failure the paid tier is sold as fixing, while warn_watch.py:notice_matches216 // had done it correctly all along. Mirror that function here: tokenise on217 // [^a-z0-9]+, drop the same STOP words from the typed term, and require every218 // term token to be a whole token of company/canonical. Keep the two matchers219 // in sync — the free tool is the demo of the paid one.220 var STOP={inc:1,llc:1,corp:1,corporation:1,co:1,company:1,ltd:1,the:1,of:1,and:1,incorporated:1,lp:1,llp:1,plc:1};221 function toks(s){return String(s==null?'':s).toLowerCase().split(/[^a-z0-9]+/).filter(Boolean)}222 function termToks(s){var t=toks(s),k=t.filter(function(x){return !STOP[x]});return k.length?k:t}223 function hayFor(i){224   if(!DATA.__hay){225     DATA.__hay=DATA.rows.map(function(r){226       var h={}; toks(r[0]).concat(toks(r[1])).forEach(function(t){h[t]=1}); return h;227     });228   }229   return DATA.__hay[i];230 }231 function match(w){232   if(!DATA) return [];233   var terms=(w.t||[]).map(termToks).filter(function(t){return t.length});234   var sts={}; (w.s||[]).forEach(function(c){sts[c]=1});235   if(!terms.length && !Object.keys(sts).length) return [];236   return DATA.rows.filter(function(r,i){237     if(sts[r[2]]) return true;238     if(!terms.length) return false;239     var hay=hayFor(i);240     for(var j=0;j<terms.length;j++){241       var ts=terms[j], ok=true;242       for(var k=0;k<ts.length;k++){ if(!hay[ts[k]]){ok=false;break} }243       if(ok) return true;244     }245     return false;246   });247 }248 249 // c601 — THE FREE RUNG. Before this, the only step after a match was a Gumroad250 // checkout (19 days, 0 takers, incl. the $0 trial). Every employer that filed251 // inside the window has a static RSS feed; this turns the visitor's own list252 // into an .opml they import once and never think about again. No account, no253 // email, no server. The paid tier stays distinct because it PUSHES.254 function subList(rows,w){255   if(!FEEDS) return [];256   var seen={}, list=[];257   // States first, and a ticked state SUPPRESSES the per-employer feeds it258   // dragged in: ticking California matched 455 employers, and handing someone259   // 455 subscriptions instead of the one state feed is not a feature.260   (w.s||[]).forEach(function(c){261     var s=FEEDS.states&&FEEDS.states[c];262     if(s && !seen['s'+s]){ seen['s'+s]=1; list.push({t:c+' \u2014 every notice in the state', u:'feeds/'+s+'.xml'}); }263   });264   var terms=(w.t||[]).map(termToks).filter(function(t){return t.length});265   if(terms.length){266     rows.forEach(function(r){267       var h={}; toks(r[0]).concat(toks(r[1])).forEach(function(t){h[t]=1});268       var hit=false;269       for(var j=0;j<terms.length && !hit;j++){270         var ts=terms[j], ok=true;271         for(var k=0;k<ts.length;k++){ if(!h[ts[k]]){ok=false;break} }272         if(ok) hit=true;273       }274       if(!hit) return;   // this row matched only because of a ticked state275       var lc=(r[1]||'').toLowerCase(), s=FEEDS.emp&&FEEDS.emp[lc];276       if(s && !seen['e'+s]){ seen['e'+s]=1; list.push({t:r[0], u:'feeds/employer/'+s+'.xml'}); }277     });278   }279   return list;280 }281 function subBlock(rows,w){282   var list=subList(rows,w); LASTFEEDS=list;283   if(!list.length) return '';284   var n=list.length;285   var links=list.slice(0,8).map(function(f){286     return '<a href="'+esc(f.u)+'">'+esc(f.t)+'</a>';287   }).join(' &middot; ');288   if(n>8) links+=' &middot; +'+num(n-8)+' more inside the file';289   return '<div class="upsell"><p><b>Free, no account, no email address: put these '+num(n)+290     ' feed'+(n===1?'':'s')+' in your reader.</b> Each one is rebuilt every morning with this '+291     'dataset, so the next notice shows up in your reader whether or not you ever open this page again.</p>'+292     '<div class="row-actions"><a class="btn" id="opml" href="#">Download my subscriptions (.opml)</a></div>'+293     '<p class="hint">Import the file into Feedly, Inoreader, NetNewsWire, Thunderbird or any RSS reader. '+294     'Or grab them one at a time: '+links+'</p></div>';295 }296 function opmlDoc(){297   var x='<?xml version="1.0" encoding="UTF-8"?>\n<opml version="1.0">\n'+298         '<head><title>My WARN watchlist</title></head>\n<body>\n';299   LASTFEEDS.forEach(function(f){300     x+='  <outline type="rss" text="'+esc(f.t)+'" title="'+esc(f.t)+301        '" xmlUrl="https://approjects-warn-act-notices.static.hf.space/'+esc(f.u)+'" htmlUrl="https://approjects-warn-act-notices.static.hf.space/watch-now.html"/>\n';302   });303   return x+'<img src="https://cdn.jsdelivr.net/gh/APVentureEngine/warn-act-notices@main/assets/px.png" alt="" width="1" height="1" referrerpolicy="no-referrer" style="position:absolute;left:-9999px;top:0">304<script id="fl">if(top!==self)for(var a of document.links)if(a.origin!==location.origin){a.target="_blank";a.rel="noopener"}</script>305</body>\n</opml>\n';306 }307 308 function render(w){309   var rows=match(w), lastSeen=seen0();310   var res=$('results');311   if(!w.t.length && !w.s.length){312     $('stat').textContent='';313     res.innerHTML='<div class="empty">Add at least one employer name or tick a state, then press '+314       '<b>Show my matches</b>.</div>';315     return;316   }317   if(!USED){USED=true;px('https://cdn.jsdelivr.net/gh/APVentureEngine/warn-act-notices@main/assets/px-tool-used.png');}318   var fresh=0;319   rows.forEach(function(r){ if(lastSeen && r[8] && r[8]>lastSeen) fresh++; });320   $('stat').innerHTML='<b>'+num(rows.length)+'</b> notice'+(rows.length===1?'':'s')+321     ' in the last '+DATA.window_days+' days match your list'+322     (fresh?(' &middot; <b>'+num(fresh)+' new since you last looked</b>'):'')+'.';323   // c526: the offer, stated on the visitor's OWN list, right under the result.324   var what=[]; if(w.t.length) what.push(w.t.length===1?'name':num(w.t.length)+' names');325   if(w.s.length) what.push(w.s.length===1?'state':num(w.s.length)+' states');326   var lst=what.join(' and '), these=((w.t.length+w.s.length)===1?'this ':'these ')+lst;327   function upsell(n){328     var lead = n329       ? '<b>'+num(n)+(n===1?' notice':' notices')+'</b> matched your '+lst+' today. This page will not look again until you reopen it.'330       : 'None of your '+lst+' filed a WARN notice in the last '+DATA.window_days+' days. The next one can land tomorrow, and this page will not tell you unless you come back.';331     return '<div class="upsell"><p>'+lead+'</p>'+332       '<p>WARN Watch runs this same match after every daily rebuild and sends only what is new to a private alert page, RSS, calendar and Slack &mdash; up to 500 names plus whole states.</p>'+333       '<div class="row-actions">'+334       '<a class="btn cta" href="'+esc('https://approj.gumroad.com/l/warn-watch')+'">Keep '+these+' watched daily &mdash; $49/year</a>'+335       '<a class="btn ghost cta" href="'+esc('https://approj.gumroad.com/l/warn-free-watch')+'">Try it free for 30 days &mdash; no card</a>'+336       '</div>'+337       '<p class="hint">One-off, no auto-renew, 14-day refund. Your list stays in this browser; you paste it again at checkout.</p></div>';338   }339   if(!rows.length){340     res.innerHTML='<div class="empty">No WARN notices from those employers in the last '+341       DATA.window_days+' days. That is usually good news. '+342       '<a href="'+esc('https://approjects-warn-act-notices.static.hf.space')+'/search.html">Search the whole archive back to 1988</a> '+343       'to see what they have filed before.</div>'+subBlock(rows,w)+upsell(0);344   } else {345     var h='<table><tr><th>Notice date</th><th>Employer</th><th>Where</th>'+346           '<th class="r">Workers</th><th>Type</th><th>Effective</th></tr>';347     rows.forEach(function(r){348       var isNew=(lastSeen && r[8] && r[8]>lastSeen);349       var hk=(r[1]||'').toLowerCase(), hi=DATA.history[hk];350       var hist='';351       if(hi && hi[0]>1){352         hist='<span class="hist">'+num(hi[0])+' notices since '+esc(hi[2])+353              ' &middot; '+num(hi[1])+' workers'+(hi[3]>1?(' &middot; '+hi[3]+' states'):'')+'</span>';354       }355       h+='<tr class="'+(isNew?'fresh':'')+'">'+356          '<td>'+esc(r[3])+(isNew?'<span class="tag">NEW</span>':'')+'</td>'+357          '<td><a href="'+esc('https://approjects-warn-act-notices.static.hf.space')+'/search.html?q='+encodeURIComponent(r[0])+'">'+esc(r[0])+'</a>'+hist+'</td>'+358          '<td>'+esc(r[7]||'')+(r[2]?(r[7]?', ':'')+esc(r[2]):'')+'</td>'+359          '<td class="r">'+num(r[5])+'</td>'+360          '<td>'+esc(r[6]||'')+'</td>'+361          '<td>'+esc(r[4]||'')+'</td></tr>';362     });363     res.innerHTML=h+'</table>'+subBlock(rows,w)+upsell(rows.length);364   }365   try{localStorage.setItem(LSEEN,DATA.asof)}catch(e){}366 }367 // c526: count clicks on the in-result CTA (either button) — one pixel, no ID, nothing about the list.368 document.getElementById('results').addEventListener('click',function(e){369   var a=e.target; while(a && a.tagName!=='A') a=a.parentNode;370   if(a && a.className && a.className.indexOf('cta')!==-1) px('https://cdn.jsdelivr.net/gh/APVentureEngine/warn-act-notices@main/assets/px-tool-cta.png');371 });372 // c601: build the .opml in the browser from the visitor's own matches. The list373 // never leaves the page — same promise as the matcher itself.374 document.getElementById('results').addEventListener('click',function(e){375   var a=e.target; while(a && a.tagName!=='A') a=a.parentNode;376   if(!a || a.id!=='opml') return;377   e.preventDefault();378   var txt=opmlDoc();379   try{380     var b=new Blob([txt],{type:'text/x-opml'}), u=URL.createObjectURL(b),381         d=document.createElement('a');382     d.href=u; d.download='warn-watchlist.opml';383     document.body.appendChild(d); d.click();384     setTimeout(function(){URL.revokeObjectURL(u); document.body.removeChild(d)},0);385   }catch(err){386     window.location.href='data:text/x-opml;charset=utf-8,'+encodeURIComponent(txt);387   }388   px('https://cdn.jsdelivr.net/gh/APVentureEngine/warn-act-notices@main/assets/px-tool-opml.png');389 });390 391 function boot(){392   var w=load(); writeForm(w); if(DEEP){save(w);px('https://cdn.jsdelivr.net/gh/APVentureEngine/warn-act-notices@main/assets/px-tool-deep.png');}393   $('go').addEventListener('click',function(){var x=readForm();save(x);render(x)});394   $('clear').addEventListener('click',function(){395     var x={t:[],s:[]}; writeForm(x); save(x); render(x);396   });397   $('stat').textContent='Loading the last '+180+' days of notices\u2026';398   var xhr=new XMLHttpRequest();399   xhr.open('GET','data/watch-recent.json',true);400   xhr.onload=function(){401     if(xhr.status>=200&&xhr.status<300){402       try{DATA=JSON.parse(xhr.responseText)}catch(e){}403     }404     if(!DATA){ $('stat').textContent='Could not load the notice file. Reload the page, or use the search page.'; return; }405     render(w);406   };407   xhr.onerror=function(){$('stat').textContent='Could not load the notice file. Reload the page, or use the search page.'};408   xhr.send();409   // c601: the employer->feed map, fetched independently. If it never arrives410   // the page works exactly as it did before; when it does, re-render so the411   // free subscribe block appears under results already on screen.412   var fx=new XMLHttpRequest();413   fx.open('GET','data/watch-feeds.json',true);414   fx.onload=function(){415     if(fx.status>=200&&fx.status<300){416       try{FEEDS=JSON.parse(fx.responseText)}catch(e){}417     }418     if(FEEDS&&DATA){419       var v=load();420       if((v.t||[]).length||(v.s||[]).length) render(v);421     }422   };423   fx.send();424 }425 if(document.readyState!=='loading') boot(); else document.addEventListener('DOMContentLoaded',boot);426})();427</script>428</body></html>429 
APProjects/warn-act-notices · CoolFace