Rename to Evergreen Applicator + SEO (title, meta, OG, JSON-LD, canonical)
This commit is contained in:
37
README.md
37
README.md
@@ -1,23 +1,25 @@
|
||||
# Pest Nocturne 🪲
|
||||
# Evergreen Applicator 🌲
|
||||
|
||||
A midnight specimen-cabinet study suite for the **WSU EM019** pest management
|
||||
certification exam. The complete *Study Manual for Pest Management
|
||||
Professionals* rebuilt as an interactive, illustrated single-page app.
|
||||
**Washington pesticide applicator exam prep** — an interactive single-page study
|
||||
suite for passing the WSDA pesticide applicator license (Core + Structural +
|
||||
Ornamental & Turf + Agricultural). Built from the *Study Manual for Pest
|
||||
Management Professionals* (WSU EM019) plus an original question bank.
|
||||
|
||||
## Live
|
||||
**https://nocturne.thetempleofdoom.com**
|
||||
**https://evergreenapplicator.thetempleofdoom.com**
|
||||
|
||||
## What's inside
|
||||
- **Field guide** — all 13 chapters with illustrated plates
|
||||
- **WA Cert** — WSDA licensing guide: exam format, fees, categories, CE requirements, printable application checklist
|
||||
- **Field guide** — all 13 chapters with real pest photos (Wikimedia, CC/PD)
|
||||
- **Identification keys** — branching keys, walked one couplet at a time
|
||||
- **House faults** — 22 points of faulty construction/maintenance, in order
|
||||
- **Flashcards** 🔒 — premium
|
||||
- **Practice exam** 🔒 — premium (scored, with the official answer key)
|
||||
- **Glossary** — every defined term, searchable as you type
|
||||
- **WA Prep** — 318 questions (249 original + 69 from the manual) with instant feedback + a timed 50-question mock exam (120 min, 70% pass)
|
||||
- **Flashcards** 🔒 / **Practice exam** 🔒 — premium
|
||||
- **Glossary** — every defined term, searchable
|
||||
|
||||
## Monetization
|
||||
Freemium: the field guide, keys, and house faults are free. **Flashcards and
|
||||
the practice exam are a $5 Bitcoin unlock** via BTCPay.
|
||||
Freemium: the field guide, keys, house faults, WA Cert, and WA Prep are free.
|
||||
**Flashcards and the practice exam are a $5 Bitcoin unlock** via BTCPay.
|
||||
|
||||
- BTCPay store: `FDT6DHWEaA7DF5WFePkp4pufgQ9yy1G6JfzTCwey1jYn`
|
||||
- Price: $5 USD (on-chain BTC)
|
||||
@@ -25,17 +27,20 @@ the practice exam are a $5 Bitcoin unlock** via BTCPay.
|
||||
|
||||
## Stack
|
||||
- Single self-contained `index.html` (vanilla JS SPA, no build step)
|
||||
- Flask (`app.py`) for the paywall + BTCPay webhook
|
||||
- Flask (`app.py`) for the paywall + BTCPay webhook (HMAC-verified)
|
||||
- nginx reverse proxy → Flask :5000
|
||||
- SQLite (`orders.db`) for order state
|
||||
|
||||
## Deploy
|
||||
- Proxmox LXC CT **117** (`nocturne`) @ 10.30.20.234
|
||||
- systemd `nocturne.service`, nginx `sites-enabled/nocturne`
|
||||
- Cloudflare tunnel `thetemple-fleet` (`1aeb1ac0`), ingress → `:80`
|
||||
- Cloudflare tunnel `thetemple-fleet` (`1aeb1ac0-3c49-4801-b61d-bc92e6e4932a`), ingress → `:80`
|
||||
|
||||
## Files
|
||||
- `index.html` — the study suite + injected paywall gate + BMAC footer
|
||||
- `app.py` — Flask backend (BTCPay invoice, webhook, unlock status)
|
||||
- `inject.py` — one-shot script that injects the paywall + footer into the HTML
|
||||
- `index.html` — the study suite (paywall gate, photos, WA Prep, BMAC footer injected)
|
||||
- `app.py` — Flask backend (BTCPay invoice, webhook, unlock status, image serving)
|
||||
- `images/` — 25 real pest photos (Wikimedia Commons)
|
||||
- `wa_exam_data.py` / `wa_exam_data2.py` — the original 249-question bank (part 2 imports part 1)
|
||||
- `rebuild_wa_prep.py` — build script for the WA Prep view + mock exam
|
||||
- `inject.py` / `integrate_photos.py` / `add_wa_view.py` / `rename.py` — one-shot build scripts
|
||||
- `nocturne.service` / `nocturne.nginx` — service + nginx config
|
||||
|
||||
167
add_features.py
Normal file
167
add_features.py
Normal file
@@ -0,0 +1,167 @@
|
||||
import io
|
||||
|
||||
p = "/Users/drjones/pest-nocturne/index.html"
|
||||
s = open(p).read()
|
||||
|
||||
# ============ 1. PROGRESS TRACKER (localStorage, per-category) ============
|
||||
# add progress state after the mock declaration
|
||||
s = s.replace(
|
||||
" let mock = { qs: [], answers: [], secs: 0, timer: null };",
|
||||
" let mock = { qs: [], answers: [], secs: 0, timer: null };\n"
|
||||
" let progress = JSON.parse(localStorage.getItem('pn_progress')||'{}');\n"
|
||||
" function saveProgress(){ localStorage.setItem('pn_progress', JSON.stringify(progress)); }\n"
|
||||
" function clearProgress(){ progress = {}; localStorage.removeItem('pn_progress'); }",
|
||||
1,
|
||||
)
|
||||
|
||||
# record progress on every practice answer
|
||||
s = s.replace(
|
||||
" if (correct) score++;\n answered++;",
|
||||
" if (correct) score++;\n answered++;\n"
|
||||
" const pc = q.cat; if (!progress[pc]) progress[pc] = {c:0, t:0};\n"
|
||||
" progress[pc].t++; if (correct) progress[pc].c++; saveProgress();",
|
||||
1,
|
||||
)
|
||||
|
||||
# progress bars UI (after the category buttons row)
|
||||
s = s.replace(
|
||||
" <div class=\"wa-cats\">${cats}</div>\n"
|
||||
" <div style=\"margin-top:14px\">",
|
||||
" <div class=\"wa-cats\">${cats}</div>\n"
|
||||
" <div class=\"wa-progress\">\n"
|
||||
" ${CATS.filter(c=>c!=='All').map(c=>{const pr=progress[c]||{c:0,t:0};const pct=pr.t?Math.round(pr.c/pr.t*100):0;return `<div class=\"wa-mrow\"><span class=\"wa-mcat\">${c}</span><div class=\"wa-mbar\"><div class=\"wa-mfill\" style=\"width:${pct}%\"></div></div><span class=\"wa-mpct\">${pr.t?pr.c+'/'+pr.t+' ('+pct+'%)':'untouched'}</span></div>`;}).join('')}\n"
|
||||
" <button class=\"wa-clear\" id=\"wa-clear\">Reset progress</button>\n"
|
||||
" </div>\n"
|
||||
" <div style=\"margin-top:14px\">",
|
||||
1,
|
||||
)
|
||||
|
||||
# wire the clear button
|
||||
s = s.replace(
|
||||
" const modeBtn = root.querySelector('#wa-mode');",
|
||||
" const clearBtn = root.querySelector('#wa-clear');\n"
|
||||
" if (clearBtn) clearBtn.addEventListener('click', ()=>{ clearProgress(); render(); });\n"
|
||||
" const modeBtn = root.querySelector('#wa-mode');",
|
||||
1,
|
||||
)
|
||||
|
||||
# progress CSS
|
||||
s = s.replace(
|
||||
".wa-cats .wac.on{",
|
||||
".wa-progress{margin-top:16px;display:flex;flex-direction:column;gap:7px;max-width:560px}\n"
|
||||
".wa-mrow{display:flex;align-items:center;gap:10px;font-size:.78rem}\n"
|
||||
".wa-mcat{width:130px;color:var(--text-dim,#A3A99C);flex-shrink:0}\n"
|
||||
".wa-mbar{flex:1;height:8px;border-radius:999px;background:var(--surface-2,#1B2239);overflow:hidden}\n"
|
||||
".wa-mfill{height:100%;background:linear-gradient(90deg,var(--brass,#E3A53F),var(--verdigris,#54BFA9));border-radius:999px;transition:width .3s}\n"
|
||||
".wa-mpct{width:120px;text-align:right;color:var(--text-dim,#A3A99C);font-family:monospace}\n"
|
||||
".wa-clear{margin-top:10px;background:none;border:1px solid var(--line,#2C3455);color:var(--text-faint,#6E7688);padding:5px 12px;border-radius:8px;cursor:pointer;font-size:.72rem;align-self:flex-start}\n"
|
||||
".wa-clear:hover{border-color:var(--crimson,#DE5F45);color:var(--crimson,#DE5F45)}\n"
|
||||
".wa-cats .wac.on{",
|
||||
1,
|
||||
)
|
||||
|
||||
# ============ 2. WSDA CHECKLIST (printable one-pager in WA Cert view) ============
|
||||
CHECKLIST = r'''
|
||||
<div class="wa-checklist">
|
||||
<div class="chk-head"><h3>License application checklist</h3><button class="btn" id="wa-print" style="padding:8px 16px;font-size:.8rem">Print / save PDF</button></div>
|
||||
<ol class="chk-list">
|
||||
<li><b>Confirm your category.</b> Structural = the commercial pest-control route; add Ornamental & Turf or Agricultural as needed. Each category = its own exam.</li>
|
||||
<li><b>Order study materials.</b> WSU Extension (<a href="https://extension.wsu.edu" target="_blank">extension.wsu.edu</a>) + the EM019 manual. The field guide, flashcards and WA Prep tab on this site cover the same ground.</li>
|
||||
<li><b>Schedule the exam</b> through WSDA at (360) 902-2020. The core (general) exam is required first; category exams after.</li>
|
||||
<li><b>Pay the fee.</b> $33 exam + $73 license. Bring ID.</li>
|
||||
<li><b>Sit the exam.</b> 50–100 multiple-choice, 120 minutes, closed book, 70% to pass.</li>
|
||||
<li><b>After passing</b> — your WSDA license is issued; renew every 5 years with 40 CEUs.</li>
|
||||
<li><b>Keep records.</b> Restricted-use pesticide applications must be recorded for 2 years.</li>
|
||||
</ol>
|
||||
<p class="chk-note">One-pager · WSDA (360) 902-2020 · agr.wa.gov · Olympia WA 98504</p>
|
||||
</div>
|
||||
<style>@media print{body *{visibility:hidden}.wa-checklist,.wa-checklist *{visibility:visible}.wa-checklist{position:absolute;left:0;top:0;width:100%;padding:20px}#wa-print{display:none}}</style>
|
||||
'''
|
||||
|
||||
# insert the checklist before the WA quick test in the v-wa render
|
||||
s = s.replace(
|
||||
" <div class=\"wa-checklist\"", # no-op guard
|
||||
" <div class=\"wa-checklist\"", # keep
|
||||
1,
|
||||
) if "wa-checklist" in s else None
|
||||
|
||||
# find the v-wa render and insert checklist before the quick test section
|
||||
anchor = '<div class="facts"'
|
||||
# Actually inject into the v-wa innerHTML — find a stable anchor inside it
|
||||
old_wa_anchor = 'WA quick test'
|
||||
if old_wa_anchor in s:
|
||||
# find the start of the WA quick test section within the v-wa render
|
||||
idx = s.find(old_wa_anchor)
|
||||
# back up to the section start
|
||||
sec = s.rfind('<section', 0, idx)
|
||||
s = s[:sec] + CHECKLIST + s[sec:]
|
||||
|
||||
# print button wiring (v-wa render is a bare innerHTML at EOF; wire via a tiny script)
|
||||
s = s.rstrip() + r'''
|
||||
<script>
|
||||
(function(){ var b=document.getElementById('wa-print'); if(b) b.addEventListener('click', function(){ window.print(); }); })();
|
||||
</script>
|
||||
'''
|
||||
|
||||
# ============ 3. DISTINGUISH-THESE-PESTS ID section ============
|
||||
DIST = r'''
|
||||
<div class="wa-dist">
|
||||
<h3>Distinguish these pests (exam favorites)</h3>
|
||||
<div class="dist-grid">
|
||||
<div class="dist-card"><h4>Ant vs. termite</h4><ul>
|
||||
<li><b>Wings</b> — ant: front pair longer than hind; termite: all four equal.</li>
|
||||
<li><b>Waist</b> — ant: pinched (narrow); termite: broad, straight-sided.</li>
|
||||
<li><b>Antennae</b> — ant: elbowed (bent); termite: straight, bead-like.</li>
|
||||
</ul></div>
|
||||
<div class="dist-card"><h4>Carpenter ant vs. moisture ant</h4><ul>
|
||||
<li><b>Thorax</b> — carpenter: smooth, evenly rounded (no notch); moisture: uneven/notched.</li>
|
||||
<li><b>Habitat</b> — carpenter: sound wood, hollows galleries; moisture: rotting, damp wood.</li>
|
||||
<li><b>Frass</b> — carpenter: coarse sawdust + dead ants; moisture: fine, mixed with soil.</li>
|
||||
</ul></div>
|
||||
<div class="dist-card"><h4>Dampwood vs. subterranean vs. drywood termite</h4><ul>
|
||||
<li><b>Dampwood</b> — largest, big dark-headed soldiers, needs moist wood, NO ground contact.</li>
|
||||
<li><b>Subterranean</b> — needs soil contact, builds mud shelter tubes.</li>
|
||||
<li><b>Drywood</b> — dry wood only, kicks out hard 6-sided pellets (no mud).</li>
|
||||
</ul></div>
|
||||
<div class="dist-card"><h4>Hobo spider vs. giant house spider</h4><ul>
|
||||
<li><b>Legs</b> — hobo: shorter, ~1.5× body; giant house: very long, ~2× body.</li>
|
||||
<li><b>Markings</b> — hobo: chevron pattern on abdomen; giant house: plainer.</li>
|
||||
<li><b>Bite</b> — hobo's "necrotic bite" is a disproven myth; neither is medically significant.</li>
|
||||
</ul></div>
|
||||
<div class="dist-card"><h4>German vs. Oriental vs. American roach</h4><ul>
|
||||
<li><b>German</b> — small (~½"), two dark stripes on pronotum, indoor, fastest breeder.</li>
|
||||
<li><b>Oriental</b> — dark, shiny, ~1", damp basements/sewers, male wings short.</li>
|
||||
<li><b>American</b> — largest (~1½"), reddish-brown, sewers/basements, can fly.</li>
|
||||
</ul></div>
|
||||
<div class="dist-card"><h4>Western black widow vs. false widow</h4><ul>
|
||||
<li><b>Hourglass</b> — widow: red hourglass on the <em>underside</em> (not the top).</li>
|
||||
<li><b>False widow</b> — brownish, no red hourglass.</li>
|
||||
<li><b>Only the female widow</b> is dangerously venomous; males are tiny and harmless.</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.wa-dist{margin-top:28px;border-top:1px solid var(--line,#2C3455);padding-top:22px}
|
||||
.wa-dist h3{font-family:Fraunces,serif;font-size:1.4rem;margin-bottom:14px}
|
||||
.dist-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px}
|
||||
.dist-card{background:var(--surface,#141A30);border:1px solid var(--line,#2C3455);border-radius:12px;padding:16px}
|
||||
.dist-card h4{color:var(--brass,#E3A53F);margin-bottom:8px;font-size:1rem}
|
||||
.dist-card ul{margin:0;padding-left:18px}
|
||||
.dist-card li{margin-bottom:6px;font-size:.88rem;line-height:1.45;color:var(--text,#EDE7D6)}
|
||||
.dist-card li b{color:var(--verdigris,#54BFA9)}
|
||||
.wa-checklist{margin-top:28px;border:1px solid var(--line,#2C3455);border-radius:14px;padding:20px;background:var(--surface,#141A30)}
|
||||
.chk-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;gap:10px}
|
||||
.chk-head h3{font-family:Fraunces,serif;font-size:1.4rem;margin:0}
|
||||
.chk-list{padding-left:20px;margin:0}
|
||||
.chk-list li{margin-bottom:8px;line-height:1.5;color:var(--text,#EDE7D6)}
|
||||
.chk-note{font-size:.78rem;color:var(--text-faint,#6E7688);margin-top:12px}
|
||||
</style>
|
||||
'''
|
||||
|
||||
# inject DIST into the v-wa render, after the checklist (or before quick test)
|
||||
if 'wa-checklist' in s and 'distinguish these pests' not in s.lower():
|
||||
# inject after the checklist block
|
||||
s = s.replace('</div>\n <style>@media print', DIST + '\n <style>@media print', 1)
|
||||
|
||||
open(p, "w").write(s)
|
||||
print("added progress tracker + WSDA checklist + ID distinctions; size", len(s))
|
||||
4
app.py
4
app.py
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# Pest Nocturne — WSU EM019 study suite, freemium paywall (BTCPay)
|
||||
# Evergreen Applicator — Washington pesticide applicator exam prep, freemium paywall (BTCPay)
|
||||
import os, json, uuid, time, sqlite3, hmac, hashlib
|
||||
from flask import Flask, request, jsonify, send_from_directory, redirect
|
||||
|
||||
@@ -32,7 +32,7 @@ def create_btcpay_invoice(order_id):
|
||||
"amount": PRICE_USD,
|
||||
"currency": "USD",
|
||||
"metadata": {"orderId": order_id},
|
||||
"checkout": {"redirectURL": f"https://nocturne.thetempleofdoom.com/?paid=1&order={order_id}"},
|
||||
"checkout": {"redirectURL": f"https://evergreenapplicator.thetempleofdoom.com/?paid=1&order={order_id}"},
|
||||
}).encode()
|
||||
req = urllib.request.Request(
|
||||
f"{BTCPAY_URL}/api/v1/stores/{BTCPAY_STORE}/invoices",
|
||||
|
||||
27
index.html
27
index.html
@@ -1,11 +1,26 @@
|
||||
<title>Pest Nocturne</title>
|
||||
<title>Evergreen Applicator — Washington Pesticide Applicator Exam Prep & Practice Tests</title>
|
||||
<meta name="description" content="Pass the Washington pesticide applicator exam. 318 original + WSU EM019 practice questions, timed 50-question mock exams, a pest ID field guide, and the WSDA licensing guide — free.">
|
||||
<meta name="keywords" content="Washington pesticide applicator exam, WA pesticide license, WSDA exam prep, pesticide applicator practice test, WDO inspection, IPM, structural pest control license, ornamental and turf license">
|
||||
<meta name="robots" content="index, follow, max-image-preview:large">
|
||||
<link rel="canonical" href="https://evergreenapplicator.thetempleofdoom.com/">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Evergreen Applicator">
|
||||
<meta property="og:title" content="Evergreen Applicator — Washington Pesticide Applicator Exam Prep">
|
||||
<meta property="og:description" content="318 practice questions, timed mock exams, pest ID field guide, and the WSDA licensing guide. Pass the WA pesticide applicator test.">
|
||||
<meta property="og:url" content="https://evergreenapplicator.thetempleofdoom.com/">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Evergreen Applicator — Washington Pesticide Applicator Exam Prep">
|
||||
<meta name="twitter:description" content="318 practice questions, mock exams, pest ID guide, and the WSDA licensing guide.">
|
||||
<script type="application/ld+json">
|
||||
{"@context":"https://schema.org","@type":"WebSite","name":"Evergreen Applicator","url":"https://evergreenapplicator.thetempleofdoom.com/","description":"Washington pesticide applicator exam prep — 318 practice questions, timed mock exams, and a pest identification field guide for the WSDA pesticide applicator license.","inLanguage":"en-US","about":{"@type":"Thing","name":"Washington pesticide applicator certification"},"publisher":{"@type":"Organization","name":"Evergreen Applicator"}}
|
||||
</script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..900;1,9..144,300..900&family=Karla:ital,wght@0,300..800;1,300..800&family=JetBrains+Mono:wght@400;600&display=swap">
|
||||
|
||||
<style>
|
||||
/* ============================================================
|
||||
PEST NOCTURNE — a midnight specimen cabinet for WSU EM019
|
||||
EVERGREEN APPLICATOR — Washington pesticide applicator exam prep
|
||||
Palette: ink ground, brass pins, verdigris, bone plates
|
||||
============================================================ */
|
||||
:root{
|
||||
@@ -342,7 +357,7 @@ mark{background:color-mix(in srgb,var(--brass) 30%,transparent); color:inherit;
|
||||
<div class="bar-in">
|
||||
<div class="mark">
|
||||
<svg class="pin" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="6" r="4" fill="currentColor"/><path d="M12 10v12" stroke="currentColor" stroke-width="1.6"/><circle cx="12" cy="6" r="1.4" fill="var(--ground)"/></svg>
|
||||
Pest Nocturne
|
||||
Evergreen Applicator
|
||||
</div>
|
||||
<nav class="tabs" id="tabs" role="tablist"></nav>
|
||||
<button class="icon-btn" id="themeBtn" title="Switch theme" aria-label="Switch theme">◐</button>
|
||||
@@ -2016,7 +2031,7 @@ $('#v-home').innerHTML=`
|
||||
<div class="hero-grid">
|
||||
<div>
|
||||
<div class="eyebrow">WSU Extension EM019 · Revised April 2021</div>
|
||||
<h1><span class="lo">A hyper study suite for the</span>Pest<br><em>Nocturne</em></h1>
|
||||
<h1><span class="lo">Washington pesticide applicator</span>Evergreen<br><em>Applicator</em></h1>
|
||||
<p class="lede">Every chapter of the <strong>Study Manual for Pest Management Professionals</strong>, rebuilt as a specimen cabinet you can open at midnight: illustrated plates, branching identification keys, a house you can pick apart point by point, ${FLASH.length} flashcards, and the manual's own ${EXAM.length}-question practice exam with the official answer key.</p>
|
||||
<div class="cta-row">
|
||||
<button class="btn" data-goto="field">Open the field guide →</button>
|
||||
@@ -2292,7 +2307,7 @@ $('#gq').addEventListener('input',e=>drawGloss(e.target.value));
|
||||
drawGloss('');
|
||||
</script>
|
||||
|
||||
<!-- ══════════════ PEST NOCTURNE — PREMIUM GATE (injected) ══════════════ -->
|
||||
<!-- ══════════════ EVERGREEN APPLICATOR — PREMIUM GATE (injected) ══════════════ -->
|
||||
<style>
|
||||
#pn-paywall{position:fixed;inset:0;z-index:99999;display:none;align-items:center;justify-content:center;
|
||||
background:rgba(5,8,16,.86);backdrop-filter:blur(6px);padding:20px;font-family:Karla,system-ui,sans-serif}
|
||||
@@ -2370,7 +2385,7 @@ drawGloss('');
|
||||
|
||||
|
||||
<div style="text-align:center;padding:26px 14px 30px;font-family:Karla,system-ui,sans-serif;color:var(--text-faint,#6E7688);font-size:.78rem;line-height:1.6">
|
||||
Pest Nocturne — a study suite for WSU EM019 · <a href="https://buymeacoffee.com/r26xrthzttg" target="_blank" rel="noopener" style="color:var(--verdigris,#54BFA9)">Buy me a coffee</a>
|
||||
Evergreen Applicator — Washington pesticide applicator exam prep · <a href="https://buymeacoffee.com/r26xrthzttg" target="_blank" rel="noopener" style="color:var(--verdigris,#54BFA9)">Buy me a coffee</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
68
rename.py
Normal file
68
rename.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import io
|
||||
|
||||
p = "/Users/drjones/pest-nocturne/index.html"
|
||||
s = open(p).read()
|
||||
|
||||
# ---- SEO head block (title + meta + OG + JSON-LD) ----
|
||||
seo_head = '''<title>Evergreen Applicator — Washington Pesticide Applicator Exam Prep & Practice Tests</title>
|
||||
<meta name="description" content="Pass the Washington pesticide applicator exam. 318 original + WSU EM019 practice questions, timed 50-question mock exams, a pest ID field guide, and the WSDA licensing guide — free.">
|
||||
<meta name="keywords" content="Washington pesticide applicator exam, WA pesticide license, WSDA exam prep, pesticide applicator practice test, WDO inspection, IPM, structural pest control license, ornamental and turf license">
|
||||
<meta name="robots" content="index, follow, max-image-preview:large">
|
||||
<link rel="canonical" href="https://evergreenapplicator.thetempleofdoom.com/">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Evergreen Applicator">
|
||||
<meta property="og:title" content="Evergreen Applicator — Washington Pesticide Applicator Exam Prep">
|
||||
<meta property="og:description" content="318 practice questions, timed mock exams, pest ID field guide, and the WSDA licensing guide. Pass the WA pesticide applicator test.">
|
||||
<meta property="og:url" content="https://evergreenapplicator.thetempleofdoom.com/">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="Evergreen Applicator — Washington Pesticide Applicator Exam Prep">
|
||||
<meta name="twitter:description" content="318 practice questions, mock exams, pest ID guide, and the WSDA licensing guide.">
|
||||
<script type="application/ld+json">
|
||||
{"@context":"https://schema.org","@type":"WebSite","name":"Evergreen Applicator","url":"https://evergreenapplicator.thetempleofdoom.com/","description":"Washington pesticide applicator exam prep — 318 practice questions, timed mock exams, and a pest identification field guide for the WSDA pesticide applicator license.","inLanguage":"en-US","about":{"@type":"Thing","name":"Washington pesticide applicator certification"},"publisher":{"@type":"Organization","name":"Evergreen Applicator"}}
|
||||
</script>'''
|
||||
|
||||
# 1. Replace the bare title with the full SEO head
|
||||
s = s.replace("<title>Pest Nocturne</title>", seo_head, 1)
|
||||
|
||||
# 2. Brand comment header
|
||||
s = s.replace(
|
||||
" PEST NOCTURNE — a midnight specimen cabinet for WSU EM019",
|
||||
" EVERGREEN APPLICATOR — Washington pesticide applicator exam prep",
|
||||
1,
|
||||
)
|
||||
|
||||
# 3. Header brand mark
|
||||
s = s.replace(
|
||||
" Pest Nocturne\n </div>",
|
||||
" Evergreen Applicator\n </div>",
|
||||
1,
|
||||
)
|
||||
|
||||
# 4. WA Cert view H1 (line ~2019) — make it keyword-rich
|
||||
s = s.replace(
|
||||
'<h1><span class="lo">A hyper study suite for the</span>Pest<br><em>Nocturne</em></h1>',
|
||||
'<h1><span class="lo">Washington pesticide applicator</span>Evergreen<br><em>Applicator</em></h1>',
|
||||
1,
|
||||
)
|
||||
|
||||
# 5. Premium gate comment
|
||||
s = s.replace(
|
||||
"PEST NOCTURNE — PREMIUM GATE (injected)",
|
||||
"EVERGREEN APPLICATOR — PREMIUM GATE (injected)",
|
||||
1,
|
||||
)
|
||||
|
||||
# 6. BMAC footer
|
||||
s = s.replace(
|
||||
"Pest Nocturne — a study suite for WSU EM019",
|
||||
"Evergreen Applicator — Washington pesticide applicator exam prep",
|
||||
1,
|
||||
)
|
||||
|
||||
open(p, "w").write(s)
|
||||
|
||||
# report any remaining "Nocturne" (case-insensitive)
|
||||
import re
|
||||
left = re.findall(r'(?i)nocturne', s)
|
||||
print("remaining 'nocturne' refs:", len(left))
|
||||
print("renamed + SEO head added; size", len(s))
|
||||
Reference in New Issue
Block a user