@profile-as-code/core 0.0.0-stage → 0.1.2
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/LICENSE +21 -0
- package/README.md +80 -2
- package/dist/byte-order.d.ts +17 -0
- package/dist/byte-order.d.ts.map +1 -0
- package/dist/byte-order.js +19 -0
- package/dist/byte-order.js.map +1 -0
- package/dist/cite.d.ts +91 -0
- package/dist/cite.d.ts.map +1 -0
- package/dist/cite.js +440 -0
- package/dist/cite.js.map +1 -0
- package/dist/compile.d.ts +40 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +120 -0
- package/dist/compile.js.map +1 -0
- package/dist/completeness.d.ts +81 -0
- package/dist/completeness.d.ts.map +1 -0
- package/dist/completeness.js +300 -0
- package/dist/completeness.js.map +1 -0
- package/dist/drift.d.ts +43 -0
- package/dist/drift.d.ts.map +1 -0
- package/dist/drift.js +277 -0
- package/dist/drift.js.map +1 -0
- package/dist/generated/ai-policy.gen.d.ts +36 -0
- package/dist/generated/ai-policy.gen.d.ts.map +1 -0
- package/dist/generated/ai-policy.gen.js +31 -0
- package/dist/generated/ai-policy.gen.js.map +1 -0
- package/dist/generated/platforms.gen.d.ts +34 -0
- package/dist/generated/platforms.gen.d.ts.map +1 -0
- package/dist/generated/platforms.gen.js +253 -0
- package/dist/generated/platforms.gen.js.map +1 -0
- package/dist/generated/schema.zod.d.ts +595 -0
- package/dist/generated/schema.zod.d.ts.map +1 -0
- package/dist/generated/schema.zod.js +36 -0
- package/dist/generated/schema.zod.js.map +1 -0
- package/dist/geo.d.ts +42 -0
- package/dist/geo.d.ts.map +1 -0
- package/dist/geo.js +614 -0
- package/dist/geo.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger.d.ts +238 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +429 -0
- package/dist/ledger.js.map +1 -0
- package/dist/load.d.ts +51 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +138 -0
- package/dist/load.js.map +1 -0
- package/dist/media.d.ts +82 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +170 -0
- package/dist/media.js.map +1 -0
- package/dist/normalize.d.ts +57 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +133 -0
- package/dist/normalize.js.map +1 -0
- package/dist/presence.d.ts +94 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +217 -0
- package/dist/presence.js.map +1 -0
- package/dist/registry.d.ts +79 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +214 -0
- package/dist/registry.js.map +1 -0
- package/dist/selection.d.ts +98 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +242 -0
- package/dist/selection.js.map +1 -0
- package/dist/structured-data.d.ts +83 -0
- package/dist/structured-data.d.ts.map +1 -0
- package/dist/structured-data.js +330 -0
- package/dist/structured-data.js.map +1 -0
- package/dist/types.d.ts +327 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +34 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christian Luciani
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,81 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @profile-as-code/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The core engine of **profile-as-code** (M1): load a profile-data workspace,
|
|
4
|
+
validate it against the contract, and run the drift / GEO / compile layers.
|
|
5
|
+
|
|
6
|
+
The contract source is `schema/profile.schema.json` (D3) — Zod schemas are
|
|
7
|
+
**generated** from it, never hand-written (see `scripts/gen-zod.ts`).
|
|
8
|
+
|
|
9
|
+
## API
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { load, driftCheck, geoCheck, compile } from '@profile-as-code/core';
|
|
13
|
+
|
|
14
|
+
const profile = load('/path/to/profile-data'); // parse content/*.yaml + validate (FAIL on schema, D12)
|
|
15
|
+
const issues = driftCheck(profile); // Issue[] — WARN only, never throws (D12)
|
|
16
|
+
const geo = geoCheck(profile); // GeoReport — 0..100 score, not a gate (§8)
|
|
17
|
+
const slice = compile(profile, 'linkedin', 'es'); // PlatformProfile — language-aware renderer slice
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- **`load(workspace)`** — reads `content/*.yaml` (file name = root property:
|
|
21
|
+
`bios.yaml` → `bios[]`, `identity.yaml` → `identity`, …), merges, validates
|
|
22
|
+
against the generated Zod, normalizes (collections default to `[]`).
|
|
23
|
+
Throws `LoadError` (workspace problems) / `SchemaValidationError` (contract
|
|
24
|
+
violations with one precise `path` + `message` per error — the fail-on-schema
|
|
25
|
+
side of D12). Unknown files fail validation via `additionalProperties: false`.
|
|
26
|
+
- **`driftCheck(profile)`** — factual contradictions across surfaces, all WARN
|
|
27
|
+
(users may have different intents per platform, but they must SEE them):
|
|
28
|
+
uncanonicalized platform URLs, `start > end`, duplicated bios/headlines,
|
|
29
|
+
same role/org with different dates, same title with different year/venue,
|
|
30
|
+
ORCID conflicts/mismatches vs `identity.links`, active entries without a
|
|
31
|
+
curated base, unknown active platform keys, skill level conflicts.
|
|
32
|
+
*Out of scope (v1):* free-text mining of bio prose, DOI resolvability
|
|
33
|
+
(network), the variants store (only the platform+lang base is validated).
|
|
34
|
+
- **`geoCheck(profile)`** — weighted report (14 checks since v1.10, 0..100):
|
|
35
|
+
**fact consistency** (conflicts + per-platform bio/headline coverage),
|
|
36
|
+
**structured-data readiness** (`schema.org` Person JSON-LD with `sameAs`,
|
|
37
|
+
ready for the web renderer), **semantic associations** (the 3–5
|
|
38
|
+
`positioning.geo.semanticAssociations` anchors and how well each is
|
|
39
|
+
reinforced across statement/skills/keywords/projects), **citability**
|
|
40
|
+
(DOI/ORCID on publications, `evidence[]` on projects) plus the v1.10 citability
|
|
41
|
+
codes — canonical definition, FAQ coverage, freshness, sameAs coverage, name
|
|
42
|
+
collision. Missing data is neutral for the fact checks (never penalized);
|
|
43
|
+
readiness/citability checks (structured data, semantic anchors, the v1.10 codes)
|
|
44
|
+
can score 0 when the signal is absent — a reported gap, not a penalty (SPEC §8).
|
|
45
|
+
- **`compile(profile, platform, lang)`** — facts pass through untouched
|
|
46
|
+
(identical on every platform = GEO-citable); text (bios, headlines, statement,
|
|
47
|
+
audiences, citationsGoal) is filtered by platform+lang and falls back to `en`
|
|
48
|
+
(always required by the schema), recording each fallback in `fallbacks`.
|
|
49
|
+
|
|
50
|
+
## Contract fidelity (generator)
|
|
51
|
+
|
|
52
|
+
`scripts/gen-zod.ts` regenerates `src/generated/schema.zod.ts` from
|
|
53
|
+
`schema/profile.schema.json`. Because `json-schema-to-zod@2.8.1` does not resolve
|
|
54
|
+
`$defs`, ignore `propertyNames`, and bloats `oneOf`, the generator:
|
|
55
|
+
|
|
56
|
+
1. inlines `#/$defs/*` references (fails on unknown/circular defs),
|
|
57
|
+
2. rewrites the lone `oneOf` (`check.value`) to `anyOf` (clean `z.union`),
|
|
58
|
+
3. materializes `langMap.en` as a real property (keeps `required: ['en']`), and
|
|
59
|
+
4. wraps every langMap with a `langMapKeys` superRefine enforcing the
|
|
60
|
+
`en/es/fr` key enum (`propertyNames`).
|
|
61
|
+
|
|
62
|
+
Safety nets fail CI loudly if the output ever contains `z.any()` or loses the
|
|
63
|
+
langMap guard.
|
|
64
|
+
|
|
65
|
+
## Test
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
pnpm install
|
|
69
|
+
pnpm test # vitest (load, drift, geo, compile)
|
|
70
|
+
pnpm build # strict tsc → dist/
|
|
71
|
+
pnpm gen:zod # regenerate src/generated/schema.zod.ts (must produce no diff)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Fixtures live in `tests/fixtures/`: `minimal/` (drift-free, GEO-rich — the
|
|
75
|
+
reference fixture) and `drifting/` (schema-valid but contradicts itself on
|
|
76
|
+
every drift rule).
|
|
77
|
+
|
|
78
|
+
Requires Node ≥ 22 (the `engines` field of this manifest). Full source and docs
|
|
79
|
+
live in the [public repository](https://github.com/ChristianLuciani/profile-as-code) —
|
|
80
|
+
`scripts/gen-zod.ts` and `tests/fixtures/` above are package-relative paths there
|
|
81
|
+
(`packages/core/…`); the contract source is the repository's `schema/profile.schema.json`.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* byte-order.ts — the ONE home of every text-order comparison in the engine
|
|
3
|
+
* (D19 byte-parity, issue #305).
|
|
4
|
+
*
|
|
5
|
+
* The comparator is UTF-16 code UNITS — JS native `a < b` string order:
|
|
6
|
+
* deterministic on every environment, ICU-free. It is NOT codepoint order on
|
|
7
|
+
* the astral edge, and SPEC §15.3 names that choice exactly. A `localeCompare`
|
|
8
|
+
* call-site would depend on the ICU build and can tie (`0`), leaking
|
|
9
|
+
* environment-specific order through a stable sort — the class #257 fixed for
|
|
10
|
+
* the featured slice and #305 closes workspace-wide.
|
|
11
|
+
*
|
|
12
|
+
* The discriminating probe (`apple` vs `APPLE`: ICU collation reads lowercase
|
|
13
|
+
* first, code units read uppercase first) lives at
|
|
14
|
+
* packages/core/tests/byte-order.test.ts.
|
|
15
|
+
*/
|
|
16
|
+
export declare function byteOrder(a: string, b: string): number;
|
|
17
|
+
//# sourceMappingURL=byte-order.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-order.d.ts","sourceRoot":"","sources":["../src/byte-order.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* byte-order.ts — the ONE home of every text-order comparison in the engine
|
|
3
|
+
* (D19 byte-parity, issue #305).
|
|
4
|
+
*
|
|
5
|
+
* The comparator is UTF-16 code UNITS — JS native `a < b` string order:
|
|
6
|
+
* deterministic on every environment, ICU-free. It is NOT codepoint order on
|
|
7
|
+
* the astral edge, and SPEC §15.3 names that choice exactly. A `localeCompare`
|
|
8
|
+
* call-site would depend on the ICU build and can tie (`0`), leaking
|
|
9
|
+
* environment-specific order through a stable sort — the class #257 fixed for
|
|
10
|
+
* the featured slice and #305 closes workspace-wide.
|
|
11
|
+
*
|
|
12
|
+
* The discriminating probe (`apple` vs `APPLE`: ICU collation reads lowercase
|
|
13
|
+
* first, code units read uppercase first) lives at
|
|
14
|
+
* packages/core/tests/byte-order.test.ts.
|
|
15
|
+
*/
|
|
16
|
+
export function byteOrder(a, b) {
|
|
17
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=byte-order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-order.js","sourceRoot":"","sources":["../src/byte-order.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,CAAS;IAC5C,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC"}
|
package/dist/cite.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cite.ts — the deterministic citation matcher (SPEC §7.4, issue #291).
|
|
3
|
+
*
|
|
4
|
+
* The engine answers ONE question about an answer-engine record: did this saved
|
|
5
|
+
* answer cite this entity? It is a pure function over the SSOT and the answer
|
|
6
|
+
* bytes — no network, no model, no clock (D19) — because the alternative
|
|
7
|
+
* (substring matching) is why GEO reporting overreports, and the only fix is a
|
|
8
|
+
* matcher that says exactly which text it matched, why, and when it refuses to
|
|
9
|
+
* guess.
|
|
10
|
+
*
|
|
11
|
+
* The vocabulary is the workspace's DECLARED data, never world knowledge:
|
|
12
|
+
* name identity.name
|
|
13
|
+
* alias identity.orgName (the one declared alternate name the schema has)
|
|
14
|
+
* handle identity.handle (its final token, '@' stripped) + socialHandles
|
|
15
|
+
* rows with status: claimed
|
|
16
|
+
* hosts the role: identity URL and the sameAs set (structured-data.ts —
|
|
17
|
+
* one derivation, never a second)
|
|
18
|
+
* partial a contiguous multi-token prefix of the name (low confidence)
|
|
19
|
+
*
|
|
20
|
+
* Normalization and word-boundary matching live in `normalize.ts`. It is
|
|
21
|
+
* `cite-check`'s fold, not `geoCheck`'s: `geoCheck` keeps its own case-only
|
|
22
|
+
* comparison so this matcher cannot move a published GEO score (§8).
|
|
23
|
+
*
|
|
24
|
+
* Guards make a text hit NOT a citation (`cited: false`): a shorter term
|
|
25
|
+
* contained in a longer declared one (`longer-name`), a one-word name with no
|
|
26
|
+
* declared disambiguator in its sentence (`ambiguous-term` + `no-qualifier`), and
|
|
27
|
+
* a mention inside a contrast clause (`contrast-context`). `competing:<phrase>`
|
|
28
|
+
* never decides on its own — it only names the longer reading the text carries
|
|
29
|
+
* when the hit is already ambiguous, so ordinary prose cannot become a
|
|
30
|
+
* competitor through an adjacent capital. `confidence: low` is never citable
|
|
31
|
+
* downstream (declared in §7.4).
|
|
32
|
+
*/
|
|
33
|
+
import type { Profile } from "./types.js";
|
|
34
|
+
/** The rung a span was matched by — one kind per ladder rung (SPEC §7.4). */
|
|
35
|
+
export type CiteSpanKind = "citation-url" | "name" | "alias" | "handle" | "partial";
|
|
36
|
+
/** The best surviving rung. `low` is never a citation in a downstream report. */
|
|
37
|
+
export type CiteConfidence = "high" | "medium" | "low";
|
|
38
|
+
/** One citation row of the runner's input contract. */
|
|
39
|
+
export interface CiteCitation {
|
|
40
|
+
url: string;
|
|
41
|
+
title?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One saved answer (the runner's contract, never produced here). The matcher
|
|
45
|
+
* reads `answer` + `citations`; the rest is carried through for a report.
|
|
46
|
+
*/
|
|
47
|
+
export interface CiteAnswer {
|
|
48
|
+
engine?: string | null;
|
|
49
|
+
askedAt?: string | null;
|
|
50
|
+
question?: string | null;
|
|
51
|
+
answer: string;
|
|
52
|
+
citations: CiteCitation[];
|
|
53
|
+
}
|
|
54
|
+
/** A matched span: a character range in `answer`, or a citation pointer. */
|
|
55
|
+
export interface CiteSpan {
|
|
56
|
+
/** Original offset (inclusive). 0 for a `citation-url` span (not in the text). */
|
|
57
|
+
start: number;
|
|
58
|
+
/** Original offset (exclusive). 0 for a `citation-url` span. */
|
|
59
|
+
end: number;
|
|
60
|
+
kind: CiteSpanKind;
|
|
61
|
+
/** The citation URL — only on `citation-url` spans. */
|
|
62
|
+
url?: string;
|
|
63
|
+
}
|
|
64
|
+
/** Per-answer result. Never aggregated by the engine (SPEC §7.4). */
|
|
65
|
+
export interface CiteMatch {
|
|
66
|
+
cited: boolean;
|
|
67
|
+
confidence: CiteConfidence;
|
|
68
|
+
spans: CiteSpan[];
|
|
69
|
+
reasons: string[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The vocabulary the matcher resolved from the workspace. Exposed in `--json`
|
|
73
|
+
* so a report can say WHAT was matched without re-reading the SSOT.
|
|
74
|
+
*/
|
|
75
|
+
export interface CiteVocabulary {
|
|
76
|
+
name: string;
|
|
77
|
+
aliases: string[];
|
|
78
|
+
handles: string[];
|
|
79
|
+
partials: string[];
|
|
80
|
+
hosts: string[];
|
|
81
|
+
}
|
|
82
|
+
/** The public vocabulary of a workspace (the `entity` block of `--json`). */
|
|
83
|
+
export declare function citeVocabulary(profile: Profile): CiteVocabulary;
|
|
84
|
+
/**
|
|
85
|
+
* Match one saved answer against the workspace's declared entity (SPEC §7.4).
|
|
86
|
+
* Pure: the same profile + answer bytes always produce the same result.
|
|
87
|
+
*/
|
|
88
|
+
export declare function citeMatch(profile: Profile, answer: CiteAnswer): CiteMatch;
|
|
89
|
+
/** Exported for tests: the declared host of a URL under the matcher's rule. */
|
|
90
|
+
export declare function citationHost(url: string): string | undefined;
|
|
91
|
+
//# sourceMappingURL=cite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cite.d.ts","sourceRoot":"","sources":["../src/cite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,6EAA6E;AAC7E,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpF,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEvD,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,YAAY,CAAC;IACnB,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,cAAc,CAAC;IAC3B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAsND,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,CAE/D;AAgFD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CA0JzE;AAaD,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5D"}
|