@reneturcios/greenlight 0.10.0 → 0.11.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.
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Git operations for Autopilot, through the GitHub Git Data API only.
3
+ *
4
+ * Autopilot fixes must never push arbitrary code, so every mutation goes
5
+ * through these primitives: create a blob, a tree, a commit, and move a
6
+ * ref. The DCO surgery (message-only commit rewrites) and the format fix
7
+ * (computed merge trees) both reduce to "commit with an exact tree, then
8
+ * move the branch ref", which this module verifies step by step.
9
+ */
10
+ import { apiGet, apiPost } from "./github.js";
11
+ /** Rene's standing DCO identity: he authorized Tree to sign non-legal attestations in his name. */
12
+ export const DCO_SIGNOFF_LINE = "Signed-off-by: Rene Turcios <95189389+CloudCorpRecords@users.noreply.github.com>";
13
+ const str = (v) => (typeof v === "string" ? v : "");
14
+ /** True when the message carries a DCO Signed-off-by trailer on any line. */
15
+ export function hasSignoff(message) {
16
+ return message
17
+ .split("\n")
18
+ .some((line) => /^Signed-off-by:\s*\S/i.test(line.trim()));
19
+ }
20
+ /** Append the sign-off line to a message that lacks it; leave signed messages untouched. */
21
+ export function withSignoff(message, line = DCO_SIGNOFF_LINE) {
22
+ if (hasSignoff(message))
23
+ return message;
24
+ return `${message.replace(/\n+$/, "")}\n\n${line}`;
25
+ }
26
+ async function defaultGetCommit(owner, repo, sha) {
27
+ const c = (await apiGet(`/repos/${owner}/${repo}/git/commits/${sha}`));
28
+ return {
29
+ sha,
30
+ treeSha: str(c.tree?.sha),
31
+ message: str(c.message),
32
+ parents: (c.parents ?? []).map((p) => str(p.sha)).filter(Boolean),
33
+ authorName: str(c.author?.name),
34
+ authorEmail: str(c.author?.email),
35
+ committerName: str(c.committer?.name),
36
+ committerEmail: str(c.committer?.email),
37
+ };
38
+ }
39
+ async function defaultCreateCommit(owner, repo, args) {
40
+ const c = (await apiPost(`/repos/${owner}/${repo}/git/commits`, args));
41
+ const sha = str(c.sha);
42
+ if (!sha)
43
+ throw new Error("Git Data API did not return a commit sha");
44
+ return sha;
45
+ }
46
+ async function defaultUpdateRef(owner, repo, branch, sha, force) {
47
+ await apiPost(`/repos/${owner}/${repo}/git/refs/heads/${branch}`, { sha, force });
48
+ }
49
+ async function defaultGetRef(owner, repo, branch) {
50
+ try {
51
+ const r = (await apiGet(`/repos/${owner}/${repo}/git/ref/heads/${branch}`));
52
+ const sha = str(r.object?.sha);
53
+ return sha || null;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ async function defaultCreateBlob(owner, repo, content) {
60
+ const b = (await apiPost(`/repos/${owner}/${repo}/git/blobs`, {
61
+ content,
62
+ encoding: "utf-8",
63
+ }));
64
+ return str(b.sha);
65
+ }
66
+ async function defaultCreateTree(owner, repo, baseTree, entries) {
67
+ const t = (await apiPost(`/repos/${owner}/${repo}/git/trees`, {
68
+ base_tree: baseTree,
69
+ tree: entries.map((e) => ({ path: e.path, mode: e.mode, type: "blob", sha: e.sha })),
70
+ }));
71
+ return str(t.sha);
72
+ }
73
+ /** The plan for one PR's commit list, given the full commit objects. */
74
+ export function planDcoSurgery(commits) {
75
+ const rewrites = [];
76
+ const anchors = [];
77
+ for (const c of commits) {
78
+ if (hasSignoff(c.message)) {
79
+ anchors.push(c.sha);
80
+ }
81
+ else {
82
+ rewrites.push({
83
+ sha: c.sha,
84
+ treeSha: c.treeSha,
85
+ message: c.message,
86
+ newMessage: withSignoff(c.message),
87
+ });
88
+ }
89
+ }
90
+ return { rewrites, anchors };
91
+ }
92
+ /**
93
+ * Apply DCO surgery on a fork branch: message-only commit rewrites with
94
+ * byte-identical trees, then force-move the branch ref. Throws before the
95
+ * ref move if any tree would change.
96
+ */
97
+ export async function applyDcoSurgery(forkOwner, forkRepo, branch, commits, deps = {}) {
98
+ const getCommit = deps.getCommit ?? defaultGetCommit;
99
+ const createCommit = deps.createCommit ?? defaultCreateCommit;
100
+ const updateRef = deps.updateRef ?? defaultUpdateRef;
101
+ const plan = planDcoSurgery(commits);
102
+ if (plan.rewrites.length === 0) {
103
+ const head = commits.length > 0 ? commits[commits.length - 1].sha : "";
104
+ return { oldHead: head, newHead: head, fixed: 0, anchored: plan.anchors.length, treesIdentical: true };
105
+ }
106
+ const full = new Map(commits.map((c) => [c.sha, c]));
107
+ const shaToNew = new Map();
108
+ let lastNewParent = "";
109
+ for (const c of commits) {
110
+ if (hasSignoff(c.message)) {
111
+ shaToNew.set(c.sha, c.sha);
112
+ lastNewParent = c.sha;
113
+ continue;
114
+ }
115
+ const orig = full.get(c.sha) ?? (await getCommit(forkOwner, forkRepo, c.sha));
116
+ const newParents = orig.parents.map((p) => shaToNew.get(p) ?? p);
117
+ // The very first unsigned commit parents a signed anchor; keep going.
118
+ const newSha = await createCommit(forkOwner, forkRepo, {
119
+ message: withSignoff(orig.message),
120
+ tree: orig.treeSha,
121
+ parents: newParents.length > 0 ? newParents : [],
122
+ author: { name: orig.authorName, email: orig.authorEmail },
123
+ committer: { name: orig.committerName, email: orig.committerEmail },
124
+ });
125
+ shaToNew.set(c.sha, newSha);
126
+ lastNewParent = newSha;
127
+ }
128
+ // Verify: every replacement tree equals its original tree.
129
+ let treesIdentical = true;
130
+ for (const c of commits) {
131
+ if (hasSignoff(c.message))
132
+ continue;
133
+ const replacement = await getCommit(forkOwner, forkRepo, shaToNew.get(c.sha) ?? "");
134
+ const original = full.get(c.sha) ?? (await getCommit(forkOwner, forkRepo, c.sha));
135
+ if (replacement.treeSha !== original.treeSha) {
136
+ treesIdentical = false;
137
+ break;
138
+ }
139
+ }
140
+ if (!treesIdentical) {
141
+ throw new Error("DCO surgery aborted: a replacement tree differs from its original");
142
+ }
143
+ const oldHead = commits[commits.length - 1].sha;
144
+ const newHead = shaToNew.get(oldHead) ?? oldHead;
145
+ await updateRef(forkOwner, forkRepo, branch, newHead, true);
146
+ return {
147
+ oldHead,
148
+ newHead,
149
+ fixed: plan.rewrites.length,
150
+ anchored: plan.anchors.length,
151
+ treesIdentical: true,
152
+ };
153
+ }
154
+ export function defaultGitOps() {
155
+ return {
156
+ getCommit: defaultGetCommit,
157
+ createCommit: defaultCreateCommit,
158
+ updateRef: defaultUpdateRef,
159
+ getRef: defaultGetRef,
160
+ createBlob: defaultCreateBlob,
161
+ createTree: defaultCreateTree,
162
+ };
163
+ }
164
+ //# sourceMappingURL=autopilot-git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-git.js","sourceRoot":"","sources":["../src/autopilot-git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Autopilot feedback classification (v0.11.0).
3
+ *
4
+ * Every actionable item on a PR gets a kind, and every bot finding gets a
5
+ * validity verdict that is VERIFIED against the code at the PR head before
6
+ * Autopilot touches anything:
7
+ *
8
+ * REAL the flagged code or pattern exists at head as described
9
+ * FALSE_POSITIVE the flagged code or pattern does not exist at head,
10
+ * with the counter-evidence quoted
11
+ * NEEDS_HUMAN the finding cannot be resolved deterministically
12
+ *
13
+ * Deterministic verification comes first. The optional LLM layer is only
14
+ * consulted where the codebase already wires it, and stays off by default.
15
+ */
16
+ import type { AuthorKind } from "./review-triage.js";
17
+ import { authorKindOf, type ClassifiedFinding } from "./review-triage.js";
18
+ import type { ClassifiedCheck } from "./ci-triage.js";
19
+ export type FeedbackKind = "ci_failure" | "review_change_request" | "bot_finding" | "merge_conflict" | "dco_gap" | "maintainer_question" | "approval" | "other";
20
+ export type FindingVerdict = "REAL" | "FALSE_POSITIVE" | "NEEDS_HUMAN";
21
+ export interface FeedbackItem {
22
+ /** Stable identity for watermarks: e.g. "review:12345", "check:build". */
23
+ id: string;
24
+ kind: FeedbackKind;
25
+ title: string;
26
+ body: string;
27
+ author: string;
28
+ authorKind: AuthorKind;
29
+ url?: string;
30
+ path?: string;
31
+ line?: number;
32
+ verdict?: FindingVerdict;
33
+ /** The evidence for the verdict: quoted code, or why it cannot be resolved. */
34
+ evidence?: string;
35
+ /** Draft reply for a human to post. Autopilot never posts comments. */
36
+ draftReply?: string;
37
+ }
38
+ export interface VerifyDeps {
39
+ /** File contents at the PR head. Returns null when the file is absent. */
40
+ fetchFileAtHead?: (path: string) => Promise<string | null>;
41
+ }
42
+ /**
43
+ * Pull candidate file paths and short code quotes out of a bot finding body.
44
+ * Review comments usually name the file explicitly (backticked paths or
45
+ * file names) or ship a diff hunk; both are usable for verification.
46
+ */
47
+ export declare function extractCandidates(body: string, anchoredPath?: string): {
48
+ paths: string[];
49
+ quotes: string[];
50
+ };
51
+ /**
52
+ * Deterministically verify one bot finding against the code at head.
53
+ * REAL when the flagged pattern exists as described; FALSE_POSITIVE when
54
+ * it demonstrably does not (counter-evidence quoted); NEEDS_HUMAN when the
55
+ * files cannot be resolved or the claim is not checkable this way.
56
+ */
57
+ export declare function verifyBotFinding(item: {
58
+ body: string;
59
+ path?: string;
60
+ }, deps?: VerifyDeps): Promise<{
61
+ verdict: FindingVerdict;
62
+ evidence: string;
63
+ }>;
64
+ /** Kind-only classification for review items, before any verification. */
65
+ export declare function classifyReviewItem(input: {
66
+ body: string;
67
+ author: string;
68
+ authorKind: AuthorKind;
69
+ reviewState?: string;
70
+ }): FeedbackKind;
71
+ /**
72
+ * Build Autopilot feedback items from review-triage findings, keeping the
73
+ * triage class and the ready reply draft. Bot findings keep kind
74
+ * "bot_finding" so the verifier can adjudicate them.
75
+ */
76
+ export declare function feedbackFromReviewFindings(findings: ClassifiedFinding[], prAuthor: string): FeedbackItem[];
77
+ /**
78
+ * Build feedback items from CI triage. Only failures the classifier leans
79
+ * "yours" or cannot place (indeterminate) become fix candidates; pre-existing
80
+ * and external blockers are reported but never touched.
81
+ */
82
+ export declare function feedbackFromCiChecks(checks: ClassifiedCheck[]): FeedbackItem[];
83
+ export interface TriageSummary {
84
+ total: number;
85
+ byKind: Record<FeedbackKind, number>;
86
+ botFindingsReal: number;
87
+ botFindingsFalsePositive: number;
88
+ botFindingsNeedsHuman: number;
89
+ ciIntroduced: number;
90
+ ciPreExistingOrExternal: number;
91
+ }
92
+ export declare function summarizeFeedback(items: FeedbackItem[]): TriageSummary;
93
+ export { authorKindOf };
@@ -0,0 +1,222 @@
1
+ import { authorKindOf } from "./review-triage.js";
2
+ /**
3
+ * Pull candidate file paths and short code quotes out of a bot finding body.
4
+ * Review comments usually name the file explicitly (backticked paths or
5
+ * file names) or ship a diff hunk; both are usable for verification.
6
+ */
7
+ export function extractCandidates(body, anchoredPath) {
8
+ const paths = new Set();
9
+ if (anchoredPath)
10
+ paths.add(anchoredPath);
11
+ const backtick = body.match(/`([^`\n]{1,120})`/g) ?? [];
12
+ for (const b of backtick) {
13
+ const inner = b.slice(1, -1).trim();
14
+ if (/^[a-zA-Z0-9_./-]+\.[a-zA-Z0-9]{1,8}$/.test(inner) || inner.startsWith("src/") || inner.startsWith("packages/")) {
15
+ paths.add(inner.replace(/^\.\//, ""));
16
+ }
17
+ }
18
+ const quoted = [];
19
+ for (const m of body.matchAll(/^```(?:\w+)?\n([\s\S]{1,800}?)\n```/gm)) {
20
+ const snippet = m[1].trim();
21
+ if (snippet.length >= 12)
22
+ quoted.push(snippet);
23
+ }
24
+ const inline = body.match(/`([^`]{12,160})`/g) ?? [];
25
+ for (const b of inline)
26
+ quoted.push(b.slice(1, -1));
27
+ return { paths: [...paths].slice(0, 4), quotes: quoted.slice(0, 4) };
28
+ }
29
+ const normalize = (s) => s.replace(/\s+/g, " ").trim();
30
+ /**
31
+ * Deterministically verify one bot finding against the code at head.
32
+ * REAL when the flagged pattern exists as described; FALSE_POSITIVE when
33
+ * it demonstrably does not (counter-evidence quoted); NEEDS_HUMAN when the
34
+ * files cannot be resolved or the claim is not checkable this way.
35
+ */
36
+ export async function verifyBotFinding(item, deps = {}) {
37
+ const { paths, quotes } = extractCandidates(item.body, item.path);
38
+ const fetchFile = deps.fetchFileAtHead;
39
+ if (paths.length === 0 && quotes.length === 0) {
40
+ return {
41
+ verdict: "NEEDS_HUMAN",
42
+ evidence: "finding names no file and quotes no code to verify against",
43
+ };
44
+ }
45
+ if (!fetchFile) {
46
+ return {
47
+ verdict: "NEEDS_HUMAN",
48
+ evidence: "no file fetcher available, cannot verify against head",
49
+ };
50
+ }
51
+ const texts = [];
52
+ for (const p of paths) {
53
+ try {
54
+ const content = await fetchFile(p);
55
+ if (content !== null)
56
+ texts.push(content);
57
+ }
58
+ catch {
59
+ // unreadable file: keep going with what we have
60
+ }
61
+ }
62
+ if (texts.length === 0) {
63
+ return {
64
+ verdict: "NEEDS_HUMAN",
65
+ evidence: `could not read any of the referenced files (${paths.join(", ")}) at head`,
66
+ };
67
+ }
68
+ const haystack = normalize(texts.join("\n"));
69
+ let real = false;
70
+ let falsePositive = false;
71
+ let counter = "";
72
+ for (const q of quotes) {
73
+ const needle = normalize(q);
74
+ if (needle.length < 12)
75
+ continue;
76
+ if (haystack.includes(needle)) {
77
+ real = true;
78
+ }
79
+ else if (!counter) {
80
+ // A quoted code block that does not exist at head is a candidate
81
+ // false positive, unless it is clearly a suggestion (diff-like).
82
+ if (!/^[+-]/.test(q.trim()) && !/\bsuggest\b|\binstead\b/i.test(item.body)) {
83
+ falsePositive = true;
84
+ counter = q.length > 160 ? q.slice(0, 160) + "..." : q;
85
+ }
86
+ }
87
+ }
88
+ if (real) {
89
+ return { verdict: "REAL", evidence: `quoted code is present at head (${paths.length} file(s) checked)` };
90
+ }
91
+ if (falsePositive) {
92
+ return {
93
+ verdict: "FALSE_POSITIVE",
94
+ evidence: `the finding quotes "${counter}", which does not exist at head in any referenced file`,
95
+ };
96
+ }
97
+ return {
98
+ verdict: "NEEDS_HUMAN",
99
+ evidence: "the finding's claim could not be reduced to a code lookup",
100
+ };
101
+ }
102
+ /** Kind-only classification for review items, before any verification. */
103
+ export function classifyReviewItem(input) {
104
+ const body = input.body;
105
+ const state = (input.reviewState ?? "").toUpperCase();
106
+ if (state === "APPROVED")
107
+ return "approval";
108
+ if (state === "CHANGES_REQUESTED")
109
+ return "review_change_request";
110
+ if (input.authorKind === "bot")
111
+ return "bot_finding";
112
+ // Human authors: questions and requests are maintainer input, not noise.
113
+ if (/\?\s*$/.test(body.trim()) || /\?(\s|$)/.test(body.slice(0, 200)))
114
+ return "maintainer_question";
115
+ if (/\b(please|could you|would you|can you)\b/i.test(body))
116
+ return "maintainer_question";
117
+ return "other";
118
+ }
119
+ /**
120
+ * Build Autopilot feedback items from review-triage findings, keeping the
121
+ * triage class and the ready reply draft. Bot findings keep kind
122
+ * "bot_finding" so the verifier can adjudicate them.
123
+ */
124
+ export function feedbackFromReviewFindings(findings, prAuthor) {
125
+ const out = [];
126
+ for (const f of findings) {
127
+ const isAuthor = f.author === prAuthor;
128
+ if (isAuthor)
129
+ continue; // the author's own comments are replies, not incoming
130
+ const kind = f.class === "likely-noise"
131
+ ? "other"
132
+ : classifyReviewItem({ body: f.summary, author: f.author, authorKind: f.authorKind });
133
+ out.push({
134
+ id: `finding:${f.author}:${oneLineKey(f.summary)}`,
135
+ kind: f.class === "likely-noise" ? "other" : kind,
136
+ title: f.summary.slice(0, 120),
137
+ body: f.summary,
138
+ author: f.author,
139
+ authorKind: f.authorKind,
140
+ path: f.path,
141
+ line: f.line,
142
+ // Bot findings are verified against head by the Autopilot run after this.
143
+ verdict: undefined,
144
+ evidence: f.reason,
145
+ draftReply: f.draft || undefined,
146
+ });
147
+ }
148
+ return out;
149
+ }
150
+ function oneLineKey(s) {
151
+ return s.replace(/\s+/g, " ").trim().slice(0, 60);
152
+ }
153
+ /**
154
+ * Build feedback items from CI triage. Only failures the classifier leans
155
+ * "yours" or cannot place (indeterminate) become fix candidates; pre-existing
156
+ * and external blockers are reported but never touched.
157
+ */
158
+ export function feedbackFromCiChecks(checks) {
159
+ return checks
160
+ .filter((c) => c.conclusion !== "success")
161
+ .map((c) => ({
162
+ id: `check:${c.name}`,
163
+ kind: "ci_failure",
164
+ title: `CI: ${c.name} (${c.conclusion})`,
165
+ body: [c.name, c.conclusion, c.failureLines?.join(" | ") ?? ""].filter(Boolean).join(" - "),
166
+ author: "ci",
167
+ authorKind: "bot",
168
+ url: c.detailsUrl,
169
+ evidence: c.evidence,
170
+ verdict: c.class === "likely-yours"
171
+ ? "REAL"
172
+ : c.class === "indeterminate"
173
+ ? "NEEDS_HUMAN"
174
+ : "FALSE_POSITIVE",
175
+ }));
176
+ }
177
+ export function summarizeFeedback(items) {
178
+ const byKind = {
179
+ ci_failure: 0,
180
+ review_change_request: 0,
181
+ bot_finding: 0,
182
+ merge_conflict: 0,
183
+ dco_gap: 0,
184
+ maintainer_question: 0,
185
+ approval: 0,
186
+ other: 0,
187
+ };
188
+ let botFindingsReal = 0;
189
+ let botFindingsFalsePositive = 0;
190
+ let botFindingsNeedsHuman = 0;
191
+ let ciIntroduced = 0;
192
+ let ciPreExistingOrExternal = 0;
193
+ for (const i of items) {
194
+ byKind[i.kind] += 1;
195
+ if (i.kind === "bot_finding") {
196
+ if (i.verdict === "REAL")
197
+ botFindingsReal += 1;
198
+ else if (i.verdict === "FALSE_POSITIVE")
199
+ botFindingsFalsePositive += 1;
200
+ else if (i.verdict === "NEEDS_HUMAN")
201
+ botFindingsNeedsHuman += 1;
202
+ }
203
+ if (i.kind === "ci_failure") {
204
+ if (i.verdict === "REAL")
205
+ ciIntroduced += 1;
206
+ else
207
+ ciPreExistingOrExternal += 1;
208
+ }
209
+ }
210
+ return {
211
+ total: items.length,
212
+ byKind,
213
+ botFindingsReal,
214
+ botFindingsFalsePositive,
215
+ botFindingsNeedsHuman,
216
+ ciIntroduced,
217
+ ciPreExistingOrExternal,
218
+ };
219
+ }
220
+ // Re-export for callers that only need the author kind helper.
221
+ export { authorKindOf };
222
+ //# sourceMappingURL=autopilot-triage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-triage.js","sourceRoot":"","sources":["../src/autopilot-triage.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAA0B,MAAM,oBAAoB,CAAC;AAsC1E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,YAAqB;IAInE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,IAAI,YAAY;QAAE,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC;IACxD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,sCAAsC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACpH,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,uCAAuC,CAAC,EAAE,CAAC;QACvE,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAqC,EACrC,OAAmB,EAAE;IAErB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC;IACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,OAAO;YACL,OAAO,EAAE,aAAa;YACtB,QAAQ,EAAE,4DAA4D;SACvE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,aAAa;YACtB,QAAQ,EAAE,uDAAuD;SAClE,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC;YACnC,IAAI,OAAO,KAAK,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE,aAAa;YACtB,QAAQ,EAAE,+CAA+C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW;SACrF,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE;YAAE,SAAS;QACjC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;aAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,iEAAiE;YACjE,iEAAiE;YACjE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3E,aAAa,GAAG,IAAI,CAAC;gBACrB,OAAO,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,mCAAmC,KAAK,CAAC,MAAM,mBAAmB,EAAE,CAAC;IAC3G,CAAC;IACD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO;YACL,OAAO,EAAE,gBAAgB;YACzB,QAAQ,EAAE,uBAAuB,OAAO,wDAAwD;SACjG,CAAC;IACJ,CAAC;IACD,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,QAAQ,EAAE,2DAA2D;KACtE,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,kBAAkB,CAAC,KAKlC;IACC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACtD,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC5C,IAAI,KAAK,KAAK,mBAAmB;QAAE,OAAO,uBAAuB,CAAC;IAClE,IAAI,KAAK,CAAC,UAAU,KAAK,KAAK;QAAE,OAAO,aAAa,CAAC;IACrD,yEAAyE;IACzE,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAAE,OAAO,qBAAqB,CAAC;IACpG,IAAI,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,qBAAqB,CAAC;IACzF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAA6B,EAC7B,QAAgB;IAEhB,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;QACvC,IAAI,QAAQ;YAAE,SAAS,CAAC,sDAAsD;QAC9E,MAAM,IAAI,GACR,CAAC,CAAC,KAAK,KAAK,cAAc;YACxB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1F,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,WAAW,CAAC,CAAC,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;YAClD,IAAI,EAAE,CAAC,CAAC,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;YACjD,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;YAC9B,IAAI,EAAE,CAAC,CAAC,OAAO;YACf,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,0EAA0E;YAC1E,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,CAAC,CAAC,MAAM;YAClB,UAAU,EAAE,CAAC,CAAC,KAAK,IAAI,SAAS;SACjC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,OAAO,MAAM;SACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC;SACzC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE;QACrB,IAAI,EAAE,YAAqB;QAC3B,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,GAAG;QACxC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3F,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,KAAmB;QAC/B,GAAG,EAAE,CAAC,CAAC,UAAU;QACjB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,OAAO,EACL,CAAC,CAAC,KAAK,KAAK,cAAc;YACxB,CAAC,CAAE,MAAgB;YACnB,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,eAAe;gBAC3B,CAAC,CAAE,aAAuB;gBAC1B,CAAC,CAAE,gBAA0B;KACpC,CAAC,CAAC,CAAC;AACR,CAAC;AAYD,MAAM,UAAU,iBAAiB,CAAC,KAAqB;IACrD,MAAM,MAAM,GAAG;QACb,UAAU,EAAE,CAAC;QACb,qBAAqB,EAAE,CAAC;QACxB,WAAW,EAAE,CAAC;QACd,cAAc,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;QACV,mBAAmB,EAAE,CAAC;QACtB,QAAQ,EAAE,CAAC;QACX,KAAK,EAAE,CAAC;KACuB,CAAC;IAClC,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,wBAAwB,GAAG,CAAC,CAAC;IACjC,IAAI,qBAAqB,GAAG,CAAC,CAAC;IAC9B,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,uBAAuB,GAAG,CAAC,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC7B,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM;gBAAE,eAAe,IAAI,CAAC,CAAC;iBAC1C,IAAI,CAAC,CAAC,OAAO,KAAK,gBAAgB;gBAAE,wBAAwB,IAAI,CAAC,CAAC;iBAClE,IAAI,CAAC,CAAC,OAAO,KAAK,aAAa;gBAAE,qBAAqB,IAAI,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM;gBAAE,YAAY,IAAI,CAAC,CAAC;;gBACvC,uBAAuB,IAAI,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,MAAM;QACN,eAAe;QACf,wBAAwB;QACxB,qBAAqB;QACrB,YAAY;QACZ,uBAAuB;KACxB,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,OAAO,EAAE,YAAY,EAAE,CAAC"}