getreadystack commited on
Commit
d2f6397
·
verified ·
1 Parent(s): 293982b

Upload index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +157 -18
index.html CHANGED
@@ -1,19 +1,158 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html lang="en"><meta charset="utf-8">
2
+ <meta name="viewport" content="width=device-width,initial-scale=1">
3
+ <title>DeviceTree Config Audit - 23 dtc-style rules for .dts, .overlay, TOML, .properties</title>
4
+ <meta name="description" content="Paste a .dts, .dtsi, .overlay, TOML or .properties file and get the line numbers back. 23 rules for the spellings the compiler accepts and the build ignores - status = &quot;ok&quot; is not in the Devicetree Specification v0.4 list, and Zephyr marks a node present only for the exact value &quot;okay&quot;.">
5
+ <link rel="canonical" href="https://getreadystack.com/tools/devicetree-config-language-pack">
6
+ <script defer data-auto-init src="https://cdn.jsdelivr.net/npm/@polar-sh/checkout@latest/dist/embed.global.js"></script>
7
+ <style>
8
+ :root{color-scheme:light dark}
9
+ *{box-sizing:border-box}
10
+ body{margin:0;font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif;
11
+ background:#fbfbfa;color:#16161d}
12
+ @media(prefers-color-scheme:dark){body{background:#14141a;color:#e8e8ea}}
13
+ .wrap{max-width:900px;margin:0 auto;padding:26px 20px 64px}
14
+ h1{font-size:1.65rem;line-height:1.22;margin:.1em 0 .35em;letter-spacing:-.02em}
15
+ p.sub{margin:0 0 1.2em;opacity:.82}
16
+ .grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
17
+ @media(max-width:760px){.grid{grid-template-columns:1fr}}
18
+ label{display:block;font-size:13px;font-weight:600;opacity:.7;margin:0 0 6px;
19
+ text-transform:uppercase;letter-spacing:.06em}
20
+ textarea{width:100%;min-height:290px;font:13px/1.5 ui-monospace,Menlo,Consolas,monospace;
21
+ padding:12px;border:1px solid #c9c9d1;border-radius:10px;background:transparent;color:inherit}
22
+ button{font:600 15px/1 inherit;padding:12px 22px;border:0;border-radius:10px;
23
+ background:#1d4ed8;color:#fff;cursor:pointer;margin:12px 8px 12px 0}
24
+ button:hover{background:#1a43bd}
25
+ button.ghost{background:transparent;color:inherit;border:1px solid #c9c9d1}
26
+ #out{min-height:290px;border:1px solid #d8d8e0;border-radius:10px;padding:4px 12px 12px;
27
+ overflow:auto;max-height:420px}
28
+ table{border-collapse:collapse;width:100%;font-size:14px}
29
+ th,td{border-bottom:1px solid #d8d8e0;padding:8px 6px;text-align:left;vertical-align:top}
30
+ th{font-weight:600;opacity:.75;position:sticky;top:0;background:inherit}
31
+ td.n{width:56px;font:13px ui-monospace,monospace;opacity:.7}
32
+ .ok{padding:14px;border-radius:10px;background:#e8f5ec;color:#14532d;margin-top:10px}
33
+ @media(prefers-color-scheme:dark){.ok{background:#15321f;color:#bbf7d0}}
34
+ .count{font:600 13px/1 inherit;opacity:.7;margin:10px 0 2px}
35
+ .next{margin-top:18px;padding:18px 20px;border:1px solid #d8d8e0;border-radius:12px}
36
+ .next h2{font-size:1.05rem;margin:0 0 .2em}
37
+ .next p.axis{margin:.2em 0 .8em;opacity:.8;font-size:14px}
38
+ .next ul{margin:.3em 0 1em 1.1em;padding:0}
39
+ .next li{margin:.25em 0}
40
+ a.buy{display:inline-block;background:#111827;color:#fff;text-decoration:none;
41
+ padding:12px 20px;border-radius:10px;font-weight:600}
42
+ @media(prefers-color-scheme:dark){a.buy{background:#e8e8ea;color:#14141a}}
43
+ .fine{font-size:13px;opacity:.7;margin:.7em 0 0}
44
+ .faq{margin-top:34px}
45
+ .faq h3{font-size:1rem;margin:1.2em 0 .2em}
46
+ .faq p{margin:.2em 0;opacity:.85}
47
+ code{font:13px ui-monospace,Menlo,Consolas,monospace;
48
+ background:rgba(127,127,127,.14);padding:1px 5px;border-radius:4px}
49
+ </style>
50
+ <div class="wrap">
51
+ <h1>The devicetree line that compiles clean and boots wrong</h1>
52
+ <p class="sub"><code>status = "ok"</code> is not one of the five values in the Devicetree Specification v0.4
53
+ (<code>okay</code>, <code>disabled</code>, <code>reserved</code>, <code>fail</code>, <code>fail-sss</code>).
54
+ <code>dtc</code> has no opinion about it - it is just a string. Zephyr marks the node present only for the exact
55
+ value <code>okay</code>, so the sensor quietly leaves the build and you debug the driver instead of the line.
56
+ 23 rules, 50 snippets. This page runs the same 23 rules the extension runs, in your browser, on nothing you upload.</p>
57
+
58
+ <div class="grid">
59
+ <div>
60
+ <label for="src">Your file (a sample is loaded)</label>
61
+ <textarea id="src" spellcheck="false">/dts-v1/;
62
+ / {
63
+ compatible = "acme-controller";
64
+ address-cells = &lt;1>;
65
+
66
+ i2c1: i2c@40005400 {
67
+ status = "ok";
68
+ interrupt-parent = &lt;2>;
69
+ phandle = &lt;1>;
70
+
71
+ sensor@48 {
72
+ compatible = "bosch,bme280";
73
+ status = "enabled";
74
+ reg = &lt;0x48>;
75
+ };
76
+ };
77
+ };</textarea>
78
+ <button id="go">Check again</button>
79
+ <button id="clr" class="ghost">Clear</button>
80
+ </div>
81
+ <div>
82
+ <label>Findings</label>
83
+ <div id="out"></div>
84
+ </div>
85
+ </div>
86
+
87
+ <div class="next">
88
+ <h2>The whole repo, not the open file</h2>
89
+ <p class="axis">Everything above is free and needs no key, no account and no network - every one of the
90
+ 23 rules and all 50 snippets run on the file you have open, for as long as you like.
91
+ The licence buys <strong>scale, a file you can hand over, and repetition</strong>:</p>
92
+ <ul>
93
+ <li><strong>Every file in the board repo at once</strong> - one command walks the workspace and runs the same 23 rules on each file, with the paths and line numbers in one list.</li>
94
+ <li><strong>The findings as a file you can attach</strong> - written into the workspace as CSV, JSON or HTML for a review comment or a bring-up checklist.</li>
95
+ <li><strong>Re-checked on every save</strong> - a toggle; after that the findings refresh as you type and save, instead of when you remember to look.</li>
96
+ <li><strong>A fix list</strong> - the lines that have a documented correct value, counted and named so you can work down them. It reports; it does not rewrite your file.</li>
97
+ </ul>
98
+ <a class="buy" href="https://buy.polar.sh/polar_cl_CFCuxNMjv5zsartvO10MlY2XKN142StTkIxHL43Dlqa" data-polar-checkout data-polar-checkout-theme="light">Get the licence - $29</a>
99
+ <p class="fine">One-time, $29. A freelance embedded software engineer bills about $103 an hour
100
+ (contractrates.fyi, 2026); a staff embedded firmware engineer's hour averages $58.66 (ZipRecruiter, June 2026).
101
+ 7-day refund, no questions. Works offline; the key is checked once, then every 7 days.</p>
102
+ </div>
103
+
104
+ <div class="faq">
105
+ <h2>Questions</h2>
106
+ <h3>What does it actually do?</h3>
107
+ <p>It reads a config file line by line and reports the spellings that parse but do not mean what you
108
+ wrote - <code>status = "ok"</code>, a <code>compatible</code> with no comma, <code>address-cells</code>
109
+ without the <code>#</code>, an unquoted TOML <code>edition</code>. 23 rules over seven languages, plus
110
+ 50 snippets. No toolchain, no build context, no network.</p>
111
+ <h3>Do the free devicetree extensions not already do this?</h3>
112
+ <p>They highlight and complete, and inside a configured Zephyr or nRF context they resolve bindings -
113
+ that part they do better than this pack. They do not grade a bare <code>.overlay</code> pasted out of a
114
+ vendor forum, and they say nothing about the TOML, <code>.properties</code>, <code>.ahk</code>,
115
+ <code>.rpy</code> or <code>.ink</code> files sitting in the same repo.</p>
116
+ <h3>Why does an AI assistant get this wrong?</h3>
117
+ <p>Because <code>enabled</code> is the English word and every other config format in the repo uses it.
118
+ Devicetree does not: the value that turns a node on is <code>okay</code> and nothing else. It is the exact
119
+ shape of mistake that reads correct and builds clean.</p>
120
+ </div>
121
+ </div>
122
+ <script>
123
+ var RULES=[{"pattern": "status\\s*=\\s*\"ok\"", "flags": "i", "message": "status = \"ok\" is not in the Devicetree Specification v0.4 status list (\"okay\", \"disabled\", \"reserved\", \"fail\", \"fail-sss\"). Zephyr marks the node present only for the exact value \"okay\".", "fix": "status = \"okay\""}, {"pattern": "status\\s*=\\s*\"disable\"", "flags": "i", "message": "The disabled state is spelled \"disabled\". \"disable\" is not a defined status value.", "fix": "status = \"disabled\""}, {"pattern": "status\\s*=\\s*\"enabled?\"", "flags": "i", "message": "There is no \"enable\"/\"enabled\" status in devicetree. The value that turns a node on is \"okay\".", "fix": "status = \"okay\""}, {"pattern": "compatible\\s*=\\s*\"[^\",]*\"", "flags": "i", "message": "A compatible string is written \"vendor,device\". Without the comma it matches no binding and the driver never probes.", "fix": ""}, {"pattern": "^\\s*address-cells\\s*=", "flags": "im", "message": "The property is #address-cells, with the leading hash. Written without it, the parent supplies no address cell count and every child reg is read wrong.", "fix": "#address-cells ="}, {"pattern": "^\\s*[a-z][a-z0-9_-]*_[a-z0-9_-]*@[0-9a-f]+\\s*\\{", "flags": "im", "message": "Underscores in a node name are flagged by dtc -Wnode_name_chars_strict. Node names use lowercase letters, digits and hyphens; keep underscores for the label before the colon.", "fix": ""}, {"pattern": "@0x[0-9a-f]+\\s*\\{", "flags": "im", "message": "A unit address is written without the 0x prefix, for example serial@40011000. dtc compares it against the first reg cell as plain hex.", "fix": ""}, {"pattern": "interrupt-parent\\s*=\\s*<\\s*[0-9]", "flags": "i", "message": "interrupt-parent takes a phandle reference such as <&intc>. A literal number here only works if it happens to match a generated phandle value.", "fix": ""}, {"pattern": "^\\s*phandle\\s*=\\s*<", "flags": "im", "message": "dtc generates phandle values itself. Setting one by hand can collide with a generated value and silently rewire an interrupt or clock.", "fix": ""}, {"pattern": "gpios\\s*=\\s*<\\s*&[a-z0-9_]+\\s+[0-9]+\\s*>", "flags": "i", "message": "A GPIO specifier on these bindings has two cells: pin and flags, as in <&gpio0 13 GPIO_ACTIVE_LOW>. With the flags cell missing the polarity defaults and the LED or button reads inverted.", "fix": ""}, {"pattern": "^\\s*version\\s*=\\s*[0-9]+\\.[0-9]+", "flags": "im", "message": "TOML has no bare version literal. 1.0.0 is not a number, so the key must be quoted: version = \"1.0.0\".", "fix": ""}, {"pattern": "^\\s*edition\\s*=\\s*[0-9]{4}\\s*$", "flags": "im", "message": "The edition key is a string in TOML: edition = \"2021\". An unquoted year parses as an integer and the manifest is rejected.", "fix": ""}, {"pattern": "^\\s*requires-python\\s*=\\s*[^\"'\\s]", "flags": "im", "message": "PEP 621 requires-python is a quoted string: requires-python = \">=3.9\". An unquoted specifier is not valid TOML.", "fix": ""}, {"pattern": "^\\s*mp\\.jwt\\.verify\\.publickey\\.location\\s*=\\s*http:", "flags": "im", "message": "mp.jwt.verify.publickey.location is being fetched over plain http, so the verification key can be swapped in transit. Use https, classpath: or file:.", "fix": ""}, {"pattern": "^\\s*%[a-z0-9]+\\s*=", "flags": "im", "message": "A MicroProfile config profile prefix must be followed by the property name: %dev.my.property=value. On its own, %dev is not a property key.", "fix": ""}, {"pattern": "/mp-rest/(uri|baseurl|base-url)\\s*=", "flags": "i", "message": "The MicroProfile Rest Client key is /mp-rest/url. Any other spelling is ignored and the client falls back to the annotation value.", "fix": ""}, {"pattern": "^\\s*(MsgBox|SetTimer|StringReplace|WinActivate|Gui|FileAppend)\\s*,", "flags": "im", "message": "This is AutoHotkey v1 command syntax. v2 uses function calls with parentheses, for example MsgBox(\"text\") and SetTimer(callback, 1000).", "fix": ""}, {"pattern": "^\\s*#(NoEnv|Persistent|EscapeChar)\\b", "flags": "im", "message": "This directive was removed in AutoHotkey v2. #NoEnv and #EscapeChar are gone, and #Persistent became the Persistent function.", "fix": ""}, {"pattern": ":=\\s*[^%\\n]*%[a-z_][a-z0-9_]*%", "flags": "i", "message": "Percent dereferencing inside an expression was removed in AutoHotkey v2. Write the variable name on its own, or use %name% only in a double-deref such as %varName%.", "fix": ""}, {"pattern": "\\bim\\.(Scale|FactorScale|Composite|Crop|Grayscale)\\(", "flags": "i", "message": "The im.* image manipulators are deprecated in Ren'Py. Use a Transform with zoom, xysize or crop instead; im.* results are not cached the same way and cost memory on Android.", "fix": ""}, {"pattern": "^\\s*(label\\s+[a-z_][a-z0-9_]*|menu)\\s*$", "flags": "im", "message": "A Ren'Py block statement ends with a colon: label start: or menu:. Without it the parser stops on this line.", "fix": ""}, {"pattern": "\\b(try|as)!\\s", "flags": "i", "message": "try! and as! crash the process on failure. Use try?/do-catch or as? with a guard so a malformed board profile does not take the tool down.", "fix": ""}, {"pattern": "^\\s*inkling\\s+\"1\\.[0-9]+\"", "flags": "im", "message": "The Inkling 1.x version declaration is not accepted by the 2.0 toolchain. The first line must read inkling \"2.0\".", "fix": "inkling \"2.0\""}];
124
+ function scan(t){var L=String(t).split(/\r?\n/),h=[],i,k,r,re;
125
+ for(i=0;i<L.length;i++){for(k=0;k<RULES.length;k++){r=RULES[k];
126
+ try{re=new RegExp(r.pattern,r.flags||'')}catch(e){continue}
127
+ if(re.test(L[i]))h.push({line:i+1,msg:r.message,fix:r.fix||''})}}
128
+ return h}
129
+ function esc(s){return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')}
130
+ function run(){
131
+ var t=document.getElementById('src').value,o=document.getElementById('out');
132
+ if(!t.trim()){o.innerHTML='<p class="count">Nothing to check.</p>';return}
133
+ var h=scan(t);
134
+ if(!h.length){o.innerHTML='<div class="ok">No findings. This file passes all '+RULES.length+' rules.</div>';return}
135
+ var s='<p class="count">'+h.length+' finding'+(h.length===1?'':'s')+' in '+
136
+ String(t).split(/\r?\n/).length+' lines</p><table><tr><th>Line</th><th>Finding</th></tr>';
137
+ for(var i=0;i<h.length;i++){s+='<tr><td class="n">'+h[i].line+'</td><td>'+esc(h[i].msg)+
138
+ (h[i].fix?' <code>'+esc(h[i].fix)+'</code>':'')+'</td></tr>'}
139
+ o.innerHTML=s+'</table>'}
140
+ document.getElementById('go').onclick=run;
141
+ document.getElementById('clr').onclick=function(){
142
+ document.getElementById('src').value='';run()};
143
+ document.getElementById('src').addEventListener('input',run);
144
+ run();
145
+ </script>
146
  </html>
147
+
148
+
149
+ <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://www.npmjs.com/package/@readystack/devicetree-config-language-pack" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://www.npmjs.com/package/@readystack/devicetree-config-language-pack" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">MCP server (npx)</a><a href="https://hub.docker.com/r/getreadystack/devicetree-config-language-pack" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/devicetree-config-language-pack &lt;file&gt;
150
+ npx @readystack/devicetree-config-language-pack --mcp
151
+ docker run --rm -v &quot;$PWD:/w&quot; getreadystack/devicetree-config-language-pack /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://buy.polar.sh/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
152
+ <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind DeviceTree Config Audit: 23 dtc-Style Rules, 50 Snippets every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"devicetree-config-language-pack",lang:"en",source:"rule_alert"})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script></section>
153
+
154
+ <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">status = &quot;ok&quot; compiles clean and the node never appears. 23 rules over 7 config languages, on the file you have open.</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A freelance embedded software engineer bills about $103/hour (contractrates.fyi, 2026); a staff embedded firmware engineer's hour averages $58.66 in the US (ZipRecruiter, June 2026). One node silently dropped from a build costs an</p><a href="https://buy.polar.sh/polar_cl_CFCuxNMjv5zsartvO10MlY2XKN142StTkIxHL43Dlqa" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
155
+ <section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">More from ReadyStack</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Ready-to-use files. One-time download, no subscription.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/grocery-store-shopify-theme"><span class="yj-rel-t">Grocery Store Shopify Theme</span><span class="yj-rel-p">$180</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/wedding-lut-pack"><span class="yj-rel-t">Wedding LUT and Lightroom Preset Pack – 22 Looks for Prep Rooms, Church Tungst</span><span class="yj-rel-p">$100</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/content-calendar-template"><span class="yj-rel-t">Content Calendar Template with Capacity &amp; Cost Calculator for Small Content Te</span><span class="yj-rel-p">$90</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/n8n-lead-generation-template-pack"><span class="yj-rel-t">n8n Lead Generation Template Pack — 5 B2B Outbound Workflows (CAN-SPAM and GDP</span><span class="yj-rel-p">$199</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/irs-mileage-log-spreadsheet-2026"><span class="yj-rel-t">IRS Mileage Log Spreadsheet for Self-Employed Drivers 2026</span><span class="yj-rel-p">$21</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/federal-resume-template"><span class="yj-rel-t">Federal Resume Template — 6 USAJOBS-Format .docx (First Federal Job · Military</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section><!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>
156
+ <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||'')})}).catch(function(){});}catch(e){}})();</script>
157
+
158
+ <script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use'})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script>