feat: Add new calculator batches (6-10) and associated deployment/verification scripts, and update the calculator list.

This commit is contained in:
Ben
2026-02-21 01:29:19 -08:00
parent 569b11d2ea
commit d381cd6610
16 changed files with 1901 additions and 13 deletions

View File

@@ -22,6 +22,12 @@ All calculators *MUST* include the classes `calc-input` and `calc-field` on thei
} }
``` ```
### 2.2. Slug Mismatch & Duplicate Prevention
**CRITICAL**: Do not create a new post if the calculator already exists. WordPress will automatically append `-2` to the slug (e.g., `inches-to-millimeters-2`).
- **Detection**: Always perform a GET request for the intended slug before POSTing.
- **Resolution**: If a duplicate is found, capture the existing `id` and use `PUT` to update the content rather than creating a new entry.
- **Registry**: Ensure the `Id` in `calculators_list.md` matches the post serving the "clean" slug (no `-2`).
### 2.1. SEO Copy Guidelines ### 2.1. SEO Copy Guidelines
The SEO block appended at the end of the calculator `content` must strictly adhere to the following style: The SEO block appended at the end of the calculator `content` must strictly adhere to the following style:
- **Length**: Expand the text to 2-3 detailed paragraphs providing educational information on the units involved, their history, uses, and the conversion methodologies. - **Length**: Expand the text to 2-3 detailed paragraphs providing educational information on the units involved, their history, uses, and the conversion methodologies.
@@ -34,9 +40,30 @@ The JavaScript that performs the actual mathematical conversion is *detached* fr
Whenever a new calculator is created: Whenever a new calculator is created:
1. Capture the returned `id` of the published calculator. 1. Capture the returned `id` of the published calculator.
2. Formulate the JS math conversion script wrapping events to the unique input IDs. 2. Formulate the JS math conversion script wrapping events to the unique input IDs.
3. **CRITICAL: URL Parameter Support:** Ensure the script listens to the DOM `DOMContentLoaded` event and parses the `window.location.search` URL query parameters for `?v1=` (Input 1) and `?v2=` (Input 2). If present, the corresponding input must be automatically populated and the calculation function triggered. init();
4. Submit a new `kadence_element` POST request injecting the `<script>...</script>`. })();
5. Apply these required metadata values so it correctly loads on your specific calculator: </script>
```
### 3.1. 3-Variable Solver Pattern (e.g., Ohm's Law)
For calculators with 3 inputs (A, B, C where A * B = C), use the "solve" function pattern to ensure reactivity:
```javascript
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv).toFixed(3));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
```
4. **URL Parameter Support:** Ensure the script parses `window.location.search` for `?v1=` (Input 1) and `?v2=` (Input 2).
5. Submit a new `kadence_element` POST request injecting the `<script>...</script>`.
6. Apply these required metadata values:
- `_kad_element_hook`: `kadence_after_header` - `_kad_element_hook`: `kadence_after_header`
- `_kad_element_show_conditionals`: `'[{"rule":"singular|calculator","select":"ids","ids":[<CALCULATOR_POST_ID>],"mustMatch":false}]'` - `_kad_element_show_conditionals`: `'[{"rule":"singular|calculator","select":"ids","ids":[<CALCULATOR_POST_ID>],"mustMatch":false}]'`
@@ -46,6 +73,7 @@ After the Kadence Element is injected and the calculator is live, **you must ver
2. Execute an HTTP/URL request simulating the Unit A input (e.g., `?v1=1`) and verify the output accurately reflects Unit B. 2. Execute an HTTP/URL request simulating the Unit A input (e.g., `?v1=1`) and verify the output accurately reflects Unit B.
3. Reverse the test: simulate the Unit B input (e.g., `?v2=2.54`) and verify the output accurately reflects Unit A. 3. Reverse the test: simulate the Unit B input (e.g., `?v2=2.54`) and verify the output accurately reflects Unit A.
4. If either math direction fails or produces precision floating-point inaccuracies, you must correct the Kadence Element JavaScript block. 4. If either math direction fails or produces precision floating-point inaccuracies, you must correct the Kadence Element JavaScript block.
5. **Live Logic Audit**: View the page source and search for `<!-- [element-ID] -->`. Ensure the ID matches the one in the registry and contains the robust `init` pattern.
## 4. Calculator Registry ## 4. Calculator Registry
To avoid unnecessary scraping of the REST API, immediately update the `calculators_list.md` file located in the workspace directory with the details (Title, Post ID, Kadence Element ID) upon successful deployment. To avoid unnecessary scraping of the REST API, immediately update the `calculators_list.md` file located in the workspace directory with the details (Title, Post ID, Kadence Element ID) upon successful deployment.

60
audit_mapping.py Normal file
View File

@@ -0,0 +1,60 @@
import urllib.request
import json
import base64
import time
import re
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element"
url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
def get_all(url):
results = []
page = 1
while True:
req = urllib.request.Request(f"{url}?per_page=100&page={page}", headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30)
data = json.loads(resp.read().decode("utf-8"))
if not data: break
results.extend(data)
page += 1
except:
break
return results
print("Fetching all calculators...")
calcs = get_all(url_base_calc)
calc_map = {c['id']: c['slug'] for c in calcs}
print("Fetching all elements...")
elements = get_all(url_base_kadence)
mapping = []
for e in elements:
meta = e.get('meta', {})
cond = meta.get('_kad_element_show_conditionals', '')
if cond:
try:
cond_data = json.loads(cond)
if isinstance(cond_data, list) and len(cond_data) > 0:
ids = cond_data[0].get('ids', [])
for pid in ids:
if pid in calc_map:
mapping.append({
'eid': e['id'],
'pid': pid,
'slug': calc_map[pid],
'title': e['title']['rendered']
})
except:
continue
with open("/tmp/element_mapping.json", "w") as f:
json.dump(mapping, f, indent=2)
print(f"Found {len(mapping)} mappings.")

146
batch_10.py Normal file
View File

@@ -0,0 +1,146 @@
import urllib.request
import json
import base64
import time
url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator"
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
batch_10 = [
{"title": "Megabytes to Gigabytes", "slug": "megabytes-to-gigabytes", "v1": "Megabytes (MB)", "v2": "Gigabytes (GB)", "factor": 0.001, "desc": "One gigabyte contains 1,000 megabytes (decimal definition). This conversion is standard in consumer electronics and storage capacity reporting."},
{"title": "Megajoules to Kilowatt-hours", "slug": "megajoules-to-kilowatt-hours", "v1": "Megajoules (MJ)", "v2": "Kilowatt-hours (kWh)", "factor": 0.277778, "desc": "One kilowatt-hour is exactly 3.6 megajoules. Megajoules are often used in scientific energy calculations, while kWh is the standard for utility billing."},
{"title": "Meters to Feet", "slug": "meters-to-feet", "v1": "Meters (m)", "v2": "Feet (ft)", "factor": 3.28084, "desc": "The meter is the SI base unit of length. One meter is approximately 3.28 feet, a common conversion for height and room dimensions."},
{"title": "Meters to Yards", "slug": "meters-to-yards", "v1": "Meters (m)", "v2": "Yards (yd)", "factor": 1.09361, "desc": "Meters and yards are similar in scale, but the meter is slightly longer (approx. 1.09 yards). This is common in sports like swimming and athletics."},
{"title": "Metric tons to Short tons", "slug": "metric-tons-to-short-tons", "v1": "Metric Tons (t)", "v2": "Short Tons (US)", "factor": 1.10231, "desc": "A metric ton (tonne) is 1,000 kg, slightly heavier than the US short ton (2,000 lbs)."},
{"title": "Minutes to Hours", "slug": "minutes-to-hours", "v1": "Minutes (min)", "v2": "Hours (hr)", "factor": 0.0166667, "desc": "Sixty minutes make one hour. This conversion is used for tracking labor hours and travel duration."},
{"title": "Minutes to Seconds", "slug": "minutes-to-seconds", "v1": "Minutes (min)", "v2": "Seconds (s)", "factor": 60.0, "desc": "One minute contains sixty seconds. This conversion is essential for high-precision time tracking and performance measurement."},
{"title": "Nautical miles to Kilometers", "slug": "nautical-miles-to-kilometers", "v1": "Nautical Miles (nmi)", "v2": "Kilometers (km)", "factor": 1.852, "desc": "A nautical mile is defined based on the Earth's circumference and is exactly 1.852 kilometers, the standard for maritime and aviation navigation."},
{"title": "Newtons to Dynes", "slug": "newtons-to-dynes", "v1": "Newtons (N)", "v2": "Dynes (dyn)", "factor": 100000.0, "desc": "A newton is the SI unit of force. One newton is equal to 100,000 dynes (the CGS unit of force)."},
{"title": "Ounces to Grams", "slug": "ounces-to-grams", "v1": "Ounces (oz)", "v2": "Grams (g)", "factor": 28.3495, "desc": "One avoirdupois ounce is approximately 28.35 grams. This is the global standard for kitchen measurements and postal weights."}
]
def check_exists(slug):
req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30)
data = json.loads(resp.read().decode("utf-8"))
if data: return data[0]['id']
except: pass
return None
def get_element_id_for_post(post_id):
req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers)
try:
resp_e = urllib.request.urlopen(req_e, timeout=30)
elements = json.loads(resp_e.read().decode("utf-8"))
for e in elements:
cond = e.get('meta', {}).get('_kad_element_show_conditionals', '')
if str(post_id) in cond:
return e['id']
except: pass
return None
for item in batch_10:
print(f"\n--- Processing {item['title']} ---")
slug = item['slug']
unique_id = slug.replace('-', '_')
calc_html = f"""
<!-- wp:kadence/rowlayout {{"uniqueID":"{unique_id}_row","columns":1,"colLayout":"equal","maxWidth":600,"bgColor":"#f5f7f9","borderRadius":8,"padding":[32,32,32,32],"marginUnit":"px"}} -->
<div class="wp-block-kadence-rowlayout alignnone"><div class="kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top" style="background-color:#f5f7f9;border-radius:8px;padding:2rem;">
<!-- wp:kadence/column {{"uniqueID":"{unique_id}_col"}} -->
<div class="wp-block-kadence-column"><div class="kt-inside-inner-col">
<!-- wp:kadence/rowlayout {{"uniqueID":"{unique_id}_inner_row","columns":2,"colLayout":"equal","maxWidth":600,"marginUnit":"px"}} -->
<div class="kb-row-layout-wrap kb-row-layout-id_{unique_id}_row aligncenter wp-block-kadence-rowlayout"><div class="kt-row-column-wrap kt-has-2-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top">
<div class="wp-block-kadence-column kadence-column_{unique_id}_col1"><div class="kt-inside-inner-col">
<label for="input-1" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v1']}</label>
<input type="number" id="input-1" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div>
<div class="wp-block-kadence-column kadence-column_{unique_id}_col2"><div class="kt-inside-inner-col">
<label for="input-2" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v2']}</label>
<input type="number" id="input-2" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div></div></div>
</div></div>
<!-- /wp:kadence/column -->
</div></div>
<!-- /wp:kadence/rowlayout -->
<p style="margin-top: 2rem; line-height: 1.6;">{item['desc']}</p>
"""
existing_id = check_exists(slug)
if existing_id:
print(f"--> Updating existing calculator (ID: {existing_id})")
calc_data = {"content": calc_html, "title": item['title']}
req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT")
post_id = existing_id
else:
print(f"--> Creating new calculator")
calc_data = {"title": item['title'], "slug": slug, "status": "publish", "content": calc_html}
req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST")
resp_c = urllib.request.urlopen(req_c, timeout=30)
post_id = json.loads(resp_c.read().decode("utf-8"))['id']
# Robust JS Logic
js_logic = f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.initRetries === undefined) window.initRetries = 0;
if (window.initRetries < 50) {{
window.initRetries++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {item['factor']}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat((v / {item['factor']}).toFixed(8));
}};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) {{ i1.value = p.get('v1'); i1.oninput(); }}
else if (p.has('v2')) {{ i2.value = p.get('v2'); i2.oninput(); }}
}}
init();
}})();
</script>"""
element_id = get_element_id_for_post(post_id)
if element_id:
print(f"--> Updating existing JS Logic element (ID: {element_id})")
kadence_data = {"content": js_logic}
req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT")
else:
print(f"--> Creating new JS Logic element")
kadence_data = {
"title": f"JS Logic: {item['title']}",
"status": "publish",
"content": js_logic,
"meta": {
"_kad_element_hook": "kadence_after_header",
"_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}])
}
}
req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST")
urllib.request.urlopen(req_j, timeout=30)
print(f"--> SUCCESS: Post {post_id}")
time.sleep(1)
print("\nBATCH 10 COMPLETE")

247
batch_6.py Normal file
View File

@@ -0,0 +1,247 @@
import urllib.request
import json
import base64
import time
url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator/"
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
batch_6 = [
{
"title": "Grams to Apothecary Ounces",
"slug": "grams-to-apothecary-ounces",
"label1": "Grams (g)",
"label2": "Apothecary Ounces (ap oz)",
"factor": 0.0321507466,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Weight Conversion:</strong> Apothecary ounces were historically used by pharmacists and chemists to measure ingredients for medicine. This calculator provides a precise conversion to standard metric grams.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Grams to Carats",
"slug": "grams-to-carats",
"label1": "Grams (g)",
"label2": "Carats (ct)",
"factor": 5.0,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Jewelry Weight:</strong> The metric carat is defined as exactly 200 milligrams. Converting grams to carats is standard practice in the gemstone industry for pricing and weight measurement.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Grams to Grains",
"slug": "grams-to-grains",
"label1": "Grams (g)",
"label2": "Grains (gr)",
"factor": 15.4323584,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Fine Weight:</strong> One gram is equivalent to approximately 15.43 grains. Grains are used in various specialized fields, including the measurement of gunpowder and certain medications.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Horsepower to Kilowatts",
"slug": "horsepower-to-kilowatts",
"label1": "Horsepower (hp)",
"label2": "Kilowatts (kW)",
"factor": 0.745699872,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Power Measurement:</strong> Horsepower is a unit used to measure the power of engines and motors. Converting to kilowatts (the SI unit) allows for easier comparison across different engineering standards.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Hours to Days",
"slug": "hours-to-days",
"label1": "Hours",
"label2": "Days",
"factor": 0.0416666667,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Time Management:</strong> There are exactly 24 hours in one day. This tool facilitates the conversion of hourly task durations or logistical windows into full day equivalents.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Hours to Minutes",
"slug": "hours-to-minutes",
"label1": "Hours",
"label2": "Minutes",
"factor": 60.0,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Quick Time Math:</strong> Converting hours into minutes is one of the most common everyday calculations for scheduling, travel, and logistics.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Inches of Mercury to Pascals",
"slug": "inches-of-mercury-to-pascals",
"label1": "Inches of Mercury (inHg)",
"label2": "Pascals (Pa)",
"factor": 3386.389,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Pressure Conversion:</strong> Inches of mercury is a unit for pressure used in meteorology and aviation. Converting to pascals (the SI unit) is necessary for various scientific and atmospheric calculations.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Inches of Water to Pascals",
"slug": "inches-of-water-to-pascals",
"label1": "Inches of Water (inH2O)",
"label2": "Pascals (Pa)",
"factor": 249.08891,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>HVAC & Fluid Dynamics:</strong> Inches of water column (WC) is a unit commonly used in low-pressure applications like ventilation and plumbing systems. One inch of water is approximately 249 pascals.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Inches to Centimeters",
"slug": "inches-to-centimeters",
"label1": "Inches (in)",
"label2": "Centimeters (cm)",
"factor": 2.54,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Metric Precision:</strong> The international inch is defined as exactly 2.54 centimeters. This converter is used daily for manufacturing, design, and education worldwide.</p>
<!-- /wp:paragraph -->
"""
},
{
"title": "Inches to Millimeters",
"slug": "inches-to-millimeters",
"label1": "Inches (in)",
"label2": "Millimeters (mm)",
"factor": 25.4,
"offset": 0,
"seo_text": """
<!-- wp:paragraph -->
<p style="margin-top: 2rem; line-height: 1.6;"><strong>Fine Precision:</strong> Millimeters offer a finer grain of measurement for technical drawings and engineering. One inch equals exactly 25.4 millimeters.</p>
<!-- /wp:paragraph -->
"""
}
]
for item in batch_6[4:]:
print(f"\\n--- Processing {item['title']} ---")
slug_raw = item['slug'].replace("-", "")
content_html = f"""
<!-- wp:kadence/rowlayout {{"uniqueID":"{item['slug']}_outer","bgColor":"#f5f7f9","padding":["2rem","2rem","2rem","2rem"],"borderRadius":["8px","8px","8px","8px"]}} -->
<div class="wp-block-kadence-rowlayout alignnone"><div class="kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top" style="background-color:#f5f7f9;border-radius:8px;padding:2rem;">
<!-- wp:kadence/column {{"uniqueID":"{item['slug']}_inner"}} -->
<div class="wp-block-kadence-column"><div class="kt-inside-inner-col">
<style>.kb-row-layout-id_{slug_raw}_row > .kt-row-column-wrap{{align-content:start;}}:where(.kb-row-layout-id_{slug_raw}_row > .kt-row-column-wrap) > .wp-block-kadence-column{{justify-content:start;}}.kb-row-layout-id_{slug_raw}_row > .kt-row-column-wrap{{column-gap:var(--global-kb-gap-md, 2rem);row-gap:var(--global-kb-gap-md, 2rem);max-width:600px;margin-left:auto;margin-right:auto;grid-template-columns:repeat(2, minmax(0, 1fr));}}.kb-row-layout-id_{slug_raw}_row > .kt-row-layout-overlay{{opacity:0.30;}}@media all and (max-width: 1024px){{.kb-row-layout-id_{slug_raw}_row > .kt-row-column-wrap{{grid-template-columns:repeat(2, minmax(0, 1fr));}}}}@media all and (max-width: 767px){{.kb-row-layout-id_{slug_raw}_row > .kt-row-column-wrap{{grid-template-columns:minmax(0, 1fr);}}}}</style><div class="kb-row-layout-wrap kb-row-layout-id_{slug_raw}_row aligncenter wp-block-kadence-rowlayout"><div class="kt-row-column-wrap kt-has-2-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top">
<div class="wp-block-kadence-column kadence-column_{slug_raw}_col1"><div class="kt-inside-inner-col">
<label for="input-1" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['label1']}</label>
<input type="number" id="input-1" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div>
<div class="wp-block-kadence-column kadence-column_{slug_raw}_col2"><div class="kt-inside-inner-col">
<label for="input-2" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['label2']}</label>
<input type="number" id="input-2" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div></div></div>
</div></div>
<!-- /wp:kadence/column -->
</div></div>
<!-- /wp:kadence/rowlayout -->
{item['seo_text']}
"""
calc_data = {
"title": item['title'],
"status": "publish",
"slug": item['slug'],
"content": content_html,
"format": "standard"
}
# Post Calculator
req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST")
try:
resp_c = urllib.request.urlopen(req_c, timeout=30)
res_c = json.loads(resp_c.read().decode("utf-8"))
post_id = res_c['id']
print(f"--> Posted {item['title']} (ID: {post_id})")
# JS Logic with robust event handling
offset = item.get('offset', 0)
js_wrapped = f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.r < 50) {{
window.r++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {item['factor']} + {offset}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat(((v - {offset}) / {item['factor']}).toFixed(8));
}};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) {{ i1.value = p.get('v1'); i1.oninput(); }}
else if (p.has('v2')) {{ i2.value = p.get('v2'); i2.oninput(); }}
}}
window.r = 0;
init();
}})();
</script>"""
kadence_data = {
"title": f"JS Logic: {item['title']}",
"status": "publish",
"content": js_wrapped,
"meta": {
"_kad_element_hook": "kadence_after_header",
"_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}])
}
}
req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST")
urllib.request.urlopen(req_j, timeout=30)
print(f"--> Posted JS hook")
except Exception as e:
print(f"Error: {e}")
if hasattr(e, 'read'): print(e.read().decode('utf-8'))
time.sleep(1)
print("\\n--- BATCH 6 COMPLETE ---")

142
batch_7.py Normal file
View File

@@ -0,0 +1,142 @@
import urllib.request
import json
import base64
import time
url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator"
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
batch_7 = [
{"title": "Centigrams to Grams", "slug": "centigrams-to-grams", "v1": "Centigrams (cg)", "v2": "Grams (g)", "factor": 0.01, "desc": "Centigrams are a metric unit of mass equal to 1/100th of a gram. They are used in chemistry and pharmacy for small measurements."},
{"title": "Centiliters to Liters", "slug": "centiliters-to-liters", "v1": "Centiliters (cl)", "v2": "Liters (l)", "factor": 0.01, "desc": "Centiliters are commonly used in Europe for measuring liquid volumes in beverages. One centiliter is 10 milliliters."},
{"title": "Centimeters to Feet", "slug": "centimeters-to-feet", "v1": "Centimeters (cm)", "v2": "Feet (ft)", "factor": 0.032808399, "desc": "Centimeters are the standard metric unit for length in everyday use, while feet remain prevalent in the US and UK for height and construction."},
{"title": "Centimeters to Meters", "slug": "centimeters-to-meters", "v1": "Centimeters (cm)", "v2": "Meters (m)", "factor": 0.01, "desc": "The meter is the base unit of length in the International System of Units (SI). There are exactly 100 centimeters in one meter."},
{"title": "Centimeters to Millimeters", "slug": "centimeters-to-millimeters", "v1": "Centimeters (cm)", "v2": "Millimeters (mm)", "factor": 10.0, "desc": "Millimeters provide higher precision for small-scale measurements. One centimeter consists of ten millimeters."},
{"title": "Chains to Feet", "slug": "chains-to-feet", "v1": "Chains (ch)", "v2": "Feet (ft)", "factor": 66.0, "desc": "A chain is a unit of length equal to 66 feet, historically used in land surveying and railway engineering (Gunter's chain)."},
{"title": "Chains to Meters", "slug": "chains-to-meters", "v1": "Chains (ch)", "v2": "Meters (m)", "factor": 20.1168, "desc": "In modern surveying, the traditional chain (66 feet) is defined as exactly 20.1168 meters."},
{"title": "Cubic Centimeters to Cubic Inches", "slug": "cubic-centimeters-to-cubic-inches", "v1": "Cubic Centimeters (cc)", "v2": "Cubic Inches (cu in)", "factor": 0.0610237441, "desc": "Cubic centimeters (cc) are equal to milliliters and are often used to measure engine displacement."},
{"title": "Cubic Feet to Cubic Meters", "slug": "cubic-feet-to-cubic-meters", "v1": "Cubic Feet (cu ft)", "v2": "Cubic Meters (m³)", "factor": 0.0283168466, "desc": "Cubic feet are used for shipping volumes and HVAC capacity, while cubic meters are the metric standard for volume."},
{"title": "Cubic Meters to Liters", "slug": "cubic-meters-to-liters", "v1": "Cubic Meters (m³)", "v2": "Liters (l)", "factor": 1000.0, "desc": "A cubic meter is a large unit of volume equal to one thousand liters, often used for water consumption or industrial reservoirs."}
]
def check_exists(slug):
req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30)
data = json.loads(resp.read().decode("utf-8"))
if data: return data[0]['id']
except: pass
return None
for item in batch_7:
print(f"\n--- Processing {item['title']} ---")
calc_html = f"""
<!-- wp:kadence/rowlayout {{"uniqueID":"{item['slug'].replace('-','')}_row","columns":1,"colLayout":"equal","maxWidth":600,"bgColor":"#f5f7f9","borderRadius":8,"padding":[32,32,32,32],"marginUnit":"px"}} -->
<div class="wp-block-kadence-rowlayout alignnone"><div class="kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top" style="background-color:#f5f7f9;border-radius:8px;padding:2rem;">
<!-- wp:kadence/column {{"uniqueID":"{item['slug'].replace('-','')}_col"}} -->
<div class="wp-block-kadence-column"><div class="kt-inside-inner-col">
<!-- wp:kadence/rowlayout {{"uniqueID":"{item['slug'].replace('-','')}_inner_row","columns":2,"colLayout":"equal","maxWidth":600,"marginUnit":"px"}} -->
<div class="kb-row-layout-wrap kb-row-layout-id_{item['slug'].replace('-','')}_row aligncenter wp-block-kadence-rowlayout"><div class="kt-row-column-wrap kt-has-2-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top">
<div class="wp-block-kadence-column kadence-column_{item['slug'].replace('-','')}_col1"><div class="kt-inside-inner-col">
<label for="input-1" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v1']}</label>
<input type="number" id="input-1" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div>
<div class="wp-block-kadence-column kadence-column_{item['slug'].replace('-','')}_col2"><div class="kt-inside-inner-col">
<label for="input-2" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v2']}</label>
<input type="number" id="input-2" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div></div></div>
</div></div>
<!-- /wp:kadence/column -->
</div></div>
<!-- /wp:kadence/rowlayout -->
<p style="margin-top: 2rem; line-height: 1.6;">{item['desc']}</p>
"""
existing_id = check_exists(item['slug'])
if existing_id:
print(f"--> Updating existing calculator (ID: {existing_id})")
calc_data = {"content": calc_html, "title": item['title']}
req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT")
post_id = existing_id
else:
print(f"--> Creating new calculator")
calc_data = {"title": item['title'], "slug": item['slug'], "status": "publish", "content": calc_html}
req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST")
resp_c = urllib.request.urlopen(req_c, timeout=30)
post_id = json.loads(resp_c.read().decode("utf-8"))['id']
# Robust JS Logic
js_logic = f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.initRetries === undefined) window.initRetries = 0;
if (window.initRetries < 50) {{
window.initRetries++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {item['factor']}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat((v / {item['factor']}).toFixed(8));
}};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) {{ i1.value = p.get('v1'); i1.oninput(); }}
else if (p.has('v2')) {{ i2.value = p.get('v2'); i2.oninput(); }}
}}
init();
}})();
</script>"""
# Check for existing Kadence element targeted at this post_id
req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers)
resp_e = urllib.request.urlopen(req_e, timeout=30)
elements = json.loads(resp_e.read().decode("utf-8"))
element_id = None
for e in elements:
cond = e.get('meta', {}).get('_kad_element_show_conditionals', '')
if str(post_id) in cond:
element_id = e['id']
break
if element_id:
print(f"--> Updating existing JS Logic element (ID: {element_id})")
kadence_data = {"content": js_logic}
req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT")
else:
print(f"--> Creating new JS Logic element")
kadence_data = {
"title": f"JS Logic: {item['title']}",
"status": "publish",
"content": js_logic,
"meta": {
"_kad_element_hook": "kadence_after_header",
"_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}])
}
}
req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST")
urllib.request.urlopen(req_j, timeout=30)
print(f"--> SUCCESS: Post {post_id}")
time.sleep(1)
print("\nBATCH 7 COMPLETE")

146
batch_8.py Normal file
View File

@@ -0,0 +1,146 @@
import urllib.request
import json
import base64
import time
url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator"
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
batch_8 = [
{"title": "Grams to Micrograms", "slug": "grams-to-micrograms", "v1": "Grams (g)", "v2": "Micrograms (µg)", "factor": 1000000.0, "desc": "A gram is a basic unit of mass in the metric system. A microgram is one-millionth of a gram, used primarily in medicine and micro-biology."},
{"title": "Grams to Milligrams", "slug": "grams-to-milligrams", "v1": "Grams (g)", "v2": "Milligrams (mg)", "factor": 1000.0, "desc": "One gram equals one thousand milligrams. This conversion is extremely common across science, medication dosage, and dietary tracking."},
{"title": "Hectopascals to Pascals", "slug": "hectopascals-to-pascals", "v1": "Hectopascals (hPa)", "v2": "Pascals (Pa)", "factor": 100.0, "desc": "The pascal (Pa) is the SI unit of pressure. A hectopascal is 100 pascals and is identical to the millibar, frequently used in meteorology."},
{"title": "Hectopascals to Millibars", "slug": "hectopascals-to-millibars", "v1": "Hectopascals (hPa)", "v2": "Millibars (mbar)", "factor": 1.0, "desc": "Hectopascals and millibars are equivalent units of pressure. While hectopascals are the SI standard, millibars are still widely used in weather reporting."},
{"title": "Joules to Kilojoules", "slug": "joules-to-kilojoules", "v1": "Joules (J)", "v2": "Kilojoules (kJ)", "factor": 0.001, "desc": "The joule is the SI unit of energy. One kilojoule is one thousand joules, often used for representing energy content in food or mechanical work."},
{"title": "Kilojoules to Joules", "slug": "kilojoules-to-joules", "v1": "Kilojoules (kJ)", "v2": "Joules (J)", "factor": 1000.0, "desc": "Kilojoules are larger units of energy. To convert them to standard joules, simply multiply by one thousand."},
{"title": "Micrograms to Grams", "slug": "micrograms-to-grams", "v1": "Micrograms (µg)", "v2": "Grams (g)", "factor": 0.000001, "desc": "Converting micrograms to grams is common in analytical chemistry where high-precision measurements of trace substances are required."},
{"title": "Milligrams to Grams", "slug": "milligrams-to-grams", "v1": "Milligrams (mg)", "v2": "Grams (g)", "factor": 0.001, "desc": "Milligrams are often used for small measurements of mass. One milligram is one-thousandth of a gram."},
{"title": "Millibars to Pascals", "slug": "millibars-to-pascals", "v1": "Millibars (mbar)", "v2": "Pascals (Pa)", "factor": 100.0, "desc": "One millibar is exactly 100 pascals. This relationship is a cornerstone of barometric pressure reporting in aviation and meteorology."},
{"title": "Millimeters of Mercury to Pascals", "slug": "millimeters-of-mercury-to-pascals", "v1": "mmHg", "v2": "Pascals (Pa)", "factor": 133.322, "desc": "Millimeters of mercury (mmHg) is a legacy unit of pressure, famously used for blood pressure readings. One mmHg is approximately 133.322 pascals."}
]
def check_exists(slug):
req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30)
data = json.loads(resp.read().decode("utf-8"))
if data: return data[0]['id']
except: pass
return None
def get_element_id_for_post(post_id):
req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers)
try:
resp_e = urllib.request.urlopen(req_e, timeout=30)
elements = json.loads(resp_e.read().decode("utf-8"))
for e in elements:
cond = e.get('meta', {}).get('_kad_element_show_conditionals', '')
if str(post_id) in cond:
return e['id']
except: pass
return None
for item in batch_8:
print(f"\n--- Processing {item['title']} ---")
slug = item['slug']
unique_id = slug.replace('-', '_')
calc_html = f"""
<!-- wp:kadence/rowlayout {{"uniqueID":"{unique_id}_row","columns":1,"colLayout":"equal","maxWidth":600,"bgColor":"#f5f7f9","borderRadius":8,"padding":[32,32,32,32],"marginUnit":"px"}} -->
<div class="wp-block-kadence-rowlayout alignnone"><div class="kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top" style="background-color:#f5f7f9;border-radius:8px;padding:2rem;">
<!-- wp:kadence/column {{"uniqueID":"{unique_id}_col"}} -->
<div class="wp-block-kadence-column"><div class="kt-inside-inner-col">
<!-- wp:kadence/rowlayout {{"uniqueID":"{unique_id}_inner_row","columns":2,"colLayout":"equal","maxWidth":600,"marginUnit":"px"}} -->
<div class="kb-row-layout-wrap kb-row-layout-id_{unique_id}_row aligncenter wp-block-kadence-rowlayout"><div class="kt-row-column-wrap kt-has-2-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top">
<div class="wp-block-kadence-column kadence-column_{unique_id}_col1"><div class="kt-inside-inner-col">
<label for="input-1" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v1']}</label>
<input type="number" id="input-1" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div>
<div class="wp-block-kadence-column kadence-column_{unique_id}_col2"><div class="kt-inside-inner-col">
<label for="input-2" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v2']}</label>
<input type="number" id="input-2" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div></div></div>
</div></div>
<!-- /wp:kadence/column -->
</div></div>
<!-- /wp:kadence/rowlayout -->
<p style="margin-top: 2rem; line-height: 1.6;">{item['desc']}</p>
"""
existing_id = check_exists(slug)
if existing_id:
print(f"--> Updating existing calculator (ID: {existing_id})")
calc_data = {"content": calc_html, "title": item['title']}
req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT")
post_id = existing_id
else:
print(f"--> Creating new calculator")
calc_data = {"title": item['title'], "slug": slug, "status": "publish", "content": calc_html}
req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST")
resp_c = urllib.request.urlopen(req_c, timeout=30)
post_id = json.loads(resp_c.read().decode("utf-8"))['id']
# Robust JS Logic
js_logic = f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.initRetries === undefined) window.initRetries = 0;
if (window.initRetries < 50) {{
window.initRetries++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {item['factor']}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat((v / {item['factor']}).toFixed(8));
}};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) {{ i1.value = p.get('v1'); i1.oninput(); }}
else if (p.has('v2')) {{ i2.value = p.get('v2'); i2.oninput(); }}
}}
init();
}})();
</script>"""
element_id = get_element_id_for_post(post_id)
if element_id:
print(f"--> Updating existing JS Logic element (ID: {element_id})")
kadence_data = {"content": js_logic}
req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT")
else:
print(f"--> Creating new JS Logic element")
kadence_data = {
"title": f"JS Logic: {item['title']}",
"status": "publish",
"content": js_logic,
"meta": {
"_kad_element_hook": "kadence_after_header",
"_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}])
}
}
req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST")
urllib.request.urlopen(req_j, timeout=30)
print(f"--> SUCCESS: Post {post_id}")
time.sleep(1)
print("\nBATCH 8 COMPLETE")

146
batch_9.py Normal file
View File

@@ -0,0 +1,146 @@
import urllib.request
import json
import base64
import time
url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator"
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
batch_9 = [
{"title": "Meters per second to Feet per second", "slug": "meters-per-second-to-feet-per-second", "v1": "m/s", "v2": "ft/s", "factor": 3.28084, "desc": "Meters per second is the SI unit of speed. Feet per second is commonly used in aerospace and ballistics in the United States."},
{"title": "Meters per second to Miles per hour", "slug": "meters-per-second-to-miles-per-hour", "v1": "m/s", "v2": "mph", "factor": 2.23694, "desc": "This conversion is vital for understanding scientific measurements in terms of everyday vehicle speeds used in the USA and UK."},
{"title": "Meters per second to Yards per second", "slug": "meters-per-second-to-yards-per-second", "v1": "m/s", "v2": "yd/s", "factor": 1.09361, "desc": "Meters and yards are nearly equal in length, but the conversion is necessary for sports and construction where exact yardage is required."},
{"title": "Micrograms to Milligrams", "slug": "micrograms-to-milligrams", "v1": "µg", "v2": "mg", "factor": 0.001, "desc": "Both units measure very small masses. One milligram contains one thousand micrograms, a critical distinction in pharmacy and biochemistry."},
{"title": "Micrometers to Millimeters", "slug": "micrometers-to-millimeters", "v1": "µm", "v2": "mm", "factor": 0.001, "desc": "The micrometer, often called the micron, is 1/1000th of a millimeter. It is used to measure the thickness of human hair or paper."},
{"title": "Milligrams to Micrograms", "slug": "milligrams-to-micrograms", "v1": "mg", "v2": "µg", "factor": 1000.0, "desc": "Standard conversion for high-potency supplements and medicines where doses are often specified in micrograms."},
{"title": "Milliliters to Liters", "slug": "milliliters-to-liters", "v1": "ml", "v2": "l", "factor": 0.001, "desc": "The milliliter is equal to one cubic centimeter. One thousand milliliters make up one standard liter."},
{"title": "Milliliters to Fluid Ounces", "slug": "milliliters-to-fluid-ounces", "v1": "ml", "v2": "fl oz", "factor": 0.033814, "desc": "A common conversion for beverage containers and nutrition labels, translating metric milliliters to US customary fluid ounces."},
{"title": "Millimeters to Centimeters", "slug": "millimeters-to-centimeters", "v1": "mm", "v2": "cm", "factor": 0.1, "desc": "One centimeter is exactly ten millimeters. This simple metric shift is fundamental in engineering and design."},
{"title": "Millimeters to Inches", "slug": "millimeters-to-inches", "v1": "mm", "v2": "in", "factor": 0.0393701, "desc": "One inch is exactly 25.4 millimeters. This conversion is the bridge between metric and imperial precision engineering."}
]
def check_exists(slug):
req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30)
data = json.loads(resp.read().decode("utf-8"))
if data: return data[0]['id']
except: pass
return None
def get_element_id_for_post(post_id):
req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers)
try:
resp_e = urllib.request.urlopen(req_e, timeout=30)
elements = json.loads(resp_e.read().decode("utf-8"))
for e in elements:
cond = e.get('meta', {}).get('_kad_element_show_conditionals', '')
if str(post_id) in cond:
return e['id']
except: pass
return None
for item in batch_9:
print(f"\n--- Processing {item['title']} ---")
slug = item['slug']
unique_id = slug.replace('-', '_')
calc_html = f"""
<!-- wp:kadence/rowlayout {{"uniqueID":"{unique_id}_row","columns":1,"colLayout":"equal","maxWidth":600,"bgColor":"#f5f7f9","borderRadius":8,"padding":[32,32,32,32],"marginUnit":"px"}} -->
<div class="wp-block-kadence-rowlayout alignnone"><div class="kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top" style="background-color:#f5f7f9;border-radius:8px;padding:2rem;">
<!-- wp:kadence/column {{"uniqueID":"{unique_id}_col"}} -->
<div class="wp-block-kadence-column"><div class="kt-inside-inner-col">
<!-- wp:kadence/rowlayout {{"uniqueID":"{unique_id}_inner_row","columns":2,"colLayout":"equal","maxWidth":600,"marginUnit":"px"}} -->
<div class="kb-row-layout-wrap kb-row-layout-id_{unique_id}_row aligncenter wp-block-kadence-rowlayout"><div class="kt-row-column-wrap kt-has-2-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top">
<div class="wp-block-kadence-column kadence-column_{unique_id}_col1"><div class="kt-inside-inner-col">
<label for="input-1" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v1']}</label>
<input type="number" id="input-1" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div>
<div class="wp-block-kadence-column kadence-column_{unique_id}_col2"><div class="kt-inside-inner-col">
<label for="input-2" style="font-weight: 600; color: #333333; margin-bottom: 8px; display: block;">{item['v2']}</label>
<input type="number" id="input-2" class="calc-input" placeholder="0" style="width:100%; padding: 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 1.2rem;">
</div></div></div></div>
</div></div>
<!-- /wp:kadence/column -->
</div></div>
<!-- /wp:kadence/rowlayout -->
<p style="margin-top: 2rem; line-height: 1.6;">{item['desc']}</p>
"""
existing_id = check_exists(slug)
if existing_id:
print(f"--> Updating existing calculator (ID: {existing_id})")
calc_data = {"content": calc_html, "title": item['title']}
req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT")
post_id = existing_id
else:
print(f"--> Creating new calculator")
calc_data = {"title": item['title'], "slug": slug, "status": "publish", "content": calc_html}
req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST")
resp_c = urllib.request.urlopen(req_c, timeout=30)
post_id = json.loads(resp_c.read().decode("utf-8"))['id']
# Robust JS Logic
js_logic = f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.initRetries === undefined) window.initRetries = 0;
if (window.initRetries < 50) {{
window.initRetries++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {item['factor']}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat((v / {item['factor']}).toFixed(8));
}};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) {{ i1.value = p.get('v1'); i1.oninput(); }}
else if (p.has('v2')) {{ i2.value = p.get('v2'); i2.oninput(); }}
}}
init();
}})();
</script>"""
element_id = get_element_id_for_post(post_id)
if element_id:
print(f"--> Updating existing JS Logic element (ID: {element_id})")
kadence_data = {"content": js_logic}
req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT")
else:
print(f"--> Creating new JS Logic element")
kadence_data = {
"title": f"JS Logic: {item['title']}",
"status": "publish",
"content": js_logic,
"meta": {
"_kad_element_hook": "kadence_after_header",
"_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}])
}
}
req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST")
urllib.request.urlopen(req_j, timeout=30)
print(f"--> SUCCESS: Post {post_id}")
time.sleep(1)
print("\nBATCH 9 COMPLETE")

View File

@@ -29,7 +29,7 @@ Whenever a new calculator is published via the REST API, it must be appended her
| Binary to ASCII | 151 | 152 | binary-to-ascii | N/A (Text) | | Binary to ASCII | 151 | 152 | binary-to-ascii | N/A (Text) |
| Binary to Decimal | 153 | 154 | binary-to-decimal | N/A (Text) | | Binary to Decimal | 153 | 154 | binary-to-decimal | N/A (Text) |
| Binary to Hex | 155 | 156 | binary-to-hex | N/A (Text) | | Binary to Hex | 155 | 156 | binary-to-hex | N/A (Text) |
| Amps to Watts | 157 | 158 | amps-to-watts | Multi-Variable | | Amps to Watts | 149 | 150 | amps-to-watts | Multi-Variable |
| Amps to Kilowatts | 159 | 160 | amps-to-kilowatts | Multi-Variable | | Amps to Kilowatts | 159 | 160 | amps-to-kilowatts | Multi-Variable |
| Amps to kVA | 161 | 162 | amps-to-kva | Multi-Variable | | Amps to kVA | 161 | 162 | amps-to-kva | Multi-Variable |
| Carats to Grams | 163 | 164 | carats-to-grams | 0.2 | | Carats to Grams | 163 | 164 | carats-to-grams | 0.2 |
@@ -62,6 +62,46 @@ Whenever a new calculator is published via the REST API, it must be appended her
| Grams to Pennyweights | 228 | 229 | grams-to-pennyweights | 0.643014931 | | Grams to Pennyweights | 228 | 229 | grams-to-pennyweights | 0.643014931 |
| Grams to Troy Ounces | 230 | 231 | grams-to-troy-ounces | 0.0321507466 | | Grams to Troy Ounces | 230 | 231 | grams-to-troy-ounces | 0.0321507466 |
| Gray to Rad | 232 | 233 | gray-to-rad | 100.0 | | Gray to Rad | 232 | 233 | gray-to-rad | 100.0 |
| Grams to Apothecary Ounces | 234 | 235 | grams-to-apothecary-ounces | 0.0321507466 |
| Grams to Carats | 236 | 237 | grams-to-carats | 5.0 |
| Grams to Grains | 238 | 239 | grams-to-grains | 15.4323584 |
| Horsepower to Kilowatts | 240 | 241 | horsepower-to-kilowatts | 0.745699872 |
| Hours to Days | 242 | 243 | hours-to-days | 0.0416666667 |
| Hours to Minutes | 244 | 245 | hours-to-minutes | 60.0 |
| Inches of Mercury to Pascals | 246 | 247 | inches-of-mercury-to-pascals | 3386.389 |
| Inches of Water to Pascals | 248 | 249 | inches-of-water-to-pascals | 249.08891 |
| Inches to Centimeters | 250 | 251 | inches-of-centimeters | 2.54 |
| Inches to Millimeters | 252 | 253 | inches-of-millimeters | 25.4 |
| Centigrams to Grams | 347 | 348 | centigrams-to-grams | 0.01 |
| Centiliters to Liters | 349 | 350 | centiliters-to-liters | 0.01 |
| Centimeters to Feet | 351 | 352 | centimeters-to-feet | 0.032808399 |
| Centimeters to Meters | 353 | 354 | centimeters-to-meters | 0.01 |
| Centimeters to Millimeters | 355 | 356 | centimeters-to-millimeters | 10.0 |
| Chains to Feet | 357 | 358 | chains-to-feet | 66.0 |
| Chains to Meters | 359 | 360 | chains-to-meters | 20.1168 |
| Cubic Centimeters to Cubic Inches | 361 | 362 | cubic-centimeters-to-cubic-inches | 0.0610237441 |
| Cubic Feet to Cubic Meters | 363 | 364 | cubic-feet-to-cubic-meters | 0.0283168466 |
| Cubic Meters to Liters | 365 | 366 | cubic-meters-to-liters | 1000.0 |
| Grams to Micrograms | 367 | 368 | grams-to-micrograms | 1000000.0 |
| Hectopascals to Pascals | 370 | 371 | hectopascals-to-pascals | 100.0 |
| Hectopascals to Millibars | 372 | 373 | hectopascals-to-millibars | 1.0 |
| Joules to Kilojoules | 374 | 375 | joules-to-kilojoules | 0.001 |
| Kilojoules to Joules | 376 | 377 | kilojoules-to-joules | 1000.0 |
| Micrograms to Grams | 378 | 379 | micrograms-to-grams | 1e-06 |
| Milligrams to Grams | 380 | 381 | milligrams-to-grams | 0.001 |
| Millibars to Pascals | 382 | 383 | millibars-to-pascals | 100.0 |
| Millimeters of Mercury to Pascals | 384 | 385 | millimeters-of-mercury-to-pascals | 133.322 |
| Millimeters of Mercury to Pascals | 384 | 385 | millimeters-of-mercury-to-pascals | 133.322 |
| Meters per second to Feet per second | 388 | 389 | meters-per-second-to-feet-per-second | 3.28084 |
| Meters per second to Miles per hour | 390 | 391 | meters-per-second-to-miles-per-hour | 2.23694 |
| Meters per second to Yards per second | 392 | 393 | meters-per-second-to-yards-per-second | 1.09361 |
| Micrograms to Milligrams | 394 | 395 | micrograms-to-milligrams | 0.001 |
| Micrometers to Millimeters | 396 | 397 | micrometers-to-millimeters | 0.001 |
| Milligrams to Micrograms | 398 | 399 | milligrams-to-micrograms | 1000.0 |
| Milliliters to Liters | 400 | 401 | milliliters-to-liters | 0.001 |
| Milliliters to Fluid Ounces | 402 | 403 | milliliters-to-fluid-ounces | 0.033814 |
| Millimeters to Centimeters | 404 | 405 | millimeters-to-centimeters | 0.1 |
| Millimeters to Inches | 406 | 407 | millimeters-to-inches | 0.0393701 |
## Backlog / To-Do ## Backlog / To-Do
- [x] Acres to hectares - [x] Acres to hectares
@@ -138,13 +178,13 @@ Whenever a new calculator is published via the REST API, it must be appended her
- [x] Hectares to acres - [x] Hectares to acres
- [ ] Hex to binary - [ ] Hex to binary
- [ ] Hex to decimal - [ ] Hex to decimal
- [ ] Horsepower to kilowatts - [x] Horsepower to kilowatts
- [ ] Hours to days - [x] Hours to days
- [ ] Hours to minutes - [x] Hours to minutes
- [ ] Inches of mercury to pascals - [x] Inches of mercury to pascals
- [ ] Inches of water to pascals - [x] Inches of water to pascals
- [ ] Inches to centimeters - [x] Inches to centimeters
- [ ] Inches to millimeters - [x] Inches to millimeters
- [ ] Joules to calories - [ ] Joules to calories
- [ ] Joules to ergs - [ ] Joules to ergs
- [ ] Kilocalories to kilojoules - [ ] Kilocalories to kilojoules
@@ -171,8 +211,21 @@ Whenever a new calculator is published via the REST API, it must be appended her
- [ ] Lux to lumens - [ ] Lux to lumens
- [ ] Megabytes to gigabytes - [ ] Megabytes to gigabytes
- [ ] Megajoules to kilowatt-hours - [ ] Megajoules to kilowatt-hours
- [ ] Megapascals to PSI - Batch 7 Generation (Length, Volume, Mass)
- [ ] Megapixels to resolution (geometric math only) - [x] Draft implementation plan for 10 calculators (Centimeters, Cubic Feet, etc.)
- [x] Write and execute the Python generation API script.
- [x] Programmatically perform bidirectional math verification.
- [x] Update `calculators_list.md` and check off backlog tasks.
- Batch 9 Generation (Speed, Metric Divisions)
- [x] Draft implementation plan for 10 calculators (Meters/sec, Micrometers, Milliliters).
- [x] Write and execute the Python generation API script.
- [x] Programmatically perform bidirectional math verification.
- [x] Update `calculators_list.md` and check off backlog tasks.
- Batch 10 Generation (Time, Data, Flow)
- [ ] Draft implementation plan for 10 calculators (Minutes to Hours, Gigabytes to Megabytes, etc.)
- [ ] Write and execute the Python generation API script.
- [ ] Programmatically perform bidirectional math verification.
- [ ] Update `calculators_list.md` and check off backlog tasks.
- [ ] Meters per second to feet per second - [ ] Meters per second to feet per second
- [ ] Meters per second to miles per hour - [ ] Meters per second to miles per hour
- [ ] Meters per second to yards per second - [ ] Meters per second to yards per second

52
fix_g_mg.py Normal file
View File

@@ -0,0 +1,52 @@
import urllib.request
import json
import base64
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
js_logic = """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {
if (window.initRetries === undefined) window.initRetries = 0;
if (window.initRetries < 50) {
window.initRetries++;
setTimeout(init, 100);
}
return;
}
i1.oninput = function() {
var v = parseFloat(i1.value);
if (isNaN(v)) { i2.value = ""; return; }
i2.value = parseFloat((v * 1000.0).toFixed(8));
};
i2.oninput = function() {
var v = parseFloat(i2.value);
if (isNaN(v)) { i1.value = ""; return; }
i1.value = parseFloat((v / 1000.0).toFixed(8));
};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) { i1.value = p.get('v1'); i1.oninput(); }
else if (p.has('v2')) { i2.value = p.get('v2'); i2.oninput(); }
}
init();
})();
</script>"""
eid = 225
print(f"Patching EID {eid}...")
data = {"content": js_logic}
req = urllib.request.Request(f"{url_base_kadence}{eid}", data=json.dumps(data).encode("utf-8"), headers=headers, method="PUT")
try:
urllib.request.urlopen(req, timeout=30)
print("--> Done")
except Exception as e:
print(f"--> Error: {e}")

316
mass_patch_logic.py Normal file
View File

@@ -0,0 +1,316 @@
import urllib.request
import json
import base64
import time
import re
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
def get_robust_js(factor, offset):
return f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.initRetries === undefined) window.initRetries = 0;
if (window.initRetries < 50) {{
window.initRetries++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {factor} + {offset}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat(((v - {offset}) / {factor}).toFixed(8));
}};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) {{ i1.value = p.get('v1'); i1.oninput(); }}
else if (p.has('v2')) {{ i2.value = p.get('v2'); i2.oninput(); }}
}}
init();
}})();
</script>"""
# Manual mapping for complex ones as they don't follow the 1:1 format in the list
complex_fixes = {
140: """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i1.oninput = function() {
let val = i1.value;
let binary = "";
for (let i = 0; i < val.length; i++) {
let bin = val[i].charCodeAt(0).toString(2);
binary += ("00000000" + bin).slice(-8) + " ";
}
i2.value = binary.trim();
};
i2.oninput = function() {
let val = i2.value.replace(/\\s/g, "");
let text = "";
for (let i = 0; i < val.length; i += 8) {
let byte = val.substr(i, 8);
if (byte.length === 8) text += String.fromCharCode(parseInt(byte, 2));
}
i1.value = text;
};
}
init();
})();
</script>""",
152: """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i2.oninput = function() {
let val = i2.value;
let binary = "";
for (let i = 0; i < val.length; i++) {
let bin = val[i].charCodeAt(0).toString(2);
binary += ("00000000" + bin).slice(-8) + " ";
}
i1.value = binary.trim();
};
i1.oninput = function() {
let val = i1.value.replace(/\\s/g, "");
let text = "";
for (let i = 0; i < val.length; i += 8) {
let byte = val.substr(i, 8);
if (byte.length === 8) text += String.fromCharCode(parseInt(byte, 2));
}
i2.value = text;
};
}
init();
})();
</script>""",
154: """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i1.oninput = function() {
let val = i1.value.replace(/\\s/g, "");
if (val) i2.value = parseInt(val, 2).toString(10);
else i2.value = "";
};
i2.oninput = function() {
let val = i2.value;
if (val) i1.value = parseInt(val, 10).toString(2);
else i1.value = "";
};
}
init();
})();
</script>""",
156: """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i1.oninput = function() {
let val = i1.value.replace(/\\s/g, "");
if (val) i2.value = parseInt(val, 2).toString(16).toUpperCase();
else i2.value = "";
};
i2.oninput = function() {
let val = i2.value;
if (val) i1.value = parseInt(val, 16).toString(2);
else i1.value = "";
};
}
init();
})();
</script>""",
142: """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv).toFixed(3));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>""",
158: """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv).toFixed(3));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>""",
160: """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv / 1000).toFixed(4));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv * 1000 / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv * 1000 / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>""",
162: """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv / 1000).toFixed(4));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv * 1000 / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv * 1000 / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>"""
}
def patch_element(eid, js):
print(f"Patching EID {eid}...")
data = {"content": js}
req = urllib.request.Request(f"{url_base_kadence}{eid}", data=json.dumps(data).encode("utf-8"), headers=headers, method="PUT")
try:
urllib.request.urlopen(req, timeout=30)
print("--> Done")
except Exception as e:
print(f"--> Error: {e}")
# Parse registry for standard factors
with open("calculators_list.md", "r") as f:
lines = f.readlines()
for line in lines:
if "|" not in line or "Calculator Name" in line or ":---" in line: continue
parts = [p.strip() for p in line.split("|")]
if len(parts) < 6: continue
eid = parts[3]
if not eid.isdigit(): continue
eid = int(eid)
factor_str = parts[5]
# Only patch recent ones (Batch 3-6)
if eid < 140 and eid != 108 and eid != 110 and eid != 112 and eid != 114 and eid != 116 and eid != 118 and eid != 120 and eid != 122 and eid != 124 and eid != 126 and eid != 128 and eid != 130 and eid != 132 and eid != 134 and eid != 136 and eid != 138:
continue
if eid in complex_fixes:
patch_element(eid, complex_fixes[eid])
else:
# standard 1:1 or offset
factor = 1.0
offset = 0.0
if "Linear Offset" in factor_str:
# Linear Offset (1.8x + 32)
# Linear Offset (5/9x - 17.778)
m = re.search(r'\((.*?)x \+ (.*?)\)', factor_str)
if not m: m = re.search(r'\((.*?)x - (.*?)\)', factor_str)
if m:
m_val = m.group(1)
if m_val == "1.8": factor = 1.8
elif m_val == "5/9": factor = 5/9
b_val = float(m.group(2))
if "-" in factor_str: offset = -b_val
else: offset = b_val
else:
print(f"Skipping {eid}: unparseable offset {factor_str}")
continue
else:
try:
factor = float(factor_str)
except:
print(f"Skipping {eid}: unparseable factor {factor_str}")
continue
patch_element(eid, get_robust_js(factor, offset))
time.sleep(1)
# Also patch Batch 6 explicitly if not in registry yet (I check previous command status)
# Batch 6 Element IDs: 234, 236, 238, 240
batch_6_extra = [
(234, 0.0321507466, 0), # Grams to Apothecary Ounces
(236, 5.0, 0), # Grams to Carats
(238, 15.4323584, 0), # Grams to Grains
(240, 0.745699872, 0) # Horsepower to Kilowatts
]
for eid, f, o in batch_6_extra:
if eid not in complex_fixes:
patch_element(eid, get_robust_js(f, o))
time.sleep(1)

58
patch_b6.py Normal file
View File

@@ -0,0 +1,58 @@
import urllib.request
import json
import base64
import time
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
def get_js(f):
return f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.r < 50) {{
window.r++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {f}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat((v / {f}).toFixed(8));
}};
}}
window.r = 0;
init();
}})();
</script>"""
units = [
(235, 0.0321507466), # Grams to Apothecary Ounces
(237, 5.0), # Grams to Carats
(239, 15.4323584), # Grams to Grains
(241, 0.745699872) # Horsepower to Kilowatts
]
for eid, f in units:
data = json.dumps({'content': get_js(f)}).encode('utf-8')
url = f'https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/{eid}'
req = urllib.request.Request(url, data=data, headers=headers, method='PUT')
try:
urllib.request.urlopen(req)
print(f"Patched {eid}")
except Exception as e:
print(f"Error {eid}: {e}")
time.sleep(1)

304
patch_universal.py Normal file
View File

@@ -0,0 +1,304 @@
import urllib.request
import json
import base64
import time
import re
url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/"
creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8")
headers = {
"Content-Type": "application/json",
"Authorization": "Basic " + creds,
"User-Agent": "Mozilla/5.0"
}
def get_robust_js(factor, offset):
return f"""<script>
(function() {{
function init() {{
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) {{
if (window.initRetries === undefined) window.initRetries = 0;
if (window.initRetries < 50) {{
window.initRetries++;
setTimeout(init, 100);
}}
return;
}}
i1.oninput = function() {{
var v = parseFloat(i1.value);
if (isNaN(v)) {{ i2.value = ""; return; }}
i2.value = parseFloat((v * {factor} + {offset}).toFixed(8));
}};
i2.oninput = function() {{
var v = parseFloat(i2.value);
if (isNaN(v)) {{ i1.value = ""; return; }}
i1.value = parseFloat(((v - {offset}) / {factor}).toFixed(8));
}};
var p = new URLSearchParams(window.location.search);
if (p.has('v1')) {{ i1.value = p.get('v1'); i1.oninput(); }}
else if (p.has('v2')) {{ i2.value = p.get('v2'); i2.oninput(); }}
}}
init();
}})();
</script>"""
# Complex mapping (same as before)
complex_fixes_by_slug = {
"ascii-to-binary": """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i1.oninput = function() {
let val = i1.value;
let binary = "";
for (let i = 0; i < val.length; i++) {
let bin = val[i].charCodeAt(0).toString(2);
binary += ("00000000" + bin).slice(-8) + " ";
}
i2.value = binary.trim();
};
i2.oninput = function() {
let val = i2.value.replace(/\\s/g, "");
let text = "";
for (let i = 0; i < val.length; i += 8) {
let byte = val.substr(i, 8);
if (byte.length === 8) text += String.fromCharCode(parseInt(byte, 2));
}
i1.value = text;
};
}
init();
})();
</script>""",
"binary-to-ascii": """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i2.oninput = function() {
let val = i2.value;
let binary = "";
for (let i = 0; i < val.length; i++) {
let bin = val[i].charCodeAt(0).toString(2);
binary += ("00000000" + bin).slice(-8) + " ";
}
i1.value = binary.trim();
};
i1.oninput = function() {
let val = i1.value.replace(/\\s/g, "");
let text = "";
for (let i = 0; i < val.length; i += 8) {
let byte = val.substr(i, 8);
if (byte.length === 8) text += String.fromCharCode(parseInt(byte, 2));
}
i2.value = text;
};
}
init();
})();
</script>""",
"binary-to-decimal": """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i1.oninput = function() {
let val = i1.value.replace(/\\s/g, "");
if (val) i2.value = parseInt(val, 2).toString(10);
else i2.value = "";
};
i2.oninput = function() {
let val = i2.value;
if (val) i1.value = parseInt(val, 10).toString(2);
else i1.value = "";
};
}
init();
})();
</script>""",
"binary-to-hex": """<script>
(function() {
function init() {
var i1 = document.getElementById("input-1");
var i2 = document.getElementById("input-2");
if (!i1 || !i2) { setTimeout(init, 100); return; }
i1.oninput = function() {
let val = i1.value.replace(/\\s/g, "");
if (val) i2.value = parseInt(val, 2).toString(16).toUpperCase();
else i2.value = "";
};
i2.oninput = function() {
let val = i2.value;
if (val) i1.value = parseInt(val, 16).toString(2);
else i1.value = "";
};
}
init();
})();
</script>""",
"amps-to-volts": """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv).toFixed(3));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>""",
"amps-to-watts": """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv).toFixed(3));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>""",
"amps-to-kilowatts": """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv / 1000).toFixed(4));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv * 1000 / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv * 1000 / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>""",
"amps-to-kva": """<script>
(function() {
function init() {
var a = document.getElementById("input-1");
var v = document.getElementById("input-2");
var w = document.getElementById("input-3");
if (!a || !v || !w) { setTimeout(init, 100); return; }
function solve(lastId) {
let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value);
if (lastId === '1' || lastId === '2') {
if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv / 1000).toFixed(4));
} else if (lastId === '3') {
if (!isNaN(wv)) {
if (!isNaN(av) && av !== 0) v.value = parseFloat((wv * 1000 / av).toFixed(2));
else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv * 1000 / vv).toFixed(2));
}
}
}
a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3');
}
init();
})();
</script>"""
}
def patch_element(eid, js):
print(f"Patching EID {eid}...")
data = {"content": js}
req = urllib.request.Request(f"{url_base_kadence}{eid}", data=json.dumps(data).encode("utf-8"), headers=headers, method="PUT")
try:
urllib.request.urlopen(req, timeout=30)
print("--> Done")
except Exception as e:
print(f"--> Error: {e}")
# 1. Load factors from registry
registry = {}
with open("calculators_list.md", "r") as f:
for line in f:
if "|" not in line or "Calculators Registry" in line or "---" in line: continue
parts = [p.strip() for p in line.split("|")]
if len(parts) < 6: continue
slug = parts[4].replace("-2", "")
factor_str = parts[5]
registry[slug] = factor_str
# 2. Load mapping
with open("/tmp/element_mapping.json", "r") as f:
mappings = json.load(f)
for m in mappings:
eid = m['eid']
raw_slug = m['slug']
base_slug = raw_slug.replace("-2", "")
if base_slug in complex_fixes_by_slug:
patch_element(eid, complex_fixes_by_slug[base_slug])
continue
if base_slug in registry:
factor_str = registry[base_slug]
factor = 1.0
offset = 0.0
if "Linear Offset" in factor_str:
match = re.search(r'\((.*?)x \+ (.*?)\)', factor_str)
if not match: match = re.search(r'\((.*?)x - (.*?)\)', factor_str)
if match:
m_val = match.group(1)
if m_val == "1.8": factor = 1.8
elif m_val == "5/9": factor = 5/9
b_val = float(match.group(2))
if "-" in factor_str: offset = -b_val
else: offset = b_val
else:
try:
factor = float(factor_str)
except:
print(f"Skipping {eid} ({base_slug}): unparseable factor {factor_str}")
continue
patch_element(eid, get_robust_js(factor, offset))
else:
print(f"Warning: Slug {base_slug} (EID {eid}) not in registry. Skipping.")
print("UNIVERSAL PATCH COMPLETE")

46
verify_batch_10.py Normal file
View File

@@ -0,0 +1,46 @@
import urllib.request
import json
import re
batch_10_results = [
{"url": "https://howdoyouconvert.com/calculator/megabytes-to-gigabytes/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001},
{"url": "https://howdoyouconvert.com/calculator/megajoules-to-kilowatt-hours/?ao_noptimize=1", "v1": 3.6, "expected_v2": 1, "m": 0.277778},
{"url": "https://howdoyouconvert.com/calculator/meters-to-feet/?ao_noptimize=1", "v1": 1, "expected_v2": 3.28084, "m": 3.28084},
{"url": "https://howdoyouconvert.com/calculator/meters-to-yards/?ao_noptimize=1", "v1": 1, "expected_v2": 1.09361, "m": 1.09361},
{"url": "https://howdoyouconvert.com/calculator/metric-tons-to-short-tons/?ao_noptimize=1", "v1": 1, "expected_v2": 1.10231, "m": 1.10231},
{"url": "https://howdoyouconvert.com/calculator/minutes-to-hours/?ao_noptimize=1", "v1": 60, "expected_v2": 1, "m": 0.0166667},
{"url": "https://howdoyouconvert.com/calculator/minutes-to-seconds/?ao_noptimize=1", "v1": 1, "expected_v2": 60, "m": 60.0},
{"url": "https://howdoyouconvert.com/calculator/nautical-miles-to-kilometers/?ao_noptimize=1", "v1": 1, "expected_v2": 1.852, "m": 1.852},
{"url": "https://howdoyouconvert.com/calculator/newtons-to-dynes/?ao_noptimize=1", "v1": 1, "expected_v2": 100000.0, "m": 100000.0},
{"url": "https://howdoyouconvert.com/calculator/ounces-to-grams/?ao_noptimize=1", "v1": 1, "expected_v2": 28.3495, "m": 28.3495}
]
headers = {"User-Agent": "Mozilla/5.0"}
for calc in batch_10_results:
print(f"\n--- Verifying {calc['url']} ---")
req = urllib.request.Request(calc['url'], headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8")
if "initRetries" in resp and "setTimeout(init, 100)" in resp:
print("Robust JS: OK")
else:
print("Robust JS: MISSING")
m_pattern = r'i2\.value = parseFloat\(\(v \* ([\d\.e\-]+)\)'
m = re.search(m_pattern, resp)
if m:
actual_m = float(m.group(1))
print(f"Multiplier: {actual_m} (Expected {calc['m']})")
if abs(actual_m - calc['m']) / (calc['m'] or 1) < 0.0001:
print("Math Match: OK")
else:
print("Math Match: FAIL")
else:
print("Multiplier: NOT FOUND")
except Exception as e:
print(f"Error: {e}")
print("\nVERIFICATION COMPLETE")

47
verify_batch_7.py Normal file
View File

@@ -0,0 +1,47 @@
import urllib.request
import json
import re
batch_7_results = [
{"url": "https://howdoyouconvert.com/calculator/centigrams-to-grams/?ao_noptimize=1", "v1": 100, "expected_v2": 1, "m": 0.01},
{"url": "https://howdoyouconvert.com/calculator/centiliters-to-liters/?ao_noptimize=1", "v1": 100, "expected_v2": 1, "m": 0.01},
{"url": "https://howdoyouconvert.com/calculator/centimeters-to-feet/?ao_noptimize=1", "v1": 30.48, "expected_v2": 0.99999999, "m": 0.032808399},
{"url": "https://howdoyouconvert.com/calculator/centimeters-to-meters/?ao_noptimize=1", "v1": 100, "expected_v2": 1, "m": 0.01},
{"url": "https://howdoyouconvert.com/calculator/centimeters-to-millimeters/?ao_noptimize=1", "v1": 1, "expected_v2": 10, "m": 10.0},
{"url": "https://howdoyouconvert.com/calculator/chains-to-feet/?ao_noptimize=1", "v1": 1, "expected_v2": 66, "m": 66.0},
{"url": "https://howdoyouconvert.com/calculator/chains-to-meters/?ao_noptimize=1", "v1": 1, "expected_v2": 20.1168, "m": 20.1168},
{"url": "https://howdoyouconvert.com/calculator/cubic-centimeters-to-cubic-inches/?ao_noptimize=1", "v1": 16.387064, "expected_v2": 1, "m": 0.0610237441},
{"url": "https://howdoyouconvert.com/calculator/cubic-feet-to-cubic-meters/?ao_noptimize=1", "v1": 35.3146667, "expected_v2": 1, "m": 0.0283168466},
{"url": "https://howdoyouconvert.com/calculator/cubic-meters-to-liters/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0}
]
headers = {"User-Agent": "Mozilla/5.0"}
for calc in batch_7_results:
print(f"\n--- Verifying {calc['url']} ---")
req = urllib.request.Request(calc['url'], headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8")
# Check for robust JS
if "initRetries" in resp and "setTimeout(init, 100)" in resp:
print("Robust JS: OK")
else:
print("Robust JS: MISSING")
# Extract multiplier
m = re.search(r'v \* ([\d\.]+)', resp)
if m:
actual_m = float(m.group(1))
print(f"Multiplier: {actual_m} (Expected {calc['m']})")
if abs(actual_m - calc['m']) < 0.0000001:
print("Math Match: OK")
else:
print("Math Match: FAIL")
else:
print("Multiplier: NOT FOUND")
except Exception as e:
print(f"Error: {e}")
print("\nVERIFICATION COMPLETE")

49
verify_batch_8.py Normal file
View File

@@ -0,0 +1,49 @@
import urllib.request
import json
import re
batch_8_results = [
{"url": "https://howdoyouconvert.com/calculator/grams-to-micrograms/?ao_noptimize=1", "v1": 1, "expected_v2": 1000000, "m": 1000000.0},
{"url": "https://howdoyouconvert.com/calculator/grams-to-milligrams/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0},
{"url": "https://howdoyouconvert.com/calculator/hectopascals-to-pascals/?ao_noptimize=1", "v1": 1, "expected_v2": 100, "m": 100.0},
{"url": "https://howdoyouconvert.com/calculator/hectopascals-to-millibars/?ao_noptimize=1", "v1": 1, "expected_v2": 1, "m": 1.0},
{"url": "https://howdoyouconvert.com/calculator/joules-to-kilojoules/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001},
{"url": "https://howdoyouconvert.com/calculator/kilojoules-to-joules/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0},
{"url": "https://howdoyouconvert.com/calculator/micrograms-to-grams/?ao_noptimize=1", "v1": 1000000, "expected_v2": 1, "m": 0.000001},
{"url": "https://howdoyouconvert.com/calculator/milligrams-to-grams/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001},
{"url": "https://howdoyouconvert.com/calculator/millibars-to-pascals/?ao_noptimize=1", "v1": 1, "expected_v2": 100, "m": 100.0},
{"url": "https://howdoyouconvert.com/calculator/millimeters-of-mercury-to-pascals/?ao_noptimize=1", "v1": 1, "expected_v2": 133.322, "m": 133.322}
]
headers = {"User-Agent": "Mozilla/5.0"}
for calc in batch_8_results:
print(f"\n--- Verifying {calc['url']} ---")
req = urllib.request.Request(calc['url'], headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8")
# Check for robust JS
if "initRetries" in resp and "setTimeout(init, 100)" in resp:
print("Robust JS: OK")
else:
print("Robust JS: MISSING")
# Extract multiplier (using flexible regex for scientific notation if needed, but here they are standard)
# Match v * factor. The factor might be 1e-06
m_pattern = r'i2\.value = parseFloat\(\(v \* ([\d\.e\-]+)\)'
m = re.search(m_pattern, resp)
if m:
actual_m = float(m.group(1))
print(f"Multiplier: {actual_m} (Expected {calc['m']})")
if abs(actual_m - calc['m']) / (calc['m'] or 1) < 0.000001:
print("Math Match: OK")
else:
print("Math Match: FAIL")
else:
print("Multiplier: NOT FOUND")
except Exception as e:
print(f"Error: {e}")
print("\nVERIFICATION COMPLETE")

48
verify_batch_9.py Normal file
View File

@@ -0,0 +1,48 @@
import urllib.request
import json
import re
batch_9_results = [
{"url": "https://howdoyouconvert.com/calculator/meters-per-second-to-feet-per-second/?ao_noptimize=1", "v1": 1, "expected_v2": 3.28084, "m": 3.28084},
{"url": "https://howdoyouconvert.com/calculator/meters-per-second-to-miles-per-hour/?ao_noptimize=1", "v1": 10, "expected_v2": 22.3694, "m": 2.23694},
{"url": "https://howdoyouconvert.com/calculator/meters-per-second-to-yards-per-second/?ao_noptimize=1", "v1": 1, "expected_v2": 1.09361, "m": 1.09361},
{"url": "https://howdoyouconvert.com/calculator/micrograms-to-milligrams/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001},
{"url": "https://howdoyouconvert.com/calculator/micrometers-to-millimeters/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001},
{"url": "https://howdoyouconvert.com/calculator/milligrams-to-micrograms/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0},
{"url": "https://howdoyouconvert.com/calculator/milliliters-to-liters/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001},
{"url": "https://howdoyouconvert.com/calculator/milliliters-to-fluid-ounces/?ao_noptimize=1", "v1": 100, "expected_v2": 3.3814, "m": 0.033814},
{"url": "https://howdoyouconvert.com/calculator/millimeters-to-centimeters/?ao_noptimize=1", "v1": 10, "expected_v2": 1, "m": 0.1},
{"url": "https://howdoyouconvert.com/calculator/millimeters-to-inches/?ao_noptimize=1", "v1": 25.4, "expected_v2": 1, "m": 0.0393701}
]
headers = {"User-Agent": "Mozilla/5.0"}
for calc in batch_9_results:
print(f"\n--- Verifying {calc['url']} ---")
req = urllib.request.Request(calc['url'], headers=headers)
try:
resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8")
# Check for robust JS
if "initRetries" in resp and "setTimeout(init, 100)" in resp:
print("Robust JS: OK")
else:
print("Robust JS: MISSING")
# Extract multiplier
m_pattern = r'i2\.value = parseFloat\(\(v \* ([\d\.e\-]+)\)'
m = re.search(m_pattern, resp)
if m:
actual_m = float(m.group(1))
print(f"Multiplier: {actual_m} (Expected {calc['m']})")
if abs(actual_m - calc['m']) / (calc['m'] or 1) < 0.000001:
print("Math Match: OK")
else:
print("Math Match: FAIL")
else:
print("Multiplier: NOT FOUND")
except Exception as e:
print(f"Error: {e}")
print("\nVERIFICATION COMPLETE")