@dreamdata_io/verify-tracking 0.1.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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +756 -0
  3. package/dist/ai/checker.js +222 -0
  4. package/dist/ai/checker.js.map +1 -0
  5. package/dist/ai/checklist.js +190 -0
  6. package/dist/ai/checklist.js.map +1 -0
  7. package/dist/ai/cli-presets.js +27 -0
  8. package/dist/ai/cli-presets.js.map +1 -0
  9. package/dist/ai/evidence-view.js +143 -0
  10. package/dist/ai/evidence-view.js.map +1 -0
  11. package/dist/ai/local-cli.js +58 -0
  12. package/dist/ai/local-cli.js.map +1 -0
  13. package/dist/ai/openai-compatible.js +78 -0
  14. package/dist/ai/openai-compatible.js.map +1 -0
  15. package/dist/ai/response-parser.js +105 -0
  16. package/dist/ai/response-parser.js.map +1 -0
  17. package/dist/ai/types.js +2 -0
  18. package/dist/ai/types.js.map +1 -0
  19. package/dist/analysis/consent-mode.js +225 -0
  20. package/dist/analysis/consent-mode.js.map +1 -0
  21. package/dist/analysis/deployment.js +2658 -0
  22. package/dist/analysis/deployment.js.map +1 -0
  23. package/dist/analysis/diagnosis/copy.en.js +303 -0
  24. package/dist/analysis/diagnosis/copy.en.js.map +1 -0
  25. package/dist/analysis/diagnosis/diagnose.js +172 -0
  26. package/dist/analysis/diagnosis/diagnose.js.map +1 -0
  27. package/dist/analysis/diagnosis/docs.js +118 -0
  28. package/dist/analysis/diagnosis/docs.js.map +1 -0
  29. package/dist/analysis/diagnosis/index.js +5 -0
  30. package/dist/analysis/diagnosis/index.js.map +1 -0
  31. package/dist/analysis/diagnosis/rules.js +656 -0
  32. package/dist/analysis/diagnosis/rules.js.map +1 -0
  33. package/dist/analysis/diagnosis/types.js +2 -0
  34. package/dist/analysis/diagnosis/types.js.map +1 -0
  35. package/dist/cli.js +344 -0
  36. package/dist/cli.js.map +1 -0
  37. package/dist/config/env.js +100 -0
  38. package/dist/config/env.js.map +1 -0
  39. package/dist/config/preflight.js +167 -0
  40. package/dist/config/preflight.js.map +1 -0
  41. package/dist/config/user-config.js +79 -0
  42. package/dist/config/user-config.js.map +1 -0
  43. package/dist/evidence/collect.js +527 -0
  44. package/dist/evidence/collect.js.map +1 -0
  45. package/dist/evidence/consent-accept.js +377 -0
  46. package/dist/evidence/consent-accept.js.map +1 -0
  47. package/dist/evidence/consent.js +340 -0
  48. package/dist/evidence/consent.js.map +1 -0
  49. package/dist/evidence/constants.js +615 -0
  50. package/dist/evidence/constants.js.map +1 -0
  51. package/dist/evidence/globals.js +132 -0
  52. package/dist/evidence/globals.js.map +1 -0
  53. package/dist/evidence/gtm-container.js +432 -0
  54. package/dist/evidence/gtm-container.js.map +1 -0
  55. package/dist/evidence/heuristic-banner.js +107 -0
  56. package/dist/evidence/heuristic-banner.js.map +1 -0
  57. package/dist/evidence/http-probe.js +139 -0
  58. package/dist/evidence/http-probe.js.map +1 -0
  59. package/dist/evidence/init-script.js +112 -0
  60. package/dist/evidence/init-script.js.map +1 -0
  61. package/dist/evidence/network.js +365 -0
  62. package/dist/evidence/network.js.map +1 -0
  63. package/dist/evidence/preference-center.js +368 -0
  64. package/dist/evidence/preference-center.js.map +1 -0
  65. package/dist/evidence/script.js +425 -0
  66. package/dist/evidence/script.js.map +1 -0
  67. package/dist/evidence/second-page.js +332 -0
  68. package/dist/evidence/second-page.js.map +1 -0
  69. package/dist/evidence/selector-probe.js +53 -0
  70. package/dist/evidence/selector-probe.js.map +1 -0
  71. package/dist/evidence/stealth.js +21 -0
  72. package/dist/evidence/stealth.js.map +1 -0
  73. package/dist/evidence/types.js +14 -0
  74. package/dist/evidence/types.js.map +1 -0
  75. package/dist/interactive/prompt.js +31 -0
  76. package/dist/interactive/prompt.js.map +1 -0
  77. package/dist/mcp/server.js +308 -0
  78. package/dist/mcp/server.js.map +1 -0
  79. package/dist/mcp/summary.js +41 -0
  80. package/dist/mcp/summary.js.map +1 -0
  81. package/dist/report/context.js +184 -0
  82. package/dist/report/context.js.map +1 -0
  83. package/dist/report/projection.js +125 -0
  84. package/dist/report/projection.js.map +1 -0
  85. package/dist/report/quote-check.js +90 -0
  86. package/dist/report/quote-check.js.map +1 -0
  87. package/dist/report/render.js +178 -0
  88. package/dist/report/render.js.map +1 -0
  89. package/dist/report/serializers.js +124 -0
  90. package/dist/report/serializers.js.map +1 -0
  91. package/dist/report/store.js +139 -0
  92. package/dist/report/store.js.map +1 -0
  93. package/dist/run/verify.js +77 -0
  94. package/dist/run/verify.js.map +1 -0
  95. package/dist/utils/duration.js +10 -0
  96. package/dist/utils/duration.js.map +1 -0
  97. package/dist/utils/errors.js +17 -0
  98. package/dist/utils/errors.js.map +1 -0
  99. package/dist/utils/logger.js +59 -0
  100. package/dist/utils/logger.js.map +1 -0
  101. package/dist/utils/runTimingsLog.js +27 -0
  102. package/dist/utils/runTimingsLog.js.map +1 -0
  103. package/dist/utils/slug.js +27 -0
  104. package/dist/utils/slug.js.map +1 -0
  105. package/dist/version.js +10 -0
  106. package/dist/version.js.map +1 -0
  107. package/package.json +57 -0
  108. package/scripts/install.sh +314 -0
@@ -0,0 +1,132 @@
1
+ import { AJS_COOKIE_NAMES, AJS_COOKIE_PREFIX, COOKIELESS_GLOBAL_KEY, DD_COOKIE_NAMES, DREAMDATA_METHODS, mentionsDreamdata, SEGMENT_COMPAT_GLOBAL_KEY, } from "./constants.js";
2
+ export function attachConsoleCollector(page) {
3
+ const errors = [];
4
+ const warnings = [];
5
+ page.on("console", (msg) => {
6
+ const text = msg.text();
7
+ if (!mentionsDreamdata(text))
8
+ return;
9
+ if (msg.type() === "error")
10
+ errors.push(text);
11
+ else if (msg.type() === "warning")
12
+ warnings.push(text);
13
+ });
14
+ page.on("pageerror", (err) => {
15
+ if (mentionsDreamdata(err.message))
16
+ errors.push(err.message);
17
+ });
18
+ return { errors, warnings };
19
+ }
20
+ /**
21
+ * Probes one window key. `isStubQueue` is the important one: a loader snippet
22
+ * creates its global as an *array* that queues calls until the real bundle
23
+ * replaces it, so an array here means the bundle never arrived — which is
24
+ * expected when it is consent-gated, and a defect when it is not.
25
+ */
26
+ async function probeGlobals(page, keys, methodNames) {
27
+ return page
28
+ .evaluate(({ keys, methodNames }) => {
29
+ const w = window;
30
+ const out = {};
31
+ for (const key of keys) {
32
+ const value = w[key];
33
+ const exists = value !== undefined && value !== null;
34
+ out[key] = {
35
+ exists,
36
+ initialized: exists ? Boolean(value?.initialized) : false,
37
+ isStubQueue: Array.isArray(value),
38
+ methods: exists ? methodNames.filter((name) => typeof value?.[name] === "function") : [],
39
+ hasReady: typeof value?.["ready"] === "function",
40
+ };
41
+ }
42
+ return out;
43
+ }, { keys: [...keys], methodNames: [...methodNames] })
44
+ .catch(() => ({}));
45
+ }
46
+ /**
47
+ * Waits for ready() on the first global that exposes it. Segment-compatible
48
+ * installs only ever have it on window.analytics, so anchoring solely on
49
+ * window.dreamdata would report a healthy install as broken.
50
+ */
51
+ async function awaitReadyCallback(page, candidateKeys, timeoutMs) {
52
+ for (const key of candidateKeys) {
53
+ const fired = await page
54
+ .evaluate(({ key, timeoutMs }) => new Promise((resolve) => {
55
+ const target = window[key];
56
+ if (typeof target?.ready !== "function") {
57
+ resolve(false);
58
+ return;
59
+ }
60
+ const timer = setTimeout(() => resolve(false), timeoutMs);
61
+ target.ready(() => {
62
+ clearTimeout(timer);
63
+ resolve(true);
64
+ });
65
+ }), { key, timeoutMs })
66
+ .catch(() => false);
67
+ if (fired)
68
+ return { readyCallbackFired: true, readyCallbackGlobal: key };
69
+ }
70
+ return { readyCallbackFired: false, readyCallbackGlobal: null };
71
+ }
72
+ export async function readDreamdataGlobals(page, readyTimeoutMs) {
73
+ const probes = await probeGlobals(page, ["dreamdata", COOKIELESS_GLOBAL_KEY, SEGMENT_COMPAT_GLOBAL_KEY], DREAMDATA_METHODS);
74
+ const empty = { exists: false, initialized: false, isStubQueue: false, methods: [], hasReady: false };
75
+ const dd = probes["dreamdata"] ?? empty;
76
+ const cl = probes[COOKIELESS_GLOBAL_KEY] ?? empty;
77
+ const seg = probes[SEGMENT_COMPAT_GLOBAL_KEY] ?? empty;
78
+ // Prefer whichever global actually exposes ready(); dreamdata first so a
79
+ // dual install still reports the primary one.
80
+ const readyCandidates = ["dreamdata", COOKIELESS_GLOBAL_KEY, SEGMENT_COMPAT_GLOBAL_KEY].filter((key) => (probes[key] ?? empty).hasReady);
81
+ const ready = await awaitReadyCallback(page, readyCandidates, readyTimeoutMs);
82
+ const gtagUserDataSeen = await page
83
+ .evaluate(() => {
84
+ const w = window;
85
+ const calls = w.__ddEvidence?.gtagCalls ?? [];
86
+ return calls.some((call) => call.args[0] === "set" && call.args[1] === "user_data");
87
+ })
88
+ .catch(() => false);
89
+ return {
90
+ dreamdataExists: dd.exists,
91
+ initialized: dd.initialized,
92
+ supportedMethods: dd.methods.length > 0 ? dd.methods : seg.methods,
93
+ dreamdataIsStubQueue: dd.isStubQueue,
94
+ cookielessGlobalExists: cl.exists,
95
+ cookielessInitialized: cl.initialized,
96
+ segmentCompatGlobalExists: seg.exists,
97
+ segmentCompatInitialized: seg.initialized,
98
+ segmentCompatIsStubQueue: seg.isStubQueue,
99
+ gtagUserDataSeen,
100
+ ...ready,
101
+ };
102
+ }
103
+ async function readLocalStorage(page, names) {
104
+ return page
105
+ .evaluate((keys) => {
106
+ const out = {};
107
+ for (const key of keys) {
108
+ try {
109
+ out[key] = window.localStorage.getItem(key);
110
+ }
111
+ catch {
112
+ out[key] = null;
113
+ }
114
+ }
115
+ return out;
116
+ }, [...names])
117
+ .catch(() => Object.fromEntries(names.map((n) => [n, null])));
118
+ }
119
+ export async function readCookiesAndStorage(page) {
120
+ const cookies = await page.context().cookies();
121
+ const pick = (names) => Object.fromEntries(names.map((name) => [name, cookies.find((c) => c.name === name)?.value ?? null]));
122
+ const values = pick(DD_COOKIE_NAMES);
123
+ const ajsValues = pick(AJS_COOKIE_NAMES);
124
+ const anyAjsCookie = cookies.some((c) => c.name.startsWith(AJS_COOKIE_PREFIX));
125
+ const usesAjsCompatPrefix = anyAjsCookie && Object.values(values).every((v) => v === null);
126
+ const [localStorageValues, ajsLocalStorageValues] = await Promise.all([
127
+ readLocalStorage(page, DD_COOKIE_NAMES),
128
+ readLocalStorage(page, AJS_COOKIE_NAMES),
129
+ ]);
130
+ return { values, localStorageValues, ajsValues, ajsLocalStorageValues, usesAjsCompatPrefix };
131
+ }
132
+ //# sourceMappingURL=globals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globals.js","sourceRoot":"","sources":["../../src/evidence/globals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,432 @@
1
+ /**
2
+ * Reading a published GTM container's own gating rules.
3
+ *
4
+ * A container served from googletagmanager.com is a public static file whose
5
+ * `data.resource` holds the whole published version: every tag, every trigger
6
+ * compiled down to `predicates` + `rules`, and every variable. Nothing here
7
+ * needs the customer's GTM account — the container id is in their page.
8
+ *
9
+ * This exists because a tag's `consent` list is only half of its gate. A tag
10
+ * can also carry a BLOCKING trigger (an "exception" in the GTM UI), which
11
+ * stops it firing no matter what Consent Mode says. Reporting only the
12
+ * consent list describes abcam's Dreamdata tag as "gated on analytics_storage"
13
+ * when analytics_storage is granted before the banner is answered and the
14
+ * thing actually holding the tag back is an exception on a OneTrust group.
15
+ * The two are worth telling apart: one of them is the Consent Mode layer
16
+ * working, the other is a second mechanism compensating for it not working.
17
+ */
18
+ /**
19
+ * Lifts `data.resource` out of a gtm.js body.
20
+ *
21
+ * The file is minified JS with the container embedded as an object literal,
22
+ * so the JSON has to be found by brace-matching from the `{` that opens the
23
+ * object containing "resource" — string contents are skipped so a `}` inside
24
+ * a tag's HTML cannot end the scan early.
25
+ */
26
+ export function parseGtmResource(body) {
27
+ const marker = body.indexOf('"resource"');
28
+ if (marker === -1)
29
+ return null;
30
+ const start = body.lastIndexOf("{", marker);
31
+ if (start === -1)
32
+ return null;
33
+ let depth = 0;
34
+ let inString = false;
35
+ let escaped = false;
36
+ for (let i = start; i < body.length; i++) {
37
+ const ch = body[i];
38
+ if (inString) {
39
+ if (escaped)
40
+ escaped = false;
41
+ else if (ch === "\\")
42
+ escaped = true;
43
+ else if (ch === '"')
44
+ inString = false;
45
+ continue;
46
+ }
47
+ if (ch === '"')
48
+ inString = true;
49
+ else if (ch === "{")
50
+ depth++;
51
+ else if (ch === "}") {
52
+ depth--;
53
+ if (depth === 0) {
54
+ try {
55
+ return JSON.parse(body.slice(start, i + 1)).resource ?? null;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+ /**
66
+ * GTM serialises every built-in URL variable as the same `__u` function, with
67
+ * `vtp_component` naming the part it reads. Absent means the whole URL.
68
+ */
69
+ const URL_COMPONENT_NAMES = {
70
+ URL: "Page URL",
71
+ undefined: "Page URL",
72
+ HOST: "Page Hostname",
73
+ PATH: "Page Path",
74
+ QUERY: "Query String",
75
+ FRAGMENT: "Page Fragment",
76
+ PROTOCOL: "Page Protocol",
77
+ PORT: "Page Port",
78
+ IS_OUTBOUND: "the outbound-link flag",
79
+ };
80
+ /** The readable name of whatever a predicate is testing. */
81
+ function describeOperand(operand, macros) {
82
+ if (Array.isArray(operand) && operand[0] === "macro" && typeof operand[1] === "number") {
83
+ const macro = macros[operand[1]];
84
+ if (macro?.vtp_name)
85
+ return macro.vtp_name;
86
+ // GTM strips the names of built-ins and Custom JS variables from the
87
+ // published container, so the function id is all there is to report.
88
+ if (macro?.function === "__e")
89
+ return "event";
90
+ if (macro?.function === "__jsm")
91
+ return "a custom JavaScript variable";
92
+ // GTM's built-in URL variable is one function with a component selector,
93
+ // so without it a gate on the hostname and a gate on the query string
94
+ // both read as "__u" — the same name for two different conditions.
95
+ if (macro?.function === "__u")
96
+ return URL_COMPONENT_NAMES[String(macro.vtp_component)] ?? "Page URL";
97
+ if (macro?.function === "__ref")
98
+ return URL_COMPONENT_NAMES[String(macro.vtp_component)]?.replace("Page", "Referrer") ?? "Referrer";
99
+ return macro?.function ?? "an unnamed variable";
100
+ }
101
+ return typeof operand === "string" ? operand : JSON.stringify(operand);
102
+ }
103
+ /** Affirmative and negative phrasing for each predicate GTM compiles to. */
104
+ const PREDICATE_VERBS = {
105
+ _eq: ["is", "is not"],
106
+ _sw: ["starts with", "does not start with"],
107
+ _ew: ["ends with", "does not end with"],
108
+ _cn: ["contains", "does not contain"],
109
+ _css: ["matches the CSS selector", "does not match the CSS selector"],
110
+ _re: ["matches", "does not match"],
111
+ _lt: ["is less than", "is not less than"],
112
+ _le: ["is at most", "is more than"],
113
+ _gt: ["is greater than", "is not greater than"],
114
+ _ge: ["is at least", "is less than"],
115
+ };
116
+ function describePredicate(predicate, negated, macros) {
117
+ const subject = describeOperand(predicate.arg0, macros);
118
+ const fallback = predicate.function ?? "matches";
119
+ const [affirmative, negative] = PREDICATE_VERBS[predicate.function ?? ""] ?? [fallback, `does not satisfy ${fallback}`];
120
+ const object = typeof predicate.arg1 === "string" ? predicate.arg1 : JSON.stringify(predicate.arg1);
121
+ return `${subject} ${negated ? negative : affirmative} ${object}`;
122
+ }
123
+ /**
124
+ * True for a clause that names WHEN a rule gets re-evaluated rather than a
125
+ * state a visitor has to be in: any test against GTM's built-in `event`
126
+ * variable ("on gtm.js", "on gtm.dom", "on OneTrustGroupsUpdated", the
127
+ * catch-all "on every event"), or against `gtm.triggers` (a reference to
128
+ * another Trigger Group's own compiled id, e.g. "(^$|((^|,)8002876_348($|,)))"
129
+ * — internal compiler wiring, not a condition, and not one this function
130
+ * resolves recursively: see resolveTriggerGroupGates). Reporting either kind
131
+ * adds nothing and buries the clause that actually decides the outcome.
132
+ */
133
+ function isTrivialEventClause(predicate, macros) {
134
+ const subject = describeOperand(predicate.arg0, macros);
135
+ return subject === "event" || subject === "gtm.triggers";
136
+ }
137
+ /**
138
+ * The non-trivial clauses of one rule, phrased as conditions that BLOCK the
139
+ * tag.
140
+ *
141
+ * `sense` is what the rule does with the tag, and it decides the polarity. A
142
+ * `block` rule's clauses already describe when blocking happens, so an "if"
143
+ * clause blocks when it IS met. An `add` rule's clauses describe what makes
144
+ * the tag fire, so the mapping inverts: an "if" clause blocks when it is NOT
145
+ * met, and an "unless" clause blocks when it IS.
146
+ */
147
+ function describeRuleAsBlocking(rule, sense, predicates, macros) {
148
+ const blockingClause = sense === "block" ? "unless" : "if";
149
+ const conditions = [];
150
+ for (const clause of rule) {
151
+ if (clause[0] !== "if" && clause[0] !== "unless")
152
+ continue;
153
+ for (const index of clause.slice(1)) {
154
+ const predicate = typeof index === "number" ? predicates[index] : undefined;
155
+ if (!predicate || isTrivialEventClause(predicate, macros))
156
+ continue;
157
+ conditions.push(describePredicate(predicate, clause[0] === blockingClause, macros));
158
+ }
159
+ }
160
+ return conditions;
161
+ }
162
+ /** Every rule that can fire `tagIndex` directly. GTM ORs them together. */
163
+ function firingRulesFor(rules, tagIndex) {
164
+ return rules.filter((rule) => rule.some((clause) => clause[0] === "add" && clause.slice(1).includes(tagIndex)));
165
+ }
166
+ /** Matches the group id GTM embeds in a Trigger Group's own regex, e.g. "8002876_348" out of "(^$|((^|,)8002876_348($|,)))". */
167
+ const TRIGGER_GROUP_ID_IN_REGEX = /\(\^\|,\)([\w-]+)\(\$\|,\)/g;
168
+ /**
169
+ * The conditions a tag inherits from firing through a GTM Trigger Group
170
+ * instead of a direct rule on the tag itself, phrased as blocking conditions
171
+ * the same way readTagGating's direct `block` clauses are.
172
+ *
173
+ * A Trigger Group is GTM's AND of several sub-triggers — the compound
174
+ * `gtm.triggerGroup` event only fires once every one of them has. Each
175
+ * sub-trigger is compiled as its own "listening" tag (function `__tg`,
176
+ * `vtp_isListeningTag: true`), added by an ordinary rule whose conditions
177
+ * are exactly what has to hold for that one position. Those conditions are a
178
+ * REQUIREMENT for firing, the mirror image of a `block` exception: a
179
+ * required ("if") clause blocks the tag when it is NOT met, and a forbidden
180
+ * ("unless") clause blocks it when it IS met — the opposite of the mapping
181
+ * used for a direct exception, because this clause set describes what makes
182
+ * the tag fire, not what stops it.
183
+ *
184
+ * abcam expresses its OneTrust gate as an "unless" exception directly on the
185
+ * Dreamdata tag's own rule; idtdna expresses the identical gate — the
186
+ * visitor's OnetrustActiveGroups must contain C0002 — as a required
187
+ * sub-trigger inside a Trigger Group ANDed with the tag's normal "on page
188
+ * load" trigger. Reading only direct block clauses misses the second form
189
+ * entirely, which is why idtdna's blockedWhen came back empty even though a
190
+ * behaviourally equivalent gate exists and the run showed it holding.
191
+ *
192
+ * A sub-trigger position contributes nothing unless EVERY rule capable of
193
+ * satisfying it carries a real (non-trivial) condition: if a visitor can
194
+ * reach that position through even one unconditional path, the position
195
+ * imposes no actual restriction and reporting one would overclaim a gate
196
+ * that is not really there.
197
+ *
198
+ * The same overclaiming risk exists one level up, across the tag's OWN
199
+ * `add` rules — GTM ORs them together, so the tag fires if ANY one matches.
200
+ * abcam's Dreamdata tag has three: "Virtual Page View", "gtm.dom", and a
201
+ * Trigger Group requiring the URL not be /auth/login. That URL exclusion
202
+ * only governs the third path — the tag fires perfectly well through either
203
+ * of the other two regardless of the URL — so treating it as a gate on the
204
+ * tag as a whole would be wrong, not merely unhelpful. Trigger-group
205
+ * conditions are trustworthy as a GLOBAL gate only when the group is the
206
+ * tag's ONLY way to fire, i.e. it has exactly one `add` rule.
207
+ */
208
+ function resolveTriggerGroupGates(resource, tagIndex) {
209
+ const tags = resource.tags ?? [];
210
+ const rules = resource.rules ?? [];
211
+ const predicates = resource.predicates ?? [];
212
+ const macros = resource.macros ?? [];
213
+ const addRules = firingRulesFor(rules, tagIndex);
214
+ if (addRules.length !== 1)
215
+ return [];
216
+ const groupIds = new Set();
217
+ for (const rule of addRules) {
218
+ for (const clause of rule) {
219
+ if (clause[0] !== "if" && clause[0] !== "unless")
220
+ continue;
221
+ for (const index of clause.slice(1)) {
222
+ const predicate = typeof index === "number" ? predicates[index] : undefined;
223
+ if (!predicate || predicate.function !== "_re" || typeof predicate.arg1 !== "string")
224
+ continue;
225
+ if (describeOperand(predicate.arg0, macros) !== "gtm.triggers")
226
+ continue;
227
+ for (const m of predicate.arg1.matchAll(TRIGGER_GROUP_ID_IN_REGEX))
228
+ groupIds.add(m[1]);
229
+ }
230
+ }
231
+ }
232
+ if (groupIds.size === 0)
233
+ return [];
234
+ const results = [];
235
+ for (const groupId of groupIds) {
236
+ const orchestrator = tags.find((t) => t.function === "__tg" && t.vtp_uniqueTriggerId === groupId);
237
+ const rawTriggerIds = orchestrator?.vtp_triggerIds;
238
+ const firingIds = Array.isArray(rawTriggerIds)
239
+ ? rawTriggerIds.filter((v) => typeof v === "string")
240
+ : [];
241
+ for (const firingId of firingIds) {
242
+ const listenerIndex = tags.findIndex((t) => t.function === "__tg" && t.vtp_isListeningTag === true && t.vtp_firingId === firingId);
243
+ if (listenerIndex === -1)
244
+ continue;
245
+ const branches = rules.filter((rule) => rule.some((clause) => clause[0] === "add" && clause.slice(1).includes(listenerIndex)));
246
+ if (branches.length === 0)
247
+ continue;
248
+ let sawRequirement = false;
249
+ let everyBranchGated = true;
250
+ const branchConditions = [];
251
+ for (const rule of branches) {
252
+ const conditions = describeRuleAsBlocking(rule, "add", predicates, macros);
253
+ if (conditions.length > 0)
254
+ sawRequirement = true;
255
+ branchConditions.push(conditions);
256
+ if (conditions.length === 0)
257
+ everyBranchGated = false;
258
+ }
259
+ if (sawRequirement && everyBranchGated) {
260
+ results.push(branchConditions.map((c) => c.join(" and ")).join(", or "));
261
+ }
262
+ }
263
+ }
264
+ return [...new Set(results)];
265
+ }
266
+ /**
267
+ * The custom dataLayer events the tag cannot fire without.
268
+ *
269
+ * `isTrivialEventClause` drops every clause testing GTM's built-in `event`
270
+ * variable, on the grounds that it names WHEN a rule is re-evaluated rather
271
+ * than a state the visitor has to be in. That is right for `gtm.js` /
272
+ * `gtm.dom` / `gtm.load`, which GTM pushes by itself on every page: the tag
273
+ * fires there whatever the site's own code does. It is wrong for a custom
274
+ * event, which only exists if the site pushes it — verda.com's Dreamdata tag
275
+ * fires on `virtualPageView` or `cookie_consent_update` and on nothing else,
276
+ * so a release that stops pushing `virtualPageView` silently ends tracking
277
+ * while the container still reads as a healthy, correctly consent-gated
278
+ * install. That is a gate, and this is the function that reports it.
279
+ *
280
+ * Same soundness rule as the two functions above, applied per rule instead of
281
+ * by counting them: GTM ORs a tag's `add` rules together, so a required event
282
+ * is a global requirement only when EVERY firing path requires one. A path
283
+ * triggered on `gtm.js`, or on a condition this cannot read as a single event
284
+ * name (a regex match on `event`, say), makes the tag reachable without any
285
+ * custom event and returns nothing rather than overclaiming a gate. The union
286
+ * across paths is what is reported: any one of these events is enough.
287
+ */
288
+ function resolveRequiredCustomEvents(resource, tagIndex) {
289
+ const predicates = resource.predicates ?? [];
290
+ const macros = resource.macros ?? [];
291
+ const addRules = firingRulesFor(resource.rules ?? [], tagIndex);
292
+ if (addRules.length === 0)
293
+ return [];
294
+ const required = new Set();
295
+ for (const rule of addRules) {
296
+ const onThisPath = [];
297
+ for (const clause of rule) {
298
+ // Only a required ("if") equality names an event the visitor must
299
+ // receive; an "unless" clause forbids one, which is not a requirement.
300
+ if (clause[0] !== "if")
301
+ continue;
302
+ for (const index of clause.slice(1)) {
303
+ const predicate = typeof index === "number" ? predicates[index] : undefined;
304
+ if (!predicate || predicate.function !== "_eq")
305
+ continue;
306
+ if (describeOperand(predicate.arg0, macros) !== "event")
307
+ continue;
308
+ // GTM's own events fire unprompted on every page, so requiring one is
309
+ // not a gate the site can accidentally break.
310
+ if (typeof predicate.arg1 === "string" && !predicate.arg1.startsWith("gtm."))
311
+ onThisPath.push(predicate.arg1);
312
+ }
313
+ }
314
+ if (onThisPath.length === 0)
315
+ return [];
316
+ for (const name of onThisPath)
317
+ required.add(name);
318
+ }
319
+ return [...required];
320
+ }
321
+ /**
322
+ * The conditions a tag inherits from the ONLY rule that can fire it.
323
+ *
324
+ * A trigger's own conditions are not exceptions and do not compile to `block`
325
+ * clauses: they land as `if`/`unless` clauses on the rule that adds the tag.
326
+ * ptc.com's Dreamdata tag carries no exception at all — its gate is exactly
327
+ * this shape, a required Page Hostname of www.ptc.com plus a list of URL
328
+ * substrings that must not appear — so reading only `block` clauses reports
329
+ * it as ungated while a run from any other hostname watches it never fire.
330
+ *
331
+ * Same soundness rule as resolveTriggerGroupGates, for the same reason: GTM
332
+ * ORs a tag's `add` rules together, so a condition on one of several firing
333
+ * paths is not a gate on the tag. Only a sole `add` rule makes its conditions
334
+ * global. Clauses naming WHEN the rule is evaluated (`event`) or wiring it to
335
+ * a Trigger Group (`gtm.triggers`) are dropped as trivial — the latter is
336
+ * resolved properly by resolveTriggerGroupGates instead, so the two functions
337
+ * report disjoint sets rather than the same gate twice.
338
+ */
339
+ function resolveSoleFiringRuleGates(resource, tagIndex) {
340
+ const addRules = firingRulesFor(resource.rules ?? [], tagIndex);
341
+ if (addRules.length !== 1)
342
+ return [];
343
+ return describeRuleAsBlocking(addRules[0], "add", resource.predicates ?? [], resource.macros ?? []);
344
+ }
345
+ /**
346
+ * The whole gate on one tag, by index: its consent list, plus every way it
347
+ * can be held back.
348
+ *
349
+ * The single definition of what "gated" means, so the per-bundle read
350
+ * (readTagGating) and the per-tag one (readDreamdataTags) can never describe
351
+ * the same tag differently.
352
+ */
353
+ function gatingForTagIndex(resource, tagIndex) {
354
+ const macros = resource.macros ?? [];
355
+ const predicates = resource.predicates ?? [];
356
+ const rawConsent = (resource.tags ?? [])[tagIndex]?.consent;
357
+ const consent = Array.isArray(rawConsent)
358
+ ? rawConsent.filter((v) => typeof v === "string" && v !== "list")
359
+ : null;
360
+ const blockedWhen = [];
361
+ for (const rule of resource.rules ?? []) {
362
+ const blocksThisTag = rule.some((clause) => clause[0] === "block" && clause.slice(1).includes(tagIndex));
363
+ if (!blocksThisTag)
364
+ continue;
365
+ const conditions = describeRuleAsBlocking(rule, "block", predicates, macros);
366
+ if (conditions.length > 0)
367
+ blockedWhen.push(conditions.join(" and "));
368
+ }
369
+ // A tag can carry a direct exception AND fire through a Trigger Group AND
370
+ // have conditions on its own firing trigger — all three are read, since any
371
+ // one alone would understate the gate.
372
+ blockedWhen.push(...resolveTriggerGroupGates(resource, tagIndex));
373
+ blockedWhen.push(...resolveSoleFiringRuleGates(resource, tagIndex));
374
+ return {
375
+ tagIndex,
376
+ consent: consent !== null && consent.length > 0 ? consent : null,
377
+ blockedWhen: [...new Set(blockedWhen)],
378
+ requiresEvents: resolveRequiredCustomEvents(resource, tagIndex),
379
+ };
380
+ }
381
+ /** Every tag whose serialised form mentions `scriptFile`, in container order. */
382
+ function tagIndexesLoading(resource, scriptFile) {
383
+ const indexes = [];
384
+ const tags = resource.tags ?? [];
385
+ for (let i = 0; i < tags.length; i++) {
386
+ if (JSON.stringify(tags[i]).includes(scriptFile))
387
+ indexes.push(i);
388
+ }
389
+ return indexes;
390
+ }
391
+ /**
392
+ * The gating on the first tag whose serialised form mentions `scriptFile`.
393
+ *
394
+ * Matching on the injected script's filename is what ties a tag back to a
395
+ * specific bundle: the tag's own name is not in the published container.
396
+ */
397
+ export function readTagGating(resource, scriptFile) {
398
+ const tagIndex = tagIndexesLoading(resource, scriptFile)[0];
399
+ return tagIndex === undefined ? null : gatingForTagIndex(resource, tagIndex);
400
+ }
401
+ /**
402
+ * Every Dreamdata tag in the container, grouped BY TAG rather than by bundle.
403
+ *
404
+ * readTagGating answers "how is the standard bundle gated" and takes the
405
+ * first tag that loads it, which is the right shape for a per-bundle field
406
+ * and the wrong one for two questions this cannot express:
407
+ *
408
+ * - One tag loading BOTH bundles. Asking per bundle returns the same
409
+ * tagIndex twice and reads back as two independently gated installs, when
410
+ * in fact no GTM configuration can gate them apart — see TagManagerBundleTag.
411
+ * - Two tags loading the SAME bundle, which is a duplicate install rather
412
+ * than a gate, and which the first-match read silently drops.
413
+ *
414
+ * `files` maps each bundle to the filename its loader requests, so the caller
415
+ * owns the constants and this stays a pure function of the container.
416
+ */
417
+ export function readDreamdataTags(resource, files) {
418
+ const byTag = new Map();
419
+ for (const bundle of Object.keys(files)) {
420
+ for (const tagIndex of tagIndexesLoading(resource, files[bundle])) {
421
+ const bundles = byTag.get(tagIndex);
422
+ if (bundles)
423
+ bundles.push(bundle);
424
+ else
425
+ byTag.set(tagIndex, [bundle]);
426
+ }
427
+ }
428
+ return [...byTag.entries()]
429
+ .sort(([a], [b]) => a - b)
430
+ .map(([tagIndex, bundles]) => ({ ...gatingForTagIndex(resource, tagIndex), bundles }));
431
+ }
432
+ //# sourceMappingURL=gtm-container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gtm-container.js","sourceRoot":"","sources":["../../src/evidence/gtm-container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAoCH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,OAAO;gBAAE,OAAO,GAAG,KAAK,CAAC;iBACxB,IAAI,EAAE,KAAK,IAAI;gBAAE,OAAO,GAAG,IAAI,CAAC;iBAChC,IAAI,EAAE,KAAK,GAAG;gBAAE,QAAQ,GAAG,KAAK,CAAC;YACtC,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG;YAAE,QAAQ,GAAG,IAAI,CAAC;aAC3B,IAAI,EAAE,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACxB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACpB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,OAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAgC,CAAC,QAAQ,IAAI,IAAI,CAAC;gBAC/F,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,mBAAmB,GAA2B;IAClD,GAAG,EAAE,UAAU;IACf,SAAS,EAAE,UAAU;IACrB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,cAAc;IACrB,QAAQ,EAAE,eAAe;IACzB,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,wBAAwB;CACtC,CAAC;AAEF,4DAA4D;AAC5D,SAAS,eAAe,CAAC,OAAgB,EAAE,MAAkB;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QACvF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,KAAK,EAAE,QAAQ;YAAE,OAAO,KAAK,CAAC,QAAQ,CAAC;QAC3C,qEAAqE;QACrE,qEAAqE;QACrE,IAAI,KAAK,EAAE,QAAQ,KAAK,KAAK;YAAE,OAAO,OAAO,CAAC;QAC9C,IAAI,KAAK,EAAE,QAAQ,KAAK,OAAO;YAAE,OAAO,8BAA8B,CAAC;QACvE,yEAAyE;QACzE,sEAAsE;QACtE,mEAAmE;QACnE,IAAI,KAAK,EAAE,QAAQ,KAAK,KAAK;YAAE,OAAO,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,UAAU,CAAC;QACrG,IAAI,KAAK,EAAE,QAAQ,KAAK,OAAO;YAAE,OAAO,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,UAAU,CAAC;QACpI,OAAO,KAAK,EAAE,QAAQ,IAAI,qBAAqB,CAAC;IAClD,CAAC;IACD,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACzE,CAAC;AAED,4EAA4E;AAC5E,MAAM,eAAe,GAA4D;IAC/E,GAAG,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;IACrB,GAAG,EAAE,CAAC,aAAa,EAAE,qBAAqB,CAAC;IAC3C,GAAG,EAAE,CAAC,WAAW,EAAE,mBAAmB,CAAC;IACvC,GAAG,EAAE,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACrC,IAAI,EAAE,CAAC,0BAA0B,EAAE,iCAAiC,CAAC;IACrE,GAAG,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC;IAClC,GAAG,EAAE,CAAC,cAAc,EAAE,kBAAkB,CAAC;IACzC,GAAG,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC;IACnC,GAAG,EAAE,CAAC,iBAAiB,EAAE,qBAAqB,CAAC;IAC/C,GAAG,EAAE,CAAC,aAAa,EAAE,cAAc,CAAC;CACrC,CAAC;AAEF,SAAS,iBAAiB,CAAC,SAAuB,EAAE,OAAgB,EAAE,MAAkB;IACtF,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,SAAS,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,eAAe,CAAC,SAAS,CAAC,QAAQ,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,oBAAoB,QAAQ,EAAE,CAAC,CAAC;IACxH,MAAM,MAAM,GAAG,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACpG,OAAO,GAAG,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,IAAI,MAAM,EAAE,CAAC;AACpE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,oBAAoB,CAAC,SAAuB,EAAE,MAAkB;IACvE,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxD,OAAO,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,cAAc,CAAC;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,sBAAsB,CAC7B,IAAa,EACb,KAAsB,EACtB,UAA0B,EAC1B,MAAkB;IAElB,MAAM,cAAc,GAAG,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC3D,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACpC,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5E,IAAI,CAAC,SAAS,IAAI,oBAAoB,CAAC,SAAS,EAAE,MAAM,CAAC;gBAAE,SAAS;YACpE,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,2EAA2E;AAC3E,SAAS,cAAc,CAAC,KAAgB,EAAE,QAAgB;IACxD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAClH,CAAC;AAED,gIAAgI;AAChI,MAAM,yBAAyB,GAAG,6BAA6B,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,SAAS,wBAAwB,CAAC,QAAqB,EAAE,QAAgB;IACvE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;IAErC,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;YAC1B,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ;gBAAE,SAAS;YAC3D,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5E,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,QAAQ,KAAK,KAAK,IAAI,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;oBAAE,SAAS;gBAC/F,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,cAAc;oBAAE,SAAS;gBACzE,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC;oBAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzF,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,mBAAmB,KAAK,OAAO,CAAC,CAAC;QAClG,MAAM,aAAa,GAAG,YAAY,EAAE,cAAc,CAAC;QACnD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;YAC5C,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YACjE,CAAC,CAAC,EAAE,CAAC;QAEP,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,kBAAkB,KAAK,IAAI,IAAI,CAAC,CAAC,YAAY,KAAK,QAAQ,CAC7F,CAAC;YACF,IAAI,aAAa,KAAK,CAAC,CAAC;gBAAE,SAAS;YAEnC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CACrC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CACtF,CAAC;YACF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAEpC,IAAI,cAAc,GAAG,KAAK,CAAC;YAC3B,IAAI,gBAAgB,GAAG,IAAI,CAAC;YAC5B,MAAM,gBAAgB,GAAe,EAAE,CAAC;YACxC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;gBAC3E,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;oBAAE,cAAc,GAAG,IAAI,CAAC;gBACjD,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAClC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;oBAAE,gBAAgB,GAAG,KAAK,CAAC;YACxD,CAAC;YACD,IAAI,cAAc,IAAI,gBAAgB,EAAE,CAAC;gBACvC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;IAEH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAS,2BAA2B,CAAC,QAAqB,EAAE,QAAgB;IAC1E,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;IAErC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;IAChE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;YAC1B,kEAAkE;YAClE,uEAAuE;YACvE,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;gBAAE,SAAS;YACjC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5E,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,QAAQ,KAAK,KAAK;oBAAE,SAAS;gBACzD,IAAI,eAAe,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,OAAO;oBAAE,SAAS;gBAClE,sEAAsE;gBACtE,8CAA8C;gBAC9C,IAAI,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;oBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAChH,CAAC;QACH,CAAC;QACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACvC,KAAK,MAAM,IAAI,IAAI,UAAU;YAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAS,0BAA0B,CAAC,QAAqB,EAAE,QAAgB;IACzE,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;IAChE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,OAAO,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,UAAU,IAAI,EAAE,EAAE,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AACtG,CAAC;AAoBD;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,QAAqB,EAAE,QAAgB;IAChE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC;IAE7C,MAAM,UAAU,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;QACvC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,MAAM,CAAC;QAC9E,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QACxC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACzG,IAAI,CAAC,aAAa;YAAE,SAAS;QAE7B,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7E,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YAAE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACxE,CAAC;IAED,0EAA0E;IAC1E,4EAA4E;IAC5E,uCAAuC;IACvC,WAAW,CAAC,IAAI,CAAC,GAAG,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClE,WAAW,CAAC,IAAI,CAAC,GAAG,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEpE,OAAO;QACL,QAAQ;QACR,OAAO,EAAE,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAChE,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;QACtC,cAAc,EAAE,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,CAAC;KAChE,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,SAAS,iBAAiB,CAAC,QAAqB,EAAE,UAAkB;IAClE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;IACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,QAAqB,EAAE,UAAkB;IACrE,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAqB,EACrB,KAAuC;IAEvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAa,EAAE,CAAC;QACpD,KAAK,MAAM,QAAQ,IAAI,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAClE,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpC,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;;gBAC7B,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;SACxB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;SACzB,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AAC3F,CAAC"}