@houtini/seo-audit-console 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -13
- package/dist/audit/checks.d.ts +0 -7
- package/dist/audit/checks.d.ts.map +1 -1
- package/dist/audit/checks.js +22 -282
- package/dist/audit/checks.js.map +1 -1
- package/dist/audit/drift.d.ts +0 -12
- package/dist/audit/drift.d.ts.map +1 -1
- package/dist/audit/drift.js +0 -15
- package/dist/audit/drift.js.map +1 -1
- package/dist/audit/engine.d.ts +0 -3
- package/dist/audit/engine.d.ts.map +1 -1
- package/dist/audit/engine.js +7 -42
- package/dist/audit/engine.js.map +1 -1
- package/dist/audit/keywordList.d.ts +0 -14
- package/dist/audit/keywordList.d.ts.map +1 -1
- package/dist/audit/keywordList.js +0 -5
- package/dist/audit/keywordList.js.map +1 -1
- package/dist/audit/opportunities.js +3 -26
- package/dist/audit/opportunities.js.map +1 -1
- package/dist/audit/recon.d.ts +0 -31
- package/dist/audit/recon.d.ts.map +1 -1
- package/dist/audit/recon.js +0 -27
- package/dist/audit/recon.js.map +1 -1
- package/dist/audit/report.d.ts +0 -4
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/report.js +0 -7
- package/dist/audit/report.js.map +1 -1
- package/dist/audit/schema-validate.d.ts +0 -26
- package/dist/audit/schema-validate.d.ts.map +1 -1
- package/dist/audit/schema-validate.js +8 -64
- package/dist/audit/schema-validate.js.map +1 -1
- package/dist/audit/templates.d.ts +0 -24
- package/dist/audit/templates.d.ts.map +1 -1
- package/dist/audit/templates.js +1 -21
- package/dist/audit/templates.js.map +1 -1
- package/dist/audit/topicGaps.d.ts +0 -1
- package/dist/audit/topicGaps.d.ts.map +1 -1
- package/dist/audit/topicGaps.js +3 -24
- package/dist/audit/topicGaps.js.map +1 -1
- package/dist/core/AuditDatabase.d.ts +0 -14
- package/dist/core/AuditDatabase.d.ts.map +1 -1
- package/dist/core/AuditDatabase.js +8 -61
- package/dist/core/AuditDatabase.js.map +1 -1
- package/dist/core/Backlinks.d.ts +0 -7
- package/dist/core/Backlinks.d.ts.map +1 -1
- package/dist/core/Backlinks.js +1 -23
- package/dist/core/Backlinks.js.map +1 -1
- package/dist/core/Crawler.d.ts +0 -1
- package/dist/core/Crawler.d.ts.map +1 -1
- package/dist/core/Crawler.js +24 -119
- package/dist/core/Crawler.js.map +1 -1
- package/dist/core/DataForSeoClient.d.ts +0 -74
- package/dist/core/DataForSeoClient.d.ts.map +1 -1
- package/dist/core/DataForSeoClient.js +1 -72
- package/dist/core/DataForSeoClient.js.map +1 -1
- package/dist/core/Entities.d.ts +0 -6
- package/dist/core/Entities.d.ts.map +1 -1
- package/dist/core/Entities.js +0 -8
- package/dist/core/Entities.js.map +1 -1
- package/dist/core/FirecrawlClient.d.ts +0 -18
- package/dist/core/FirecrawlClient.d.ts.map +1 -1
- package/dist/core/FirecrawlClient.js +1 -13
- package/dist/core/FirecrawlClient.js.map +1 -1
- package/dist/core/GscClient.d.ts +0 -7
- package/dist/core/GscClient.d.ts.map +1 -1
- package/dist/core/GscClient.js +1 -10
- package/dist/core/GscClient.js.map +1 -1
- package/dist/core/GscSync.d.ts +0 -4
- package/dist/core/GscSync.d.ts.map +1 -1
- package/dist/core/GscSync.js +2 -33
- package/dist/core/GscSync.js.map +1 -1
- package/dist/core/JobManager.d.ts +0 -5
- package/dist/core/JobManager.d.ts.map +1 -1
- package/dist/core/JobManager.js +0 -8
- package/dist/core/JobManager.js.map +1 -1
- package/dist/core/LinkIntersect.d.ts +0 -1
- package/dist/core/LinkIntersect.d.ts.map +1 -1
- package/dist/core/LinkIntersect.js +1 -37
- package/dist/core/LinkIntersect.js.map +1 -1
- package/dist/core/MajesticClient.d.ts +0 -26
- package/dist/core/MajesticClient.d.ts.map +1 -1
- package/dist/core/MajesticClient.js +0 -15
- package/dist/core/MajesticClient.js.map +1 -1
- package/dist/core/RankTracker.d.ts +0 -4
- package/dist/core/RankTracker.d.ts.map +1 -1
- package/dist/core/RankTracker.js +0 -9
- package/dist/core/RankTracker.js.map +1 -1
- package/dist/core/Refresh.d.ts +0 -6
- package/dist/core/Refresh.d.ts.map +1 -1
- package/dist/core/Refresh.js +0 -6
- package/dist/core/Refresh.js.map +1 -1
- package/dist/core/SupadataClient.d.ts +0 -11
- package/dist/core/SupadataClient.d.ts.map +1 -1
- package/dist/core/SupadataClient.js +0 -5
- package/dist/core/SupadataClient.js.map +1 -1
- package/dist/core/UrlInspector.d.ts +0 -5
- package/dist/core/UrlInspector.d.ts.map +1 -1
- package/dist/core/UrlInspector.js +0 -6
- package/dist/core/UrlInspector.js.map +1 -1
- package/dist/core/WikidataClient.d.ts +0 -2
- package/dist/core/WikidataClient.d.ts.map +1 -1
- package/dist/core/WikidataClient.js +0 -7
- package/dist/core/WikidataClient.js.map +1 -1
- package/dist/core/agentReadiness.d.ts +0 -9
- package/dist/core/agentReadiness.d.ts.map +1 -1
- package/dist/core/agentReadiness.js +0 -13
- package/dist/core/agentReadiness.js.map +1 -1
- package/dist/core/ctrModel.js +0 -3
- package/dist/core/ctrModel.js.map +1 -1
- package/dist/core/dashboardData.d.ts +0 -1
- package/dist/core/dashboardData.d.ts.map +1 -1
- package/dist/core/dashboardData.js +13 -95
- package/dist/core/dashboardData.js.map +1 -1
- package/dist/core/dataStorage.d.ts +0 -2
- package/dist/core/dataStorage.d.ts.map +1 -1
- package/dist/core/dataStorage.js +6 -19
- package/dist/core/dataStorage.js.map +1 -1
- package/dist/core/draftBrief.d.ts +0 -7
- package/dist/core/draftBrief.d.ts.map +1 -1
- package/dist/core/draftBrief.js +0 -10
- package/dist/core/draftBrief.js.map +1 -1
- package/dist/core/extract.d.ts +0 -11
- package/dist/core/extract.d.ts.map +1 -1
- package/dist/core/extract.js +1 -38
- package/dist/core/extract.js.map +1 -1
- package/dist/core/googleNews.d.ts +0 -11
- package/dist/core/googleNews.d.ts.map +1 -1
- package/dist/core/googleNews.js +0 -7
- package/dist/core/googleNews.js.map +1 -1
- package/dist/core/gscFreshness.d.ts +0 -10
- package/dist/core/gscFreshness.d.ts.map +1 -1
- package/dist/core/gscFreshness.js +0 -11
- package/dist/core/gscFreshness.js.map +1 -1
- package/dist/core/linkGraph.d.ts +0 -15
- package/dist/core/linkGraph.d.ts.map +1 -1
- package/dist/core/linkGraph.js +1 -23
- package/dist/core/linkGraph.js.map +1 -1
- package/dist/core/marketSizing.d.ts +0 -13
- package/dist/core/marketSizing.d.ts.map +1 -1
- package/dist/core/marketSizing.js +1 -1
- package/dist/core/marketSizing.js.map +1 -1
- package/dist/core/passageScore.d.ts +0 -13
- package/dist/core/passageScore.d.ts.map +1 -1
- package/dist/core/passageScore.js +1 -16
- package/dist/core/passageScore.js.map +1 -1
- package/dist/core/paths.d.ts +0 -3
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +0 -0
- package/dist/core/paths.js.map +1 -1
- package/dist/core/queryData.d.ts +0 -1
- package/dist/core/queryData.d.ts.map +1 -1
- package/dist/core/queryData.js +0 -18
- package/dist/core/queryData.js.map +1 -1
- package/dist/core/reconFetch.d.ts +0 -6
- package/dist/core/reconFetch.d.ts.map +1 -1
- package/dist/core/reconFetch.js +1 -4
- package/dist/core/reconFetch.js.map +1 -1
- package/dist/core/reconResearch.d.ts +0 -20
- package/dist/core/reconResearch.d.ts.map +1 -1
- package/dist/core/reconResearch.js +1 -16
- package/dist/core/reconResearch.js.map +1 -1
- package/dist/core/reranker.d.ts +0 -2
- package/dist/core/reranker.d.ts.map +1 -1
- package/dist/core/reranker.js +1 -11
- package/dist/core/reranker.js.map +1 -1
- package/dist/core/robots.d.ts +0 -6
- package/dist/core/robots.d.ts.map +1 -1
- package/dist/core/robots.js +1 -7
- package/dist/core/robots.js.map +1 -1
- package/dist/core/serpFootprint.d.ts +0 -12
- package/dist/core/serpFootprint.d.ts.map +1 -1
- package/dist/core/serpFootprint.js +0 -1
- package/dist/core/serpFootprint.js.map +1 -1
- package/dist/core/serpRecon.d.ts +0 -14
- package/dist/core/serpRecon.d.ts.map +1 -1
- package/dist/core/serpRecon.js +1 -13
- package/dist/core/serpRecon.js.map +1 -1
- package/dist/core/sitemap.js +3 -16
- package/dist/core/sitemap.js.map +1 -1
- package/dist/core/sql.d.ts +0 -4
- package/dist/core/sql.d.ts.map +1 -1
- package/dist/core/sql.js +0 -4
- package/dist/core/sql.js.map +1 -1
- package/dist/core/url-key.d.ts +0 -31
- package/dist/core/url-key.d.ts.map +1 -1
- package/dist/core/url-key.js +1 -38
- package/dist/core/url-key.js.map +1 -1
- package/dist/core/webHandlers.d.ts +0 -6
- package/dist/core/webHandlers.d.ts.map +1 -1
- package/dist/core/webHandlers.js +2 -5
- package/dist/core/webHandlers.js.map +1 -1
- package/dist/core/webServer.d.ts +0 -16
- package/dist/core/webServer.d.ts.map +1 -1
- package/dist/core/webServer.js +3 -17
- package/dist/core/webServer.js.map +1 -1
- package/dist/dashboard.js +0 -23
- package/dist/dashboard.js.map +1 -1
- package/dist/generators/index.d.ts +0 -7
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +1 -26
- package/dist/generators/index.js.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/server.js +16 -166
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -11,29 +11,31 @@
|
|
|
11
11
|
[](https://modelcontextprotocol.io)
|
|
12
12
|
[](https://nodejs.org)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Almost every technical SEO audit I've been handed in twenty years is a crawler's opinion, and a crawler only ever sees half the picture. It tells you what your site *says*. It has nothing to say about what Google *did* about it: which queries you rank for, which pages earn the impressions, where the clicks land.
|
|
15
|
+
|
|
16
|
+
This one brings the other half. SEO Audit Console runs inside Claude, pulls your **Google Search Console** history, crawls your site properly, and joins the two so every finding carries the traffic at stake. Ninety-nine checks, ranked by the clicks the fix could recover rather than how alarming the check sounds, and it writes the fix for you: the 301 rule, the JSON-LD, the internal links. The core audit needs nothing but your own Search Console; **DataForSEO** and **Majestic** slot in later, when your questions grow into competitors and link building. Your data stays on your machine.
|
|
15
17
|
|
|
16
18
|
**Built by [Houtini](https://houtini.com).** We build automation for the grunt work of digital marketing - the data collection, the crawling, the merging, the checking - so your team's time goes on the thinking, the strategy and the client work that needs a human. This plugin is that idea applied to the technical SEO audit.
|
|
17
19
|
|
|
18
20
|
> **New to MCPs, or not sure where to start?** The **[Getting started guide](manual/getting-started.md)** takes you from a completely fresh machine (no Node, no Git, never heard of a service account) to your first audit - every step screenshotted, including the one everyone misses. Ten minutes, honestly.
|
|
19
21
|
|
|
20
22
|
```console
|
|
21
|
-
you › run an SEO audit on
|
|
23
|
+
you › run an SEO audit on mysite.com
|
|
22
24
|
|
|
23
25
|
⣾ search console 1.8M rows synced (19s - incremental)
|
|
24
26
|
⣾ crawl 868 pages · HTTP/2 · robots-polite · 8 parallel
|
|
25
27
|
⣾ link graph internal PageRank · click depth · in-degree
|
|
26
28
|
✓ 99 checks · 220 findings · ranked by expected clicks per dev-hour
|
|
27
29
|
|
|
28
|
-
#1 CTR far below position-expected /
|
|
30
|
+
#1 CTR far below position-expected /pricing XL
|
|
29
31
|
#2 Page losing clicks (trend) site-wide XL
|
|
30
|
-
#3 Keyword cannibalisation "
|
|
31
|
-
#4 Robots-blocked page earning traffic /category/
|
|
32
|
+
#3 Keyword cannibalisation "project management app" L
|
|
33
|
+
#4 Robots-blocked page earning traffic /category/guides L
|
|
32
34
|
|
|
33
35
|
you › generate the fix for #1 ▍
|
|
34
36
|
```
|
|
35
37
|
|
|
36
|
-

|
|
38
|
+
[](https://github.com/houtini-ai/seo-audit)
|
|
37
39
|
|
|
38
40
|
## The manual
|
|
39
41
|
|
|
@@ -47,8 +49,8 @@ This README is the story and the quick start. The detail lives in the manual:
|
|
|
47
49
|
| [Composition](manual/composition.md) | The join keys, the grains, and thirteen worked recipes for asking your own questions across the data |
|
|
48
50
|
| [Competitive analysis](manual/competitive.md) | The Semrush-replacement workflows, DataForSEO setup, link intersect with the Majestic Trust Flow tier, and the real costs |
|
|
49
51
|
| [SEO Recon](manual/recon.md) | Why a page is losing: the live SERP + AI-Overview citation verdict, the competitor diff, and the trackable to-do ledger |
|
|
50
|
-
| [DataForSEO functions](manual/dataforseo.md) | Every DataForSEO-backed tool grouped by API module
|
|
51
|
-
| [Majestic functions](manual/majestic.md) | The optional Trust Flow tier
|
|
52
|
+
| [DataForSEO functions](manual/dataforseo.md) | Every DataForSEO-backed tool grouped by API module - Keywords, SERP, Labs, Backlinks, OnPage - each with its endpoint and cost |
|
|
53
|
+
| [Majestic functions](manual/majestic.md) | The optional Trust Flow tier - what it adds and how `link_intersect` uses it |
|
|
52
54
|
| [Dashboard & reports](manual/dashboard.md) | The eight tabs, the report hub, what each chart shows, and the shareable export |
|
|
53
55
|
|
|
54
56
|
## Surprisingly little has changed in twenty years
|
|
@@ -111,7 +113,7 @@ The crawl is where audits usually go wrong, so it's worth understanding what thi
|
|
|
111
113
|
|
|
112
114
|
After the crawl it computes a real link graph: internal PageRank with nav and footer links down-weighted, click depth from the homepage counting body links only, in-degree per page. That graph powers the orphan, equity-leak and underlinked-page checks - and the donor rankings when the tool suggests internal links.
|
|
113
115
|
|
|
114
|
-

|
|
116
|
+
[](https://github.com/houtini-ai/seo-audit)
|
|
115
117
|
|
|
116
118
|
---
|
|
117
119
|
|
|
@@ -131,9 +133,9 @@ Each of these is a real procedure I use, and each is one prompt. The expanded ve
|
|
|
131
133
|
10. **The content opportunity report.** If you write for a living, this is your page one: *"Content opportunities for mysite.com"* returns what to WRITE next (demand you already earn impressions for with no winning page), what to REFRESH (pages bleeding clicks), which SNIPPETS to rewrite (ranking well, under-clicked), and which clusters to STRENGTHEN (position 4-20, one push from the money). Every row traces to your own Search Console data - no invented keyword ideas - and *"draft the brief for row 1"* turns any of them into a grounded outline. → [competitive.md](manual/competitive.md)
|
|
132
134
|
11. **Market Sizing and Prioritisation.** *"Size the market: mysite.com vs rival1.com and rival2.com"* - the keyword universe, total monthly demand, and share of voice per topic cluster, from one cached call per domain. The engagement-opening read that used to need a Semrush subscription. → [competitive.md](manual/competitive.md)
|
|
133
135
|
12. **Content recon - why is this page losing?** *"Run content recon on mysite.com"* takes your worst declining pages, pulls the live Google SERP for each, and reads whether the **AI Overview** cites you. The verdict is the honest bit: *rank but not cited* is a data-accuracy or freshness problem, not a rewrite. It transcribes the ranking videos (Supadata), reads the reachable competitors (Firecrawl, plus a free browser-profile fetch that even gets Reddit), and writes the gaps into a tracked to-do board you can annotate and re-measure. → [recon.md](manual/recon.md)
|
|
134
|
-
13. **Link prospecting, sorted by authority that's real.** *"Link intersect for mysite.com vs rival1.com, rival2.com"* returns the domains linking to your rivals and not to you - the outreach list, followed-first and spam-filtered. Add a **Majestic** key and it re-sorts on **Trust Flow** and shows each prospect's **Topical Trust Flow**, so the directories drop out and what's left is authority that's
|
|
136
|
+
13. **Link prospecting, sorted by authority that's real.** *"Link intersect for mysite.com vs rival1.com, rival2.com"* returns the domains linking to your rivals and not to you - the outreach list, followed-first and spam-filtered. Add a **Majestic** key and it re-sorts on **Trust Flow** and shows each prospect's **Topical Trust Flow**, so the directories drop out and what's left is authority that's on your topic. → [Majestic, below](#link-intersect-and-the-majestic-trust-flow-tier)
|
|
135
137
|
|
|
136
|
-

|
|
138
|
+
[](https://github.com/houtini-ai/seo-audit)
|
|
137
139
|
|
|
138
140
|
---
|
|
139
141
|
|
|
@@ -177,7 +179,7 @@ you › link intersect for mysite.com vs rival1.com, rival2.com
|
|
|
177
179
|
|
|
178
180
|
The tier is careful with your allowance: enrichment is batched 100 domains per call (about one unit each), capped by `enrichLimit` (default 100 - and when more prospects qualify than get enriched, the response says so and tells you to raise it, rather than handing you a half-scored list), requests are serialised, and every response is cached for 30 days via `MAJESTIC_CACHE_DAYS`. Ask the same question twice in a fortnight and the second answer costs nothing.
|
|
179
181
|
|
|
180
|
-
Optional,
|
|
182
|
+
Optional, and I mean optional: with no key, `link_intersect` still runs and still sorts followed-first by domain trust. Majestic is what turns "here are 100 domains" into "here are the 20 worth an email, and here's why". Grab a key on their [plans and pricing](https://majestic.com/plans-pricing) page; the full workflow is in [competitive.md](manual/competitive.md#link-intersect-link_intersect).
|
|
181
183
|
|
|
182
184
|
> Trust Flow and Topical Trust Flow are trademarks of [Majestic](https://majestic.com) (Majestic-12 Ltd). This tier calls the Majestic API with your own key, only when you run `link_intersect`, and nothing else in the tool touches it.
|
|
183
185
|
|
|
@@ -303,4 +305,4 @@ Issues and PRs welcome. The check registry (`src/audit/checks.ts`) is built to b
|
|
|
303
305
|
|
|
304
306
|
## License
|
|
305
307
|
|
|
306
|
-
**Apache License 2.0.** Free to use, modify, and redistribute, including commercially
|
|
308
|
+
**Apache License 2.0.** Free to use, modify, and redistribute, including commercially - full terms in [LICENSE](./LICENSE).
|
package/dist/audit/checks.d.ts
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import type Database from 'better-sqlite3';
|
|
2
2
|
import type { FindingLabel, Severity } from '../core/AuditDatabase.js';
|
|
3
3
|
import { expectedCtr } from '../core/ctrModel.js';
|
|
4
|
-
/**
|
|
5
|
-
* Check registry. Each check is a pure read over the AuditDatabase (crawl + GSC +
|
|
6
|
-
* url_inspection, joined on url_key/page_key) returning affected items with evidence.
|
|
7
|
-
* Scoring + persistence happen in engine.ts. Grounded in research/01 (master checklist),
|
|
8
|
-
* research/05 (merged GSC×crawl) and research/02 (war-stories); taxonomy cross-checked
|
|
9
|
-
* against SEOmator's MIT 251-rule set.
|
|
10
|
-
*/
|
|
11
4
|
export interface CheckContext {
|
|
12
5
|
db: Database.Database;
|
|
13
6
|
gscMaxDate: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/audit/checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIvE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/audit/checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIvE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWlD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AACD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AACD,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,cAAc,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;IAClI,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,WAAW,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,GAAG,EAAE,YAAY,GAAG,UAAU,EAAE,CAAC;CACtC;AAiFD,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,eAAO,MAAM,MAAM,EAAE,QAAQ,EA+vC5B,CAAC"}
|