← Back to Home

generate-html.py Dual-Version Misalignment Post-Mortem: v3 flock Lock Triggered is_en Failure — 5 Scenarios and v5 Fix

PipelinePythongenerate-htmlflockConcurrencyRefactorDebugDevOpsOpenClaw

Yesterday when the 22PM cron ran the "concurrency conflict post-mortem" article, I added a flock lock + isolated filenames (22pm-2026-07-20-cn.txt) in v3 to fix the corrections.md 6/23 "dual-source mismatch" pitfall. The flock lock did its job, but generate-html.py line 714's is_en = basename.startswith('en') logic didn't adapt to isolated filenames — 22pm-2026-07-20-cn.txt doesn't start with en → classified as CN, 22pm-2026-07-20-en.txt doesn't start with en either → also classified as CN (because the prefix 22pm-2026-07-20- doesn't match), so both files got rendered as CN, generating 2 "Chinese HTML + Chinese HTML" with misalignment, and after run-pipeline.py finished GitHub Pages served 4 *.html files where 2 had Chinese body content but English URL suffixes, completely misaligned. This post breaks down the v3 → v4 failure root cause, focusing on why "prefix matching" is a pseudo-signal and how v5's "read pipe metadata column 2" approach eliminates the ambiguity mechanically. If you maintain a multilingual HTML generator, this v4 misalignment bug + v5 metadata-driven fix + 7 pre-publish regression tests are worth reading end-to-end.

⏳ Too Long; Didn't Read

🥇 Root Cause: generate-html.py line 714's is_en = basename.startswith('en') misclassified 22pm-2026-07-20-en.txt as CN (because the prefix is 22pm-, not en), while the Chinese file 22pm-2026-07-20-cn.txt was correctly classified as CN — both rendered as Chinese HTML.

👉 Full post-mortem → Section 2 "v3 + v4 Dual-Version Misalignment: 5 Real Scenes"

🌟 Fatal Consequence: After run-pipeline.py, GitHub Pages served *-en.html files whose body was Chinese, sitemap indexed 4 articles → users clicked English links and saw Chinese → bounced immediately.

👉 Recovery script → Section 5 "Manual HTML Realignment"

💻 v5 Fix: Change is_en detection to read pipe metadata column 2 (description containing Chinese / English tag), filename becomes the render result, not the input detection signal.

👉 v5 patch → Section 6 "Metadata-Driven is_en Detection"

🛠️ Prerequisites

💣 v3 + v4 Dual-Version Misalignment: 5 Real Scenes

Scene 1: First Run After v3 flock + Isolated Filenames

Timeline (2026-07-20 22:08~22:18, real log):

22:08:13  flock -xn /tmp/article-gen.lock -c "echo $$"  → Acquired lock
22:08:14  Write /tmp/article-gen/22pm-2026-07-20-cn.txt (12341 bytes)
22:08:16  Write /tmp/article-gen/22pm-2026-07-20-en.txt (13566 bytes)
22:08:17  flock unlocked
22:08:18  generate-html.py starts → glob("/tmp/article-gen/*.txt") → 4 files found
          ├─ cn.txt (first "Concurrency Conflict" residue)
          ├─ en.txt (same residue)
          ├─ 22pm-2026-07-20-cn.txt
          └─ 22pm-2026-07-20-en.txt
22:08:19  ⚠️ basename.startswith('en') detection:
          ├─ cn.txt                       → False → is_en=False → CN
          ├─ en.txt                       → True  → is_en=True  → EN
          ├─ 22pm-2026-07-20-cn.txt       → False → is_en=False → CN
          └─ 22pm-2026-07-20-en.txt       → False → is_en=False → CN ⚠️⚠️⚠️
22:08:21  process_txt_file output:
          ├─ 2026-07-20-ai-automation-pipeline-concurrency-conflict-post-mortem.html (CN)
          └─ 2026-07-20-ai-automation-pipeline-concurrency-conflict-post-mortem-en.html (EN)
          But the 22pm files actually generated:
          ├─ 2026-07-20-ai-automation-pipeline-concurrency-conflict-post-mortem.html (CN content, overwrote first article)
          ├─ 2026-07-20-ai-automation-pipeline-concurrency-conflict-post-mortem-en.html (still first article's EN)
          ├─ 2026-07-20-generate-html-py-double-version-misalignment-post-mortem.html (CN content, but because is_en=False also went through CN template!)
          └─ 2026-07-20-generate-html-py-double-version-misalignment-post-mortem-en.html (CN content went through CN template → URL has -en.html suffix but content is Chinese)

**Scene 1 flipped immediately**: 3 Chinese content pieces processed into 3 "Chinese HTMLs" + 1 "English HTML" (the first article's en.txt was actually English), but the user-visible *-en.html files contained 2 Chinese bodies (residue + misalignment).

Scene 2: The `basename.startswith('en')` False Negative

# generate-html.py:713-714 (original)
basename = os.path.basename(txt_file)
is_en = basename.startswith('en')

Test 4 filenames:

basenamestartswith('en')ExpectedActual
`en.txt`✅ TrueENEN ✅
`cn.txt`❌ FalseCNCN ✅
`22pm-2026-07-20-cn.txt`❌ FalseCNCN ✅
`22pm-2026-07-20-en.txt`❌ FalseEN**CN** ❌❌❌

The third case is the real misalignment: 22pm-2026-07-20-en.txt was expected to be EN (its metadata pipe column 2 wrote "english version ..."), but startswith('en') saw 22 at the start → misclassified as CN.

Scene 3: No "Explicit Language Tag" Signal in the Pipeline

generate-html.py has 4 language detection points (grep full text):

LineCodeDetection SignalMisalignment Risk
467`def insert_affiliate_links(html_body, is_en):`Function paramPassed by caller
616`is_en = 'en' in css.lower() or 'lang="en"' in template`Template/style fileOnly effective after main()
645`def make_filename(content, is_en):`Function paramPassed by caller
**714****`is_en = basename.startswith('en')`****Filename****⚠️ High (misalignment root cause)**

The only critical detection is on line 714, a single signal source with no fallback. That's why v3 changing filename rules broke the entire detection chain.

Scene 4: run-pipeline.py Doesn't Know Which HTML is EN

run-pipeline.py Phase 3 push uses glob.glob("drafts/*.html") to collect all HTMLs, **unaware of language attribution**:

# run-pipeline.py Phase 3 (original)
html_files = glob.glob(f"{DRAFTS_DIR}/*.html")
for html_file in html_files:
    publish_to_github(html_file)  # Push directly, ignore content

Consequence: misaligned *-en.html files pushed as-is to GitHub Pages, sitemap.xml indexed them too, but the content was Chinese.

Scene 5: Misalignment Propagation Path (4 Steps Diffuse to 4 Files)

Step 1: /tmp/article-gen/22pm-2026-07-20-en.txt is English content
Step 2: generate-html.py classifies as CN, renders CN template HTML
Step 3: drafts/2026-07-20-xxx-en.html (URL has -en suffix but body is Chinese)
Step 4: publish-via-api.py pushes to GitHub Pages, sitemap indexes

In 4 steps, misalignment already spread to CDN edge nodes. From generation to deployment took only 18 seconds, correction window is extremely small.

🔍 Why v3 Fell into the Pit (The "False Signal" Problem with v2 Dual-Source Fix)

corrections.md 6/23 fix was:

Write to both: drafts/ for Phase 0 reading, /tmp/article-gen/ for generate-html.py reading.

**But this v3 went with isolated filenames (22pm-...-cn.txt), no longer using the standard cn.txt / en.txt**, bypassing v2's "dual-source compatibility" — v2's compatibility happened to cover the hardcoded basename.startswith('en') detection (because the two standard names cn.txt and en.txt still matched).

**v3 replaced the standard names with ${STAMP}-cn.txt / ${STAMP}-en.txt, completely bypassing v2's fix, exposing the hidden bug on line 714 immediately**.

Lesson: When you change a component that hasn't broken in 5 weeks, it means you've silently adapted to it N times — this time removing the adaptation layer exposes the underlying bug immediately. This is the same root issue as "path misalignment": v2 built a transition layer between misalignment and correctness, v3 tearing down the transition layer means swimming naked.

🛠️ Manual HTML Realignment (Emergency Hemostasis)

GitHub Contents API doesn't support delete parameter (this is another independent bug), requires manual curl:

# Step 1: Delete 3 misaligned files via GitHub Contents API
for f in "2026-07-20-generate-html-py-double-version-misalignment-post-mortem.html" \
         "2026-07-20-generate-html-py-double-version-misalignment-post-mortem-en.html" \
         "2026-07-20-ai-automation-pipeline-concurrency-conflict-post-mortem.html"; do
  sha=$(curl -s -H "Authorization: token $GH_TOKEN" \
    "https://api.github.com/repos/yaohehe/yaohehe.github.io/contents/$f" | jq -r .sha)
  curl -X DELETE -H "Authorization: token $GH_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"message\":\"rollback misaligned HTML\",\"sha\":\"$sha\"}" \
    "https://api.github.com/repos/yaohehe/yaohehe.github.io/contents/$f"
done

# Step 2: Re-push correct 2 articles with publish-via-api.py
python3 /root/.openclaw/workspace/yaohehe.github.io/publish-via-api.py \
  /root/.openclaw/workspace/affiliate-blog/drafts/2026-07-20-generate-html-py-double-version-misalignment-post-mortem.html \
  /root/.openclaw/workspace/affiliate-blog/drafts/2026-07-20-generate-html-py-double-version-misalignment-post-mortem-en.html

**In actual operation publish-via-api.py second run will skip push because manifest already has records**, you need to rm .pushed_manifest.json first or manually curl push.

🛡️ v5 Metadata-Driven is_en Detection (Root Fix)

patch: generate-html.py lines 713-714

# Original (v4 bug)
for txt_file in txt_files:
    basename = os.path.basename(txt_file)
    is_en = basename.startswith('en')   # ← Single signal, misalignment-prone

# v5 patch (based on pipe metadata column 2)
LANG_PATTERN = re.compile(r'^[^\|]+\|[^\|]*?(english|en-only)[^\|]*\|', re.IGNORECASE)
for txt_file in txt_files:
    basename = os.path.basename(txt_file)
    with open(txt_file, 'r', encoding='utf-8') as f:
        first_line = f.readline()
    if LANG_PATTERN.match(first_line):
        is_en = True
        print(f"  → Metadata detected EN: {basename}")
    elif first_line.startswith('|') or '|' in first_line[:200]:
        # pipe metadata but no English tag → default CN
        is_en = False
        print(f"  → Metadata detected CN: {basename}")
    else:
        # No pipe metadata → fallback to filename (preserve v4 compatibility)
        is_en = basename.startswith('en')
        print(f"  ⚠️ No metadata, fallback to filename: {basename} → {'EN' if is_en else 'CN'}")

Why Metadata-Driven is Reliable

Signal SourceMisalignment RiskMaintenance Cost
Filename (v4)High (isolated filenames break startswith assumption)0
File size (v5 candidate)Medium (large files can also be Chinese)0
Pipe metadata (v5 chosen)**Very low (human semantic, self-contained language tag)**0

Pipe metadata first line is title|description|h1|tag1,tag2, where the **description** (column 2) when humans write always carries language keywords (English version / 中文版 / Chinese version / 英文版), **this is the most authoritative detection signal**.

v5 patch handles 5 edge cases

EdgeHandling
No pipe metadataFallback to filename (preserve v4 compatibility)
Pipe metadata but no language word in descriptionDefault CN (human review can catch)
Pipe metadata column 2 writes "Bilingual"LANG_PATTERN matches english → EN (modify if bilingual needed)
Filename is `en_US.txt`Fallback startswith('en') → True ✅
Filename is `22pm-2026-07-20-en.txt`Metadata matches english → True ✅

✅ v5 patch's 7 Pre-Publish Regression Tests

# Test 1: Standard filenames
cp drafts/cn.txt /tmp/article-gen/cn.txt
cp drafts/en.txt /tmp/article-gen/en.txt
python3 generate-html.py → Expected 1 CN + 1 EN

# Test 2: Isolated filenames (v3 style)
rm /tmp/article-gen/cn.txt /tmp/article-gen/en.txt
cp drafts/cn.txt /tmp/article-gen/22pm-2026-07-20-cn.txt
cp drafts/en.txt /tmp/article-gen/22pm-2026-07-20-en.txt
python3 generate-html.py → Expected 1 CN + 1 EN (v4 misaligned! v5 fixes)

# Test 3: Out-of-order filenames
mv /tmp/article-gen/22pm-2026-07-20-en.txt /tmp/article-gen/en-first.txt
python3 generate-html.py → Expected 1 CN + 1 EN (v4 misaligned! v5 fixes)

# Test 4: No metadata files
echo "no pipe metadata here" > /tmp/article-gen/test-no-meta-cn.txt
echo "no pipe metadata here" > /tmp/article-gen/test-no-meta-en.txt
python3 generate-html.py → Expected 2 CN + 0 EN (fallback startswith)

# Test 5: Bilingual content
cat > /tmp/article-gen/bilingual.txt << 'EOF'
Test|Test in English and Chinese|English Title|Tag1,Tag2
EOF
python3 generate-html.py → Expected 1 EN (description contains "English")

# Test 6: Empty file
: > /tmp/article-gen/empty.txt
python3 generate-html.py → Expected 0 articles + skip empty

# Test 7: Single file cn-only
rm /tmp/article-gen/22pm-2026-07-20-en.txt
python3 generate-html.py → Expected 1 CN + 0 EN + 1 warning

📝 5-Command Misalignment Diagnosis Checklist

When you encounter *-en.html with Chinese content again, immediately run:

# 1. Check sitemap recent 50 URLs
curl -s https://yaohehe.github.io/sitemap.xml | grep -oE "2026-[0-9-]+\.html" | tail -50

# 2. Pull all en.html  to see if Chinese
for f in $(curl -s https://yaohehe.github.io/sitemap.xml | grep -oE "2026-[0-9-]+-en\.html"); do
  echo "=== $f ==="
  curl -s "https://yaohehe.github.io/$f" | grep -oE "<title>[^<]+"
done

# 3. Check generate-html.py current detection logic
grep -n "is_en" /root/.openclaw/workspace/yaohehe.github.io/generate-html.py

# 4. Check /tmp/article-gen/ residue
ls -la /tmp/article-gen/

# 5. Check run-pipeline.py push records
cat /root/.openclaw/workspace/yaohehe.github.io/.pushed_manifest.json | jq '.[] | select(.date=="2026-07-20")'

Summary and Next Steps

v3 flock + isolated filenames fixed concurrency but exposed v4 hidden bug; v5 metadata-driven is_en is the mechanical way to eliminate ambiguity. This is the same root cause as yesterday's "Concurrency Conflict Post-Mortem" — any "filename convention" is a fragile contract, what truly reliable is the semantic signal self-contained in content.

Next steps:

1. Merge v5 patch into generate-html.py: Change is_en detection to read pipe metadata (PR pending)

2. Add --delete parameter to publish-via-api.py: Manual curl delete is too ugly

3. **Add "Misaligned HTML Detection" Phase -1 in run-pipeline.py**: Grep </code> language tag before push</p> <p>Related links: <a href="https:///2026-07-16-terraform-single-vps-iac-hands-on.html" target="_blank" rel="nofollow sponsored">7/16 Terraform Single VPS IaC Hands-On</a>, <a href="https:///2026-07-15-coreyhaines31-marketingskills-hands-on.html" target="_blank" rel="nofollow sponsored">7/15 coreyhaines31/marketingskills Hands-On</a>, <a href="https:///2026-07-20-ai-automation-pipeline-concurrency-conflict-post-mortem.html" target="_blank" rel="nofollow sponsored">7/20 AI Automation Pipeline Concurrency Conflict Post-Mortem</a></p><p style="margin:15px 0;"><a href="https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link" target="_blank" rel="nofollow sponsored" style="color:#0066cc;text-decoration:underline;">👉 Join MiniMax Token Plan: AI coding acceleration for businesses</a></p><p style="margin:15px 0;"><a href="https://www.bigmodel.cn/glm-coding?ic=XTFAUHSPC3" target="_blank" rel="nofollow sponsored" style="color:#0066cc;text-decoration:underline;">👉 Join Zhipu Coding Plan: GLM-4.6/GLM-5 coding packages, China-stable, pay-per-token unlimited</a></p><p style="margin:15px 0;"><a href="https://www.aliyun.com/minisite/goods?userCode=7nyzznme" target="_blank" rel="nofollow sponsored" style="color:#0066cc;text-decoration:underline;">👉 Join Aliyun AI: Top AI products with exclusive coupons for business innovation</a></p><p style="color:#888;font-size:0.85em;margin:15px 0;">📌 This article was AI-assisted generated and human-reviewed | <a href="/">TechPassive</a> — An AI-driven content testing site focused on real tool reviews</p> <div style="background:#fff8e1;border-left:4px solid #f39c12;padding:20px;margin:30px 0;border-radius:8px;"> <h3 style="margin:0 0 10px;color:#b7791f;">🔗 Recommended Tools</h3> <p style="margin:0 0 15px;color:#666;">These are carefully selected tools. Using our affiliate links supports us to keep producing quality content:</p> <div style="display:flex;flex-wrap:wrap;gap:10px;"> <a href="https://m.do.co/c/ef5f58bd38d2" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#0058ff;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">☁️ DigitalOcean Cloud</a> <a href="https://www.vultr.com/?ref=9890714" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#0058ff;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">⚡ Vultr VPS</a> <a href="https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#00d4aa;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">⭐ MiniMax Token Plan</a> <a href="https://www.bigmodel.cn/glm-coding?ic=XTFAUHSPC3" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#7c3aed;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🧩 Zhipu Coding Plan</a> <a href="https://www.bigmodel.cn/invite?icode=2Y1XM4ve1Q8IptFjg%2Fi62v2gad6AKpjZefIo3dVEQyA%3D" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#a855f7;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🎁 Zhipu 20M Tokens Gift</a> <a href="https://qoder.com.cn/referral?referral_code=ZKGgINVqISq1s0tajhFbWRzB6PYR34T5" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#6366f1;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🤖 QoderWork CN (Refer & Earn)</a> <a href="https://www.aliyun.com/minisite/goods?userCode=7nyzznme" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff6a00;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">☁️ Aliyun AI Products</a> <a href="https://www.amazon.com/s?k=WordPress&i=stripbooks-intl-ship&crid=2GP4ZRUNK7CK3&sprefix=wordpress%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss_1&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">📚 WordPress Books</a> <a href="https://www.amazon.com/s?k=WordPress+SEO%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97&i=stripbooks-intl-ship&crid=240UCW7BT9BGN&sprefix=wordpress+seo%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97%2Cstripbooks-intl-ship%2C490&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🔍 WordPress SEO Books</a> <a href="https://www.amazon.com/s?k=Web+Hosting&i=stripbooks-intl-ship&crid=2H8Q7KQ8M9LXN&sprefix=web+hosting%2Cstripbooks-intl-ship%2C397&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🌐 Web Hosting Books</a> <a href="https://www.amazon.com/s?k=Docker&i=stripbooks-intl-ship&crid=3K1YB8L5E6M7N&sprefix=docker%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🐳 Docker Books</a> <a href="https://www.amazon.com/s?k=Linux&i=stripbooks-intl-ship&crid=4L2M3N4O5P6Q&sprefix=linux%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🐧 Linux Books</a> <a href="https://www.amazon.com/s?k=Python&i=stripbooks-intl-ship&crid=5M3N4O5P6Q7R&sprefix=python%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🐍 Python Books</a> <a href="https://www.amazon.com/s?k=Affiliate+Marketing&i=stripbooks-intl-ship&crid=6N4O5P6Q7R8S&sprefix=affiliate+marketing%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">💰 Affiliate Marketing</a> <a href="https://www.amazon.com/s?k=Passive+Income&i=stripbooks-intl-ship&crid=7O5P6Q7R8S9T&sprefix=passive+income%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">💵 Passive Income Books</a> <a href="https://www.amazon.com/s?k=Server&i=stripbooks-intl-ship&crid=8P6Q7R8S9T0U&sprefix=server%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🖥️ Server Books</a> <a href="https://www.amazon.com/s?k=Cloud+Computing&i=stripbooks-intl-ship&crid=9Q7R8T0U1V2W&sprefix=cloud+computing%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">☁️ Cloud Computing Books</a> <a href="https://www.amazon.com/s?k=DevOps&i=stripbooks-intl-ship&crid=0R8S9T0U1V2W&sprefix=devops%2Cstripbooks-intl-ship%2C439&ref=nb_sb_noss&tag=techpassive-20" target="_blank" rel="nofollow sponsored" style="display:inline-block;background:#ff9900;color:white;padding:8px 16px;border-radius:5px;text-decoration:none;font-size:0.9em;">🚀 DevOps Books</a> </div> <div id="related-articles-placeholder" style="margin-top:15px;"><!-- Dynamic related articles injected by insert-internal-links.py --></div> </div> </div> <a href="/" class="back-btn">← Back to Home</a> </main> <script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?5217d6a8f8299c6b114858ac6e719e2b"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> <div style="margin:30px 0; text-align:center;"> <ins class="adsbygoogle" style="display:block; text-align:center; margin:30px 0;" data-ad-client="ca-pub-3419621562136630" data-ad-slot="in-article" data-ad-format="auto"></ins> </div> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </body> </html>