@ryanstark24/sfgraph-skills 1.1.4 → 1.6.0

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.
Files changed (30) hide show
  1. package/package.json +3 -2
  2. package/skills/sf-cross-layer-trace/SKILL.md +16 -5
  3. package/skills/sf-cross-org-diff/SKILL.md +7 -1
  4. package/skills/sf-dead-code-audit/SKILL.md +10 -3
  5. package/skills/sf-debug-log-analysis/SKILL.md +107 -0
  6. package/skills/sf-debug-root-cause/SKILL.md +111 -0
  7. package/skills/sf-deployment-manifest/SKILL.md +13 -7
  8. package/skills/sf-explain-code/SKILL.md +16 -1
  9. package/skills/sf-find-similar/SKILL.md +10 -4
  10. package/skills/sf-flow-impact/SKILL.md +6 -0
  11. package/skills/sf-governor-risk-fix/SKILL.md +50 -10
  12. package/skills/sf-graph-plus-source/SKILL.md +46 -0
  13. package/skills/sf-graph-router/SKILL.md +146 -0
  14. package/skills/sf-impact-from-diff/SKILL.md +11 -5
  15. package/skills/sf-metadata-refresh/SKILL.md +9 -3
  16. package/skills/sf-omnistudio-migration-audit/SKILL.md +15 -5
  17. package/skills/sf-schema-overview/SKILL.md +8 -2
  18. package/skills/sf-security-audit/SKILL.md +14 -6
  19. package/skills/sf-snapshot-compare/SKILL.md +6 -0
  20. package/skills/sf-web-explorer/SKILL.md +6 -1
  21. package/skills/sf-what-broke/SKILL.md +28 -22
  22. package/skills/sf-wip-impact/SKILL.md +8 -0
  23. package/dist/__tests__/cursor-format.test.d.ts +0 -2
  24. package/dist/__tests__/cursor-format.test.d.ts.map +0 -1
  25. package/dist/__tests__/cursor-format.test.js +0 -44
  26. package/dist/__tests__/cursor-format.test.js.map +0 -1
  27. package/dist/__tests__/installer.test.d.ts +0 -2
  28. package/dist/__tests__/installer.test.d.ts.map +0 -1
  29. package/dist/__tests__/installer.test.js +0 -64
  30. package/dist/__tests__/installer.test.js.map +0 -1
@@ -15,33 +15,39 @@ tools_used:
15
15
 
16
16
  # sf-what-broke
17
17
 
18
- Use when the user is triaging a regression and wants to know which metadata changed between two points in time and which of those changes plausibly explains a reported failure.
18
+ Use when the user is triaging a regression and wants to know which metadata changed since a recent deploy/sync, and which of those changes have **untested dependents** (the likely break surface).
19
+
20
+ **What the tool actually does (and doesn't):** `what_broke(org, since?)` compares the current graph against the latest pre-sync snapshot (or the `since` you pass), finds the changed nodes, and buckets their dependents as **at-risk** (no test coverage) vs **covered**. It does NOT take a failing-test/stack "failure signal", does NOT rank by reachability to a specific failure, and does NOT emit a path-to-failure diagram. If the user has a concrete failure (a specific exception or failing test), route that to **`sf-debug-root-cause`** (symptom → graph cause) or **`sf-debug-log-analysis`** — then come back here for the "what changed in the window" picture.
21
+
22
+ ## Evidence rule — say it only if something backs it
23
+
24
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
19
25
 
20
26
  ## Playbook
21
27
 
22
- 1. Establish the two anchors: the "good" snapshot (pre-deploy, last green build, or named checkpoint) and the "bad" anchor (now, post-deploy, or a specific snapshot id). Ask if neither is obvious.
23
- 2. Call `point_in_time_diff` between the two anchors. Note added / removed / modified nodes and edge churn per layer.
24
- 3. Call `what_broke` with the same window plus the user's failure signal (failing test name, error stack, broken UI route). The tool ranks suspect changes by reachability to the failure signal.
25
- 4. Triage in descending suspicion order. For each suspect, summarise the change (what attribute moved) and the dependency path to the failure surface.
26
- 5. Render the Mermaid path-to-failure diagram returned by `what_broke`.
27
- 6. Recommend the smallest revert or follow-up investigation (e.g. "inspect `AccountTrigger.handleInsert` — its SOQL selector lost a filter between snapshot X and Y").
28
+ 1. **`staleness_check`** first (see below).
29
+ 2. Call **`what_broke`** with the org (and `since` if the user has a specific baseline; otherwise it uses the latest pre-sync snapshot). If it reports no baseline snapshot, tell the user and fall back to `point_in_time_diff` / `sf-snapshot-compare` with an explicit anchor.
30
+ 3. Read the result: the changed nodes, and their dependents split into **at-risk** (no tests — highest priority) and **covered**.
31
+ 4. Triage at-risk first: for each, summarise what changed and what depends on it. To see the full dependency chain to a UI/test surface, hand the node to `sf-cross-layer-trace` or `trace_upstream`.
32
+ 5. For a deeper field-level diff between two points, call **`point_in_time_diff`** (or `sf-snapshot-compare`) — that's where the detailed add/remove/modify per layer lives.
33
+ 6. Recommend the smallest next step (revert a specific change, or add a test to an at-risk dependent before re-deploying).
28
34
 
29
35
  ## Visualization
30
36
 
31
- Render a **`flowchart LR`** path-to-failure diagram. Each suspect change is a node on the left; intermediate dependency hops are middle nodes; the failure surface (test, route, error) is the rightmost node. Highlight the top-suspect path with a thicker edge.
37
+ `what_broke` draws a Mermaid diagram of the changed pieces and their dependents by default (`mermaid: true`; `mermaid: false` hides it). Embed the tool's diagram rather than redrawing it. If you need a different view (for example only the untested dependents), build a simple **`flowchart LR`** yourself and say you drew it.
32
38
 
33
39
  ```
34
40
  flowchart LR
35
- S1[ApexClass:AccountTrigger]:::suspect --> H1[Service:AccountSvc] --> F1[Test:AccountTriggerTest]:::fail
36
- S2[Flow:AccountAfterUpdate] --> H1
37
- classDef suspect fill:#fee,stroke:#c00
38
- classDef fail fill:#fcc,stroke:#900,stroke-width:2px
41
+ C1[ApexClass:AccountTrigger]:::changed --> D1[ApexClass:AccountSvc]:::atrisk
42
+ C1 --> D2[Flow:AccountAfterUpdate]:::atrisk
43
+ classDef changed fill:#fee,stroke:#c00
44
+ classDef atrisk fill:#fcc,stroke:#900,stroke-width:2px
39
45
  ```
40
46
 
41
- If the suspect set is large (>15 nodes) collapse non-top suspects into a single "other changes" node — readability beats completeness.
42
-
43
47
  ## Staleness check
44
48
 
49
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
50
+
45
51
  Before calling `what_broke`, invoke `staleness_check` for the target org. If the report says stale, surface a warning to the user:
46
52
 
47
53
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -50,15 +56,15 @@ Then continue with the playbook.
50
56
 
51
57
  ## Response Shape
52
58
 
53
- - **Window** — from `<snapshot/anchor>` to `<snapshot/anchor>`.
54
- - **Top suspects** — ordered list with confidence, change summary, and the edge path linking them to the failure.
55
- - **Other changes in window** — collapsed bullet list, not the focus.
56
- - **Mermaid path-to-failure** — embedded from tool output.
57
- - **Next step** — single concrete recommendation.
59
+ - **Window** — current vs the baseline snapshot `what_broke` used (or the `since` anchor).
60
+ - **At-risk changes** — changed nodes whose dependents have no test coverage, first.
61
+ - **Covered changes** — changed nodes whose dependents are tested, briefly.
62
+ - **Next step** — single concrete recommendation (revert, or add coverage to an at-risk dependent).
58
63
 
59
64
  ## Don't
60
65
 
61
- - Do not propose a code fix without first inspecting the suspect change in detail via `sf-cross-layer-trace`.
66
+ - Do not tell the user you passed a failing test / stack to `what_broke` — it has no such parameter. Route concrete failures to `sf-debug-root-cause`.
67
+ - `what_broke` DOES emit a dependency-graph Mermaid alongside its tables — embed the tool's diagram directly; don't claim it returns tables only, and don't redraw it from scratch.
68
+ - Do not propose a code fix without first inspecting the suspect change via `sf-cross-layer-trace`.
62
69
  - Do not run write operations against the org. This skill only reads the local graph + snapshots.
63
- - Do not bury the lead — top suspect goes first, not last.
64
- - Do not invent snapshots that don't exist; if the "good" anchor is unavailable, say so.
70
+ - Do not invent snapshots that don't exist; if no baseline is available, say so and use an explicit anchor.
@@ -18,6 +18,12 @@ tools_used:
18
18
 
19
19
  Use when the user has local edits they haven't committed yet (working tree, staged or unstaged) and wants to see the downstream blast radius and test gaps before deciding whether to commit or push.
20
20
 
21
+ What counts as changed: the wip tools compare the local project with the ingested graph. In the default `mode: "changed-only"`, a file counts when it differs from git HEAD **or** was modified after the org's last sync, so commits made since the last ingest are included too; say so if the user expects only uncommitted edits. `mode: "full-folder"` parses every member.
22
+
23
+ ## Evidence rule — say it only if something backs it
24
+
25
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
26
+
21
27
  ## Playbook
22
28
 
23
29
  1. Confirm the project root. Default to the current working directory; if the user explicitly names another, use that.
@@ -52,6 +58,8 @@ If the dependent set exceeds 40 nodes, summarise per category and skip the diagr
52
58
 
53
59
  ## Staleness check
54
60
 
61
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
62
+
55
63
  Before calling `wip_impact`, invoke `staleness_check` for the linked org. WIP analysis depends on the existing graph being accurate; a stale graph will under-report dependents. If the report says stale, surface a warning to the user:
56
64
 
57
65
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=cursor-format.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor-format.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cursor-format.test.ts"],"names":[],"mappings":""}
@@ -1,44 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { toClaudeFormat, toCursorFormat } from "../installer.js";
3
- const SAMPLE = `---
4
- name: foo
5
- description: bar
6
- triggers:
7
- - "x"
8
- tools_used:
9
- - tool_a
10
- - tool_b
11
- ---
12
-
13
- # Body
14
-
15
- Some content.
16
-
17
- - bullet
18
- `;
19
- describe("format transforms", () => {
20
- it("toCursorFormat rewrites frontmatter into Cursor's contract", () => {
21
- const out = toCursorFormat(SAMPLE);
22
- // Cursor-shaped frontmatter (the only three keys it understands)
23
- expect(out).toMatch(/^description:.*bar/m);
24
- // globs now contains the SF file patterns so the rule auto-attaches
25
- // whenever the user opens any Salesforce metadata file.
26
- expect(out).toMatch(/^globs:.*sfdx-project\.json.*\*\*\/\*\.cls/m);
27
- expect(out).toMatch(/^alwaysApply:\s*false$/m);
28
- // Trigger phrases folded into the description so the agent matches them
29
- expect(out).toMatch(/Triggers:.*"?x"?/);
30
- // The agent-requested hint mentions the skill name + sfgraph routing
31
- expect(out).toMatch(/sfgraph MCP tools/);
32
- // Body preserved verbatim
33
- expect(out).toMatch(/^# Body/m);
34
- expect(out).toMatch(/^- bullet/m);
35
- // Old frontmatter is gone (it would confuse Cursor's parser)
36
- expect(out).not.toMatch(/^name: foo/m);
37
- expect(out).not.toMatch(/^triggers:/m);
38
- expect(out).not.toMatch(/^tools_used:/m);
39
- });
40
- it("toClaudeFormat is identity", () => {
41
- expect(toClaudeFormat(SAMPLE)).toBe(SAMPLE);
42
- });
43
- });
44
- //# sourceMappingURL=cursor-format.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor-format.test.js","sourceRoot":"","sources":["../../src/__tests__/cursor-format.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;CAed,CAAC;AAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACnC,iEAAiE;QACjE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAC3C,oEAAoE;QACpE,wDAAwD;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC;QACnE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAC/C,wEAAwE;QACxE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACxC,qEAAqE;QACrE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACzC,0BAA0B;QAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAClC,6DAA6D;QAC7D,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=installer.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"installer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/installer.test.ts"],"names":[],"mappings":""}
@@ -1,64 +0,0 @@
1
- import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
- import { install, listSkillsBundled } from "../installer.js";
6
- let home;
7
- beforeEach(() => {
8
- home = mkdtempSync(join(tmpdir(), "sfgraph-home-"));
9
- });
10
- afterEach(() => {
11
- rmSync(home, { recursive: true, force: true });
12
- });
13
- describe("skills installer", () => {
14
- it("installs all 16 skills to the claude target", async () => {
15
- const results = await install("claude", { homeOverride: home });
16
- const skillNames = await listSkillsBundled();
17
- expect(skillNames.length).toBe(16);
18
- expect(results.length).toBe(16);
19
- for (const r of results) {
20
- expect(r.target).toBe("claude");
21
- expect(r.action).toBe("created");
22
- expect(existsSync(r.path)).toBe(true);
23
- expect(r.path).toContain(join(home, ".claude", "skills"));
24
- expect(r.path.endsWith("SKILL.md")).toBe(true);
25
- }
26
- });
27
- it("installs to the cursor target as .mdc files in Cursor's frontmatter shape", async () => {
28
- const results = await install("cursor", { homeOverride: home });
29
- expect(results.length).toBe(16);
30
- const cursorDir = join(home, ".cursor", "rules");
31
- const files = readdirSync(cursorDir);
32
- expect(files.every((f) => f.endsWith(".mdc"))).toBe(true);
33
- expect(files.length).toBe(16);
34
- // Cursor-shaped frontmatter (the three keys Cursor's rule loader reads).
35
- const sample = readFileSync(join(cursorDir, files[0] ?? ""), "utf8");
36
- expect(sample).toMatch(/^description:/m);
37
- expect(sample).toMatch(/^globs:.*\*\*\/\*\.cls/m);
38
- expect(sample).toMatch(/^alwaysApply:\s*false$/m);
39
- // Old frontmatter is rewritten away (would confuse Cursor's parser).
40
- expect(sample).not.toMatch(/^name:/m);
41
- expect(sample).not.toMatch(/^triggers:/m);
42
- expect(sample).not.toMatch(/^tools_used:/m);
43
- // Body content preserved.
44
- expect(sample).toMatch(/## Playbook/);
45
- });
46
- it("installs to all targets in one call", async () => {
47
- const results = await install("all", { homeOverride: home });
48
- const claudeCount = results.filter((r) => r.target === "claude").length;
49
- const cursorCount = results.filter((r) => r.target === "cursor").length;
50
- const vscodeCount = results.filter((r) => r.target === "vscode").length;
51
- expect(claudeCount).toBe(16);
52
- expect(cursorCount).toBe(16);
53
- expect(vscodeCount).toBe(16);
54
- expect(existsSync(join(home, ".claude", "skills"))).toBe(true);
55
- expect(existsSync(join(home, ".cursor", "rules"))).toBe(true);
56
- });
57
- it("dry-run returns would-write actions and writes nothing", async () => {
58
- const results = await install("all", { homeOverride: home, dryRun: true });
59
- expect(results.every((r) => r.action === "would-write")).toBe(true);
60
- expect(existsSync(join(home, ".claude", "skills"))).toBe(false);
61
- expect(existsSync(join(home, ".cursor", "rules"))).toBe(false);
62
- });
63
- });
64
- //# sourceMappingURL=installer.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"installer.test.js","sourceRoot":"","sources":["../../src/__tests__/installer.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,IAAI,IAAY,CAAC;AAEjB,UAAU,CAAC,GAAG,EAAE;IACd,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC;AACH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAC;QAC7C,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACjC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC1D,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,yEAAyE;QACzE,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAClD,qEAAqE;QACrE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC5C,0BAA0B;QAC1B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;QACxE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;QACxE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;QACxE,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/D,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}