PageSourceSearch

https://app.socialninja.ai/src/pages/query-builder/QueryAnalyticsPage.tsx

js socialninja.ai collected 2026-10-05 15:10:44 UTC 64,915 bytes, 827 lines download raw bytes

1import { createHotContext as __vite__createHotContext } from "/@vite/client";import.meta.hot = __vite__createHotContext("/src/pages/query-builder/QueryAnalyticsPage.tsx");const useState = __vite__cjsImport0_react["useState"];const _jsxDEV = __vite__cjsImport13_react_jsxDevRuntime["jsxDEV"]; const _Fragment = __vite__cjsImport13_react_jsxDevRuntime["Fragment"];import __vite__cjsImport0_react from "/node_modules/.vite/deps/react.js?v=0fe5e139";
2import { useNavigate, useParams } from "/node_modules/.vite/deps/react-router-dom.js?v=0fe5e139";
3import { Doughnut, Line } from "/node_modules/.vite/deps/react-chartjs-2.js?v=0fe5e139";
4import { Chart as ChartJS, ArcElement, CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Filler } from "/node_modules/.vite/deps/chart__js.js?v=0fe5e139";
5import ChartDataLabels from "/node_modules/.vite/deps/chartjs-plugin-datalabels.js?v=0fe5e139";
6import { ArrowLeft, MessageCircle, Activity, Zap, Heart, Globe } from "/node_modules/.vite/deps/lucide-react.js?v=0fe5e139";
7import { Heading } from "/src/components/ui/Heading.tsx";
8import { Text } from "/src/components/ui/Text.tsx";
9import { Button } from "/src/components/ui/Button.tsx";
10import { PageSpinner } from "/src/components/ui/Spinner.tsx";
11import { cn } from "/src/lib/utils.ts";
12import { useGetQueryQuery, useGetAnalyticsQuery } from "/src/store/api/queryBuilderApi.ts";
13import { lineEndpointLabels, sliceValueLabels } from "/src/utils/chartDataLabels.ts";
14var _jsxFileName = "/app/src/pages/query-builder/QueryAnalyticsPage.tsx";
15import __vite__cjsImport13_react_jsxDevRuntime from "/node_modules/.vite/deps/react_jsx-dev-runtime.js?v=0fe5e139";
16var _s = $RefreshSig$();
17ChartJS.register(ArcElement, CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Filler, ChartDataLabels);
18// The plugin registry is process-wide (every Chart.js instance in the app shares it) — off by
19// default here, opted in per dataset below, so it can't leak onto some other chart unexpectedly.
20ChartJS.defaults.plugins.datalabels = { display: false };
21// Backend's real emotion label set: anger/fear/joy/sadness/disgust/surprise/none.
22const EMOTION_COLORS = {
23	joy: "bg-orange-400",
24	surprise: "bg-violet-500",
25	anger: "bg-red-500",
26	fear: "bg-blue-500",
27	sadness: "bg-gray-400",
28	disgust: "bg-emerald-500",
29	none: "bg-slate-300"
30};
31const DEFAULT_EMOTION_COLOR = "bg-indigo-400";
32const languageDisplayNames = new Intl.DisplayNames(["en"], { type: "language" });
33function languageName(code) {
34	try {
35		return languageDisplayNames.of(code) ?? code;
36	} catch {
37		return code;
38	}
39}
40function BreakdownCard({ title, icon: Icon, iconColor, rows, emptyNote }) {
41	return /* @__PURE__ */ _jsxDEV("div", {
42		className: "rounded-xl border border-gray-200 bg-white p-5 dark:border-gray-700 dark:bg-gray-800",
43		children: [/* @__PURE__ */ _jsxDEV("div", {
44			className: "mb-4 flex items-center gap-2",
45			children: [/* @__PURE__ */ _jsxDEV(Icon, { className: `h-4 w-4 ${iconColor}` }, void 0, false, {
46				fileName: _jsxFileName,
47				lineNumber: 70,
48				columnNumber: 9
49			}, this), /* @__PURE__ */ _jsxDEV(Text, {
50				weight: "semibold",
51				children: title
52			}, void 0, false, {
53				fileName: _jsxFileName,
54				lineNumber: 71,
55				columnNumber: 9
56			}, this)]
57		}, void 0, true, {
58			fileName: _jsxFileName,
59			lineNumber: 69,
60			columnNumber: 7
61		}, this), rows.length === 0 ? /* @__PURE__ */ _jsxDEV(Text, {
62			tone: "secondary",
63			children: emptyNote
64		}, void 0, false, {
65			fileName: _jsxFileName,
66			lineNumber: 74,
67			columnNumber: 9
68		}, this) : /* @__PURE__ */ _jsxDEV("div", {
69			className: "space-y-3",
70			children: rows.map((r) => {
71				const color = EMOTION_COLORS[r.label.toLowerCase()] ?? DEFAULT_EMOTION_COLOR;
72				return /* @__PURE__ */ _jsxDEV("div", {
73					className: "flex items-center gap-3",
74					children: [
75						/* @__PURE__ */ _jsxDEV("span", { className: cn("h-2 w-2 shrink-0 rounded-full", color) }, void 0, false, {
76							fileName: _jsxFileName,
77							lineNumber: 81,
78							columnNumber: 17
79						}, this),
80						/* @__PURE__ */ _jsxDEV(Text, {
81							as: "span",
82							variant: "label",
83							className: "w-16 shrink-0",
84							children: r.label
85						}, void 0, false, {
86							fileName: _jsxFileName,
87							lineNumber: 82,
88							columnNumber: 17
89						}, this),
90						/* @__PURE__ */ _jsxDEV("div", {
91							className: "h-1.5 flex-1 overflow-hidden rounded-full bg-gray-100 dark:bg-gray-700",
92							children: /* @__PURE__ */ _jsxDEV("div", {
93								className: cn("h-full rounded-full", color),
94								style: { width: `${r.percent}%` }
95							}, void 0, false, {
96								fileName: _jsxFileName,
97								lineNumber: 84,
98								columnNumber: 19
99							}, this)
100						}, void 0, false, {
101							fileName: _jsxFileName,
102							lineNumber: 83,
103							columnNumber: 17
104						}, this),
105						/* @__PURE__ */ _jsxDEV(Text, {
106							as: "span",
107							variant: "label",
108							weight: "semibold",
109							className: "w-10 shrink-0 text-right",
110							children: [r.percent, "%"]
111						}, void 0, true, {
112							fileName: _jsxFileName,
113							lineNumber: 86,
114							columnNumber: 17
115						}, this)
116					]
117				}, r.label, true, {
118					fileName: _jsxFileName,
119					lineNumber: 80,
120					columnNumber: 15
121				}, this);
122			})
123		}, void 0, false, {
124			fileName: _jsxFileName,
125			lineNumber: 76,
126			columnNumber: 9
127		}, this)]
128	}, void 0, true, {
129		fileName: _jsxFileName,
130		lineNumber: 68,
131		columnNumber: 5
132	}, this);
133}
134_c = BreakdownCard;
135function coverageNote(s) {
136	if (s.totalMatched <= 0) return "No matched posts yet.";
137	if (s.sampleTooSmall) return `only ${s.classifiedCount} of ${s.totalMatched} posts classified`;
138	const coveragePercent = Math.round(s.classifiedCount / s.totalMatched * 100);
139	return `±${s.marginPoints} pts · based on ${coveragePercent}% of matched posts`;
140}
141/** The margin sentence that sits with the number, not on another screen: how
142*  far this percentage could be from the truth, and what it was measured over.
143*  Kept verbally distinct from per-item model confidence — the two are
144*  different quantities and a reader must never merge them. */
145function marginNote(s) {
146	if (s.totalMatched <= 0) return "No matched posts yet.";
147	if (s.sampleTooSmall) {
148		return `Not enough classified posts to quote a percentage — ${s.classifiedCount} of ${s.totalMatched} classified so far.`;
149	}
150	return `±${s.marginPoints} points at 95% confidence, from ${s.classifiedCount} of ` + `${s.totalMatched} matched posts classified. This is how sure we are of the ` + `percentage, not how sure the model is about any one post. Percentages ` + `describe post captions; audience reaction in the comments is not counted here.`;
151}
152function formatBucketLabel(iso, granularity) {
153	const date = new Date(iso);
154	if (granularity === "month") return date.toLocaleDateString(undefined, {
155		month: "short",
156		year: "numeric"
157	});
158	return date.toLocaleDateString(undefined, {
159		month: "short",
160		day: "numeric"
161	});
162}
163export default function QueryAnalyticsPage() {
164	_s();
165	const navigate = useNavigate();
166	const { id } = useParams();
167	const { data: query, isLoading: queryLoading, isFetching: queryFetching } = useGetQueryQuery(id, { skip: !id });
168	const [fromDate, setFromDate] = useState("");
169	const [toDate, setToDate] = useState("");
170	const [granularity, setGranularity] = useState("month");
171	const [applyFilters, setApplyFilters] = useState(true);
172	const { data: analytics, isLoading: analyticsLoading, isFetching: analyticsFetching, isError: analyticsError } = useGetAnalyticsQuery({
173		id,
174		from: fromDate || undefined,
175		to: toDate || undefined,
176		granularity,
177		applyFilters
178	}, { skip: !id });
179	// isFetching (not just isLoading) so switching back to an
180	// already-cached date range/granularity still shows the shared page
181	// loader instead of silently sitting on the previous selection's data.
182	if (queryLoading || queryFetching) {
183		return /* @__PURE__ */ _jsxDEV(PageSpinner, {}, void 0, false, {
184			fileName: _jsxFileName,
185			lineNumber: 156,
186			columnNumber: 12
187		}, this);
188	}
189	if (!query) {
190		return /* @__PURE__ */ _jsxDEV("div", {
191			className: "p-6",
192			children: [/* @__PURE__ */ _jsxDEV(Text, {
193				tone: "secondary",
194				children: "Query not found."
195			}, void 0, false, {
196				fileName: _jsxFileName,
197				lineNumber: 162,
198				columnNumber: 9
199			}
199, this), /* @__PURE__ */ _jsxDEV(Button, {
200				variant: "outline",
201				className: "mt-3",
202				onClick: () => navigate("/listen/query-builder"),
203				children: "Back to Query Builder"
204			}, void 0, false, {
205				fileName: _jsxFileName,
206				lineNumber: 163,
207				columnNumber: 9
208			}, this)]
209		}, void 0, true, {
210			fileName: _jsxFileName,
211			lineNumber: 161,
212			columnNumber: 7
213		}, this);
214	}
215	// A percentage off a handful of classified posts is not an answer, it is a
216	// coincidence — below the backend's minimum sample it is withheld entirely
217	// rather than shown with a caveat nobody reads.
218	const tooFewClassified = analytics?.positiveSentiment.sampleTooSmall ?? false;
219	const positivePercent = tooFewClassified ? null : analytics?.positiveSentiment.percent ?? null;
220	const negativePercent = tooFewClassified ? null : analytics?.negativeSentiment.percent ?? null;
221	const neutralPercent = positivePercent !== null && negativePercent !== null ? Math.max(0, 100 - positivePercent - negativePercent) : null;
222	const sentimentSplit = [
223		{
224			label: "Positive",
225			percent: positivePercent ?? 0,
226			color: "#22c55e"
227		},
228		{
229			label: "Neutral",
230			percent: neutralPercent ?? 0,
231			color: "#9ca3af"
232		},
233		{
234			label: "Negative",
235			percent: negativePercent ?? 0,
236			color: "#ef4444"
237		}
238	];
239	const statCards = [
240		{
241			label: "Total Mentions",
242			value: analytics ? analytics.topicVolume.toLocaleString() : "0",
243			sub: analytics ? "Matched this date range" : "No data yet",
244			icon: MessageCircle,
245			color: "bg-pink-100 text-pink-600"
246		},
247		{
248			label: "Positive Sentiment",
249			value: positivePercent !== null ? `${positivePercent}%` : "—",
250			sub: analytics ? coverageNote(analytics.positiveSentiment) : "No data yet",
251			icon: Activity,
252			color: "bg-green-100 text-green-600"
253		},
254		{
255			label: "Engagements",
256			value: analytics ? analytics.engagements.toLocaleString() : "0",
257			sub: "Likes + comments + shares, this date range",
258			icon: Zap,
259			color: "bg-amber-100 text-amber-600"
260		}
261	];
262	const emotionRows = analytics?.emotionBreakdown ?? [];
263	const languageRows = (analytics?.languageBreakdown ?? []).map((r) => ({
264		...r,
265		label: languageName(r.label)
266	}));
267	return /* @__PURE__ */ _jsxDEV("div", {
268		className: "space-y-6 p-6",
269		children: [/* @__PURE__ */ _jsxDEV("div", {
270			className: "flex flex-wrap items-center justify-between gap-3",
271			children: [/* @__PURE__ */ _jsxDEV("div", {
272				className: "flex items-center gap-3",
273				children: [/* @__PURE__ */ _jsxDEV(Button, {
274					variant: "ghost",
275					size: "icon",
276					onClick: () => navigate("/listen/query-builder"),
277					"aria-label": "Back",
278					children: /* @__PURE__ */ _jsxDEV(ArrowLeft, { className: "h-5 w-5" }, void 0, false, {
279						fileName: _jsxFileName,
280						lineNumber: 217,
281						columnNumber: 13
282					}, this)
283				}, void 0, false, {
284					fileName: _jsxFileName,
285					lineNumber: 216,
286					columnNumber: 11
287				}, this), /* @__PURE__ */ _jsxDEV("div", { children: [/* @__PURE__ */ _jsxDEV(Heading, {
288					variant: "h2",
289					children: [query.name, " — Analytics"]
290				}, void 0, true, {
291					fileName: _jsxFileName,
292					lineNumber: 220,
293					columnNumber: 13
294				}, this), /* @__PURE__ */ _jsxDEV(Text, {
295					tone: "secondary",
296					children: "Follows this query's own date range"
297				}, void 0, false, {
298					fileName: _jsxFileName,
299					lineNumber: 221,
300					columnNumber: 13
301				}, this)] }, void 0, true, {
302					fileName: _jsxFileName,
303					lineNumber: 219,
304					columnNumber: 11
305				}, this)]
306			}, void 0, true, {
307				fileName: _jsxFileName,
308				lineNumber: 215,
309				columnNumber: 9
310			}, this), /* @__PURE__ */ _jsxDEV("div", {
311				className: "flex flex-wrap items-center gap-2",
312				children: [
313					/* @__PURE__ */ _jsxDEV("div", {
314						className: "flex items-center gap-2",
315						children: [
316							/* @__PURE__ */ _jsxDEV(Text, {
317								as: "span",
318								variant: "caption",
319								tone: "light",
320								children: "From"
321							}, void 0, false, {
322								fileName: _jsxFileName,
323								lineNumber: 227,
324								columnNumber: 13
325							}, this),
326							/* @__PURE__ */ _jsxDEV("input", {
327								type: "date",
328								value: fromDate,
329								onChange: (e) => setFromDate(e.target.value),
330								className: "h-9 rounded-lg border border-gray-300 px-2 text-sm dark:border-gray-600 dark:bg-gray-800"
331							}, void 0, false, {
332								fileName: _jsxFileName,
333								lineNumber: 228,
334								columnNumber: 13
335							}, this),
336							/* @__PURE__ */ _jsxDEV(Text, {
337								as: "span",
338								variant: "caption",
339								tone: "light",
340								children: "To"
341							}, void 0, false, {
342								fileName: _jsxFileName,
343								lineNumber: 234,
344								columnNumber: 13
345							}, this),
346							/* @__PURE__ */ _jsxDEV("input", {
347								type: "date",
348								value: toDate,
349								onChange: (e) => setToDate(e.target.value),
350								className: "h-9 rounded-lg border border-gray-300 px-2 text-sm dark:border-gray-600 dark:bg-gray-800"
351							}, void 0, false, {
352								fileName: _jsxFileName,
353								lineNumber: 235,
354								columnNumber: 13
355							}, this)
356						]
357					}, void 0, true, {
358						fileName: _jsxFileName,
359						lineNumber: 226,
360						columnNumber: 11
361					}, this),
362					/* @__PURE__ */ _jsxDEV("div", {
363						className: "flex items-center gap-1 rounded-lg border border-gray-200 p-1 dark:border-gray-700",
364						children: [
365							"day",
366							"week",
367							"month"
368						].map((g) => /* @__PURE__ */ _jsxDEV("button", {
369							onClick: () => setGranularity(g),
370							className: cn("rounded-md px-3 py-1 text-sm font-medium capitalize transition-colors", granularity === g ? "bg-primary text-white" : "text-text-secondary hover:bg-secondary"),
371							children: g
372						}, g, false, {
373							fileName: _jsxFileName,
374							lineNumber: 244,
375							columnNumber: 15
376						}, this))
377					}, void 0, false, {
378						fileName: _jsxFileName,
379						lineNumber: 242,
380						columnNumber: 11
381					}, this),
382					/* @__PURE__ */ _jsxDEV("label", {
383						className: "flex cursor-pointer items-center gap-2 rounded-lg border border-gray-200 px-3 py-1.5 text-sm dark:border-gray-700",
384						children: [/* @__PURE__ */ _jsxDEV("input", {
385							type: "checkbox",
386							checked: applyFilters,
387							onChange: (e) => setApplyFilters(e.target.checked),
388							className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary"
389						}, void 0, false, {
390							fileName: _jsxFileName,
391							lineNumber: 257,
392							columnNumber: 13
393						}, this), /* @__PURE__ */ _jsxDEV("span", {
394							className: "text-text-secondary",
395							children: "Show with filters only"
396						}, void 0, false, {
397							fileName: _jsxFileName,
398							lineNumber: 263,
399							columnNumber: 13
400						}, this)]
401					}, void 0, true, {
402						fileName: _jsxFileName,
403						lineNumber: 256,
404						columnNumber: 11
405					}, this)
406				]
407			}, void 0, true, {
408				fileName: _jsxFileName,
409				lineNumber: 225,
410				columnNumber: 9
411			}, this)]
412		}, void 0, true, {
413			fileName: _jsxFileName,
414			lineNumber: 214,
415			columnNumber: 7
416		}
416, this), analyticsLoading || analyticsFetching ? /* @__PURE__ */ _jsxDEV(PageSpinner, {}, void 0, false, {
417			fileName: _jsxFileName,
418			lineNumber: 269,
419			columnNumber: 9
420		}, this) : analyticsError ? /* @__PURE__ */ _jsxDEV("div", {
421			className: "rounded-xl border border-gray-200 bg-white p-8 text-center dark:border-gray-700 dark:bg-gray-800",
422			children: /* @__PURE__ */ _jsxDEV(Text, {
423				className: "text-red-500",
424				children: "Failed to load analytics."
425			}, void 0, false, {
426				fileName: _jsxFileName,
427				lineNumber: 272,
428				columnNumber: 11
429			}, this)
430		}, void 0, false, {
431			fileName: _jsxFileName,
432			lineNumber: 271,
433			columnNumber: 9
434		}, this) : /* @__PURE__ */ _jsxDEV(_Fragment, { children: [
435			/* @__PURE__ */ _jsxDEV("div", {
436				className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
437				children: statCards.map((c) => /* @__PURE__ */ _jsxDEV("div", {
438					className: "rounded-xl border border-gray-200 bg-white p-5 dark:border-gray-700 dark:bg-gray-800",
439					children: [
440						/* @__PURE__ */ _jsxDEV("div", {
441							className: `mb-3 flex h-10 w-10 items-center justify-center rounded-lg ${c.color}`,
442							children: /* @__PURE__ */ _jsxDEV(c.icon, { className: "h-5 w-5" }, void 0, false, {
443								fileName: _jsxFileName,
444								lineNumber: 280,
445								columnNumber: 19
446							}, this)
447						}, void 0, false, {
448							fileName: _jsxFileName,
449							lineNumber: 279,
450							columnNumber: 17
451						}, this),
452						/* @__PURE__ */ _jsxDEV(Text, {
453							as: "span",
454							variant: "body-lg",
455							weight: "bold",
456							children: c.value
457						}, void 0, false, {
458							fileName: _jsxFileName,
459							lineNumber: 282,
460							columnNumber: 17
461						}, this),
462						/* @__PURE__ */ _jsxDEV(Text, {
463							tone: "secondary",
464							className: "block",
465							children: c.label
466						}, void 0, false, {
467							fileName: _jsxFileName,
468							lineNumber: 283,
469							columnNumber: 17
470						}, this),
471						/* @__PURE__ */ _jsxDEV(Text, {
472							variant: "caption",
473							tone: "light",
474							className: "mt-0.5 block",
475							children: c.sub
476						}, void 0, false, {
477							fileName: _jsxFileName,
478							lineNumber: 284,
479							columnNumber: 17
480						}, this)
481					]
482				}, c.label, true, {
483					fileName: _jsxFileName,
484					lineNumber: 278,
485					columnNumber: 15
486				}, this))
487			}, void 0, false, {
488				fileName: _jsxFileName,
489				lineNumber: 276,
490				columnNumber: 11
491			}, this),
492			/* @__PURE__ */ _jsxDEV("div", {
493				className: "grid grid-cols-1 gap-4",
494				children: /* @__PURE__ */ _jsxDEV("div", {
495					className: "rounded-xl border border-gray-200 bg-white p-5 dark:border-gray-700 dark:bg-gray-800",
496					children: [
497						/* @__PURE__ */ _jsxDEV(Text, {
498							weight: "semibold",
499							className: "mb-4 block",
500							children: "Sentiment Overview"
501						}, void 0, false, {
502							fileName: _jsxFileName,
503							lineNumber: 291,
504							columnNumber: 15
505						}, this),
506						/* @__PURE__ */ _jsxDEV("div", {
507							className: "flex items-center gap-6",
508							children: [/* @__PURE__ */ _jsxDEV("div", {
509								className: "relative h-32 w-32 shrink-0",
510								children: [/* @__PURE__ */ _jsxDEV(Doughnut, {
511									data: {
512										labels: sentimentSplit.map((s) => s.label),
513										datasets: [{
514											data: sentimentSplit.map((s) => s.percent),
515											backgroundColor: sentimentSplit.map((s) => s.color),
516											borderWidth: 0,
517											// Sits on the ring itself, so it doesn't collide with the center overlay text.
518											datalabels: sliceValueLabels((v) => `${v}%`, 9)
519										}]
520									},
521									options: {
522										cutout: "72%",
523										plugins: {
524											legend: { display: false },
525											tooltip: { enabled: true }
526										}
527									}
528								}, void 0, false, {
529									fileName: _jsxFileName,
530									lineNumber: 294,
531									columnNumber: 19
532								}, this), /* @__PURE__ */ _jsxDEV("div", {
533									className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center",
534									children: [/* @__PURE__ */ _jsxDEV(Text, {
535										as: "span",
536										variant: "body-lg",
537										weight: "bold",
538										children: positivePercent !== null ? `${positivePercent}%` : "—"
539									}, void 0, false, {
540										fileName: _jsxFileName,
541										lineNumber: 311,
542										columnNumber: 21
543									}
543, this), /* @__PURE__ */ _jsxDEV(Text, {
544										as: "span",
545										variant: "caption",
546										tone: "light",
547										children: positivePercent !== null ? "Positive" : tooFewClassified ? "Too few" : "No data"
548									}, void 0, false, {
549										fileName: _jsxFileName,
550										lineNumber: 314,
551										columnNumber: 21
552									}, this)]
553								}, void 0, true, {
554									fileName: _jsxFileName,
555									lineNumber: 310,
556									columnNumber: 19
557								}, this)]
558							}, void 0, true, {
559								fileName: _jsxFileName,
560								lineNumber: 293,
561								columnNumber: 17
562							}, this), /* @__PURE__ */ _jsxDEV("div", {
563								className: "flex-1 space-y-2",
564								children: sentimentSplit.map((s) => /* @__PURE__ */ _jsxDEV("div", {
565									className: "flex items-center gap-2",
566									children: [
567										/* @__PURE__ */ _jsxDEV("span", {
568											className: "h-2 w-2 shrink-0 rounded-full",
569											style: { backgroundColor: s.color }
570										}, void 0, false, {
571											fileName: _jsxFileName,
572											lineNumber: 322,
573											columnNumber: 23
574										}, this),
575										/* @__PURE__ */ _jsxDEV(Text, {
576											as: "span",
577											variant: "label",
578											className: "w-16 shrink-0",
579											children: s.label
580										}, void 0, false, {
581											fileName: _jsxFileName,
582											lineNumber: 323,
583											columnNumber: 23
584										}, this),
585										/* @__PURE__ */ _jsxDEV("div", {
586											className: "h-1.5 flex-1 overflow-hidden rounded-full bg-gray-100 dark:bg-gray-700",
587											children: /* @__PURE__ */ _jsxDEV("div", {
588												className: "h-full rounded-full",
589												style: {
590													width: `${s.percent}%`,
591													backgroundColor: s.color
592												}
593											}, void 0, false, {
594												fileName: _jsxFileName,
595												lineNumber: 325,
596												columnNumber: 25
597											}, this)
598										}, void 0, false, {
599											fileName: _jsxFileName,
600											lineNumber: 324,
601											columnNumber: 23
602										}, this),
603										/* @__PURE__ */ _jsxDEV(Text, {
604											as: "span",
605											variant: "label",
606											weight: "semibold",
607											className: "w-10 shrink-0 text-right",
608											children: [s.percent, "%"]
609										}, void 0, true, {
610											fileName: _jsxFileName,
611											lineNumber: 327,
612											columnNumber: 23
613										}, this)
614									]
615								}, s.label, true, {
616									fileName: _jsxFileName,
617									lineNumber: 321,
618									columnNumber: 21
619								}, this))
620							}, void 0, false, {
621								fileName: _jsxFileName,
622								lineNumber: 319,
623								columnNumber: 17
624							}, this)]
625						}, void 0, true, {
626							fileName: _jsxFileName,
627							lineNumber: 292,
628							columnNumber: 15
629						}, this),
630						/* @__PURE__ */ _jsxDEV(Text, {
631							variant: "caption",
632							tone: "light",
633							className: "mt-3 block",
634							children: analytics ? marginNote(analytics.positiveSentiment) : "No data yet"
635						}, void 0, false, {
636							fileName: _jsxFileName,
637							lineNumber: 332,
638							columnNumber: 15
639						}, this),
640						/* @__PURE__ */ _jsxDEV("div", {
641							className: "mt-5 rounded-lg bg-secondary p-4 dark:bg-gray-900",
642							children: [/* @__PURE__ */ _jsxDEV(Text, {
643								variant: "caption",
644								weight: "semibold",
645								tone: "secondary",
646								className: "block",
647								children: "Sentiment Trend"
648							}, void 0, false, {
649								fileName: _jsxFileName,
650								lineNumber: 337,
651								columnNumber: 17
652							}, this), !analytics || analytics.trend.buckets.length === 0 ? /* @__PURE__ */ _jsxDEV(Text, {
653								variant: "caption",
654								tone: "light",
655								className: "mt-1 block text-center",
656								children: "No trend data for this date range yet."
657							}, void 0, false, {
658								fileName: _jsxFileName,
659								lineNumber: 339,
660								columnNumber: 19
661							}, this) : /* @__PURE__ */ _jsxDEV("div", {
662								className: "mt-2 h-40",
663								children: /* @__PURE__ */ _jsxDEV(Line, {
664									data: {
665										labels: analytics.trend.buckets.map((b) => formatBucketLabel(b, granularity)),
666										datasets: [
667											{
668												label: "Positive",
669												data: analytics.trend.positive,
670												borderColor: "#22c55e",
671												backgroundColor: "#22c55e",
672												tension: .3,
673												pointRadius: 2,
674												datalabels: lineEndpointLabels(String, 8)
675											},
676											{
677												label: "Negative",
678												data: analytics.trend.negative,
679												borderColor: "#ef4444",
680												backgroundColor: "#ef4444",
681												tension: .3,
682												pointRadius: 2,
683												datalabels: lineEndpointLabels(String, 8)
684											},
685											{
686												label: "Neutral",
687												data: analytics.trend.neutral,
688												borderColor: "#9ca3af",
689												backgroundColor: "#9ca3af",
690												tension: .3,
691												pointRadius: 2,
692												datalabels: lineEndpointLabels(String, 8)
693											},
694											{
695												label: "Unclassified",
696												data: analytics.trend.unclassified,
697												borderColor: "#d1d5db",
698												backgroundColor: "#d1d5db",
699												borderDash: [4, 4],
700												tension: .3,
701												pointRadius: 2,
702												// Text uses a darker gray than the line itself — the line's own
703												// pale hue would be illegible as label text on a white surface.
704												datalabels: lineEndpointLabels(String, 8)
705											}
706										]
707									},
708									options: {
709										maintainAspectRatio: false,
710										layout: { padding: { top: 14 } },
711										scales: {
712											x: { ticks: { font: { size: 10 } } },
713											y: {
714												beginAtZero: true,
715												grace: "10%",
716												ticks: { font: { size: 10 } }
717											}
718										},
719										plugins: { legend: {
720											position: "bottom",
721											labels: {
722												boxWidth: 8,
723												font: { size: 10 }
724											}
725										} }
726									}
727								}, void 0, false, {
728									fileName: _jsxFileName,
729									lineNumber: 342,
730									columnNumber: 21
731								}, this)
732							}, void 0, false, {
733								fileName: _jsxFileName,
734								lineNumber: 341,
735								columnNumber: 19
736							}, this)]
737						}, void 0, true, {
738							fileName: _jsxFileName,
739							lineNumber: 336,
740							columnNumber: 15
741						}, this)
742					]
743				}, void 0, true, {
744					fileName: _jsxFileName,
745					lineNumber: 290,
746					columnNumber: 13
747				}, this)
748			}, void 0, false, {
749				fileName: _jsxFileName,
750				lineNumber: 289,
751				columnNumber: 11
752			}, this),
753			/* @__PURE__ */ _jsxDEV("div", {
754				className: "grid grid-cols-1 gap-4 lg:grid-cols-2",
755				children: [/* @__PURE__ */ _jsxDEV(BreakdownCard, {
756					title: "Emotion Breakdown",
757					icon: Heart,
758					iconColor: "text-pink-500",
759					rows: emotionRows,
760					emptyNote: "No emotion data yet."
761				}, void 0, false, {
762					fileName: _jsxFileName,
763					lineNumber: 404,
764					columnNumber: 13
765				}, this), /* @__PURE__ */ _jsxDEV(BreakdownCard, {
766					title: "Language Breakdown",
767					icon: Globe,
768					iconColor: "text-purple-500",
769					rows: languageRows,
770					emptyNote: "No language data yet."
771				}, void 0, false, {
772					fileName: _jsxFileName,
773					lineNumber: 411,
774					columnNumber: 13
775				}, this)]
776			}, void 0, true, {
777				fileName: _jsxFileName,
778				lineNumber: 403,
779				columnNumber: 11
780			}, this)
781		] }, void 0, true, {
782			fileName: _jsxFileName,
783			lineNumber: 275,
784			columnNumber: 9
785		}, this)]
786	}, void 0, true, {
787		fileName: _jsxFileName,
788		lineNumber: 213,
789		columnNumber: 5
790	}, this);
791}
792_s(QueryAnalyticsPage, "iBRz0S0UxY7G7MeAYAuIZMC4Nns=", false, function() {
793	return [
794		useNavigate,
795		useParams,
796		useGetQueryQuery,
797		useGetAnalyticsQuery
798	];
799});
800_c2 = QueryAnalyticsPage;
801var _c, _c2;
802$RefreshReg$(_c, "BreakdownCard");
803$RefreshReg$(_c2, "QueryAnalyticsPage");
804import * as RefreshRuntime from "/@react-refresh";
805const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
806import * as __vite_react_currentExports from "/src/pages/query-builder/QueryAnalyticsPage.tsx";
807if (import.meta.hot && !inWebWorker) {
808  if (!window.$RefreshReg$) {
809    throw new Error(
810      "@vitejs/plugin-react can't detect preamble. Something is wrong."
811    );
812  }
813
814  const currentExports = __vite_react_currentExports;
815  queueMicrotask(() => {
816    RefreshRuntime.registerExportsForReactRefresh("/app/src/pages/query-builder/QueryAnalyticsPage.tsx", currentExports);
817    import.meta.hot.accept((nextExports) => {
818      if (!nextExports) return;
819      const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate("/app/src/pages/query-builder/QueryAnalyticsPage.tsx", currentExports, nextExports);
820      if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
821    });
822  });
823}
824function $RefreshReg$(type, id) { return RefreshRuntime.register(type, "/app/src/pages/query-builder/QueryAnalyticsPage.tsx" + ' ' + id); }
825function $RefreshSig$() { return RefreshRuntime.createSignatureFunctionForTransform(); }
826
827//# sourceMappingURL=data:application/json;base64,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LENBQUM7V0FDMUM7V0FDQTtZQUNFLE9BQU87WUFDUCxNQUFNLFVBQVUsTUFBTTtZQUN0QixhQUFhO1lBQ2IsaUJBQWlCO1lBQ2pCLFNBQVM7WUFDVCxhQUFhO1lBQ2IsWUFBWSxtQkFBbUIsUUFBUSxDQUFDO1dBQzFDO1dBQ0E7WUFDRSxPQUFPO1lBQ1AsTUFBTSxVQUFVLE1BQU07WUFDdEIsYUFBYTtZQUNiLGlCQUFpQjtZQUNqQixZQUFZLENBQUMsR0FBRyxDQUFDO1lBQ2pCLFNBQVM7WUFDVCxhQUFhOzs7WUFHYixZQUFZLG1CQUFtQixRQUFRLENBQUM7V0FDMUM7VUFDRjtTQUNGO1NBQ0EsU0FBUztVQUNQLHFCQUFxQjtVQUNyQixRQUFRLEVBQUUsU0FBUyxFQUFFLEtBQUssR0FBRyxFQUFFO1VBQy9CLFFBQVE7V0FDTixHQUFHLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEdBQUcsRUFBRSxFQUFFO1dBQ25DLEdBQUc7WUFB
827RSxhQUFhO1lBQU0sT0FBTztZQUFPLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxHQUFHLEVBQUU7V0FBRTtVQUN0RTtVQUNBLFNBQVMsRUFBRSxRQUFRO1dBQUUsVUFBVTtXQUFVLFFBQVE7WUFBRSxVQUFVO1lBQUcsTUFBTSxFQUFFLE1BQU0sR0FBRztXQUFFO1VBQUUsRUFBRTtTQUN6RjtRQUNEOzs7OztPQUNFOzs7O2VBRUo7Ozs7OztLQUNGOzs7Ozs7R0FDRjs7Ozs7R0FFTCx3QkFBQyxPQUFEO0lBQUssV0FBVTtjQUFmLENBQ0Usd0JBQUMsZUFBRDtLQUNFLE9BQU07S0FDTixNQUFNO0tBQ04sV0FBVTtLQUNWLE1BQU07S0FDTixXQUFVO0lBQ1g7Ozs7Y0FDRCx3QkFBQyxlQUFEO0tBQ0UsT0FBTTtLQUNOLE1BQU07S0FDTixXQUFVO0tBQ1YsTUFBTTtLQUNOLFdBQVU7SUFDWDs7OztZQUNFOzs7Ozs7RUFDTDs7OztVQUVEOzs7Ozs7QUFFVCIsIm5hbWVzIjpbXSwic291cmNlcyI6WyJRdWVyeUFuYWx5dGljc1BhZ2UudHN4Il0sInZlcnNpb24iOjMsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgeyB1c2VOYXZpZ2F0ZSwgdXNlUGFyYW1zIH0gZnJvbSAncmVhY3Qtcm91dGVyLWRvbSdcbmltcG9ydCB7IERvdWdobnV0LCBMaW5lIH0gZnJvbSAncmVhY3QtY2hhcnRqcy0yJ1xuaW1wb3J0IHtcbiAgQ2hhcnQgYXMgQ2hhcnRKUyxcbiAgQXJjRWxlbWVudCxcbiAgQ2F0ZWdvcnlTY2FsZSxcbiAgTGluZWFyU2NhbGUsXG4gIFBvaW50RWxlbWVudCxcbiAgTGluZUVsZW1lbnQsXG4gIFRvb2x0aXAsXG4gIExlZ2VuZCxcbiAgRmlsbGVyLFxufSBmcm9tICdjaGFydC5qcydcbmltcG9ydCBDaGFydERhdGFMYWJlbHMgZnJvbSAnY2hhcnRqcy1wbHVnaW4tZGF0YWxhYmVscydcbmltcG9ydCB7XG4gIEFycm93TGVmdCwgTWVzc2FnZUNpcmNsZSwgQWN0aXZpdHksIFphcCwgSGVhcnQsIEdsb2JlLFxufSBmcm9tICdsdWNpZGUtcmVhY3QnXG5pbXBvcnQgeyBIZWFkaW5nIH0gZnJvbSAnQC9jb21wb25lbnRzL3VpL0hlYWRpbmcnXG5pbXBvcnQgeyBUZXh0IH0gZnJvbSAnQC9jb21wb25lbnRzL3VpL1RleHQnXG5pbXBvcnQgeyBCdXR0b24gfSBmcm9tICdAL2NvbXBvbmVudHMvdWkvQnV0dG9uJ1xuaW1wb3J0IHsgUGFnZVNwaW5uZXIgfSBmcm9tICdAL2NvbXBvbmVudHMvdWkvU3Bpbm5lcidcbmltcG9ydCB7IGNuIH0gZnJvbSAnQC9saWIvdXRpbHMnXG5pbXBvcnQgeyB1c2VHZXRRdWVyeVF1ZXJ5LCB1c2VHZXRBbmFseXRpY3NRdWVyeSB9IGZyb20gJ0Avc3RvcmUvYXBpL3F1ZXJ5QnVpbGRlckFwaSdcbmltcG9ydCB7IGxpbmVFbmRwb2ludExhYmVscywgc2xpY2VWYWx1ZUxhYmVscyB9IGZyb20gJ0AvdXRpbHMvY2hhcnREYXRhTGFiZWxzJ1xuaW1wb3J0IHR5cGUgeyBBbmFseXRpY3NSZXNwb25zZSB9IGZyb20gJ0AvdHlwZXMvcXVlcnlCdWlsZGVyJ1xuXG5DaGFydEpTLnJlZ2lzdGVyKEFyY0VsZW1lbnQsIENhdGVnb3J5U2NhbGUsIExpbmVhclNjYWxlLCBQb2ludEVsZW1lbnQsIExpbmVFbGVtZW50LCBUb29sdGlwLCBMZWdlbmQsIEZpbGxlciwgQ2hhcnREYXRhTGFiZWxzKVxuLy8gVGhlIHBsdWdpbiByZWdpc3RyeSBpcyBwcm9jZXNzLXdpZGUgKGV2ZXJ5IENoYXJ0LmpzIGluc3RhbmNlIGluIHRoZSBhcHAgc2hhcmVzIGl0KSDigJQgb2ZmIGJ5XG4vLyBkZWZhdWx0IGhlcmUsIG9wdGVkIGluIHBlciBkYXRhc2V0IGJlbG93LCBzbyBpdCBjYW4ndCBsZWFrIG9udG8gc29tZSBvdGhlciBjaGFydCB1bmV4cGVjdGVkbHkuXG5DaGFydEpTLmRlZmF1bHRzLnBsdWdpbnMuZGF0YWxhYmVscyA9IHsgZGlzcGxheTogZmFsc2UgfVxuXG4vLyBCYWNrZW5kJ3MgcmVhbCBlbW90aW9uIGxhYmVsIHNldDogYW5nZXIvZmVhci9qb3kvc2FkbmVzcy9kaXNndXN0L3N1cnByaXNlL25vbmUuXG5jb25zdCBFTU9USU9OX0NPTE9SUzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgam95OiAnYmctb3JhbmdlLTQwMCcsXG4gIHN1cnByaXNlOiAnYmctdmlvbGV0LTUwMCcsXG4gIGFuZ2VyOiAnYmctcmVkLTUwMCcsXG4gIGZlYXI6ICdiZy1ibHVlLTUwMCcsXG4gIHNhZG5lc3M6ICdiZy1ncmF5LTQwMCcsXG4gIGRpc2d1c3Q6ICdiZy1lbWVyYWxkLTUwMCcsXG4gIG5vbmU6ICdiZy1zbGF0ZS0zMDAnLFxufVxuY29uc3QgREVGQVVMVF9FTU9USU9OX0NPTE9SID0gJ2JnLWluZGlnby00MDAnXG5cbmNvbnN0IGxhbmd1YWdlRGlzcGxheU5hbWVzID0gbmV3IEludGwuRGlzcGxheU5hbWVzKFsnZW4nXSwgeyB0eXBlOiAnbGFuZ3VhZ2UnIH0pXG5mdW5jdGlvbiBsYW5ndWFnZU5hbWUoY29kZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gbGFuZ3VhZ2VEaXNwbGF5TmFtZXMub2YoY29kZSkgPz8gY29kZVxuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gY29kZVxuICB9XG59XG5cbmZ1bmN0aW9uIEJyZWFrZG93bkNhcmQoe1xuICB0aXRsZSxcbiAgaWNvbjogSWNvbixcbiAgaWNvbkNvbG9yLFxuICByb3dzLFxuICBlbXB0eU5vdGUsXG59OiB7XG4gIHRpdGxlOiBzdHJpbmdcbiAgaWNvbjogdHlwZW9mIEdsb2JlXG4gIGljb25Db2xvcjogc3RyaW5nXG4gIHJvd3M6IHsgbGFiZWw6IHN0cmluZzsgcGVyY2VudDogbnVtYmVyIH1bXVxuICBlbXB0eU5vdGU6IHN0cmluZ1xufSkge1xuICByZXR1cm4gKFxuICAgIDxkaXYgY2xhc3NOYW1lPVwicm91bmRlZC14bCBib3JkZXIgYm9yZGVyLWdyYXktMjAwIGJnLXdoaXRlIHAtNSBkYXJrOmJvcmRlci1ncmF5LTcwMCBkYXJrOmJnLWdyYXktODAwXCI+XG4gICAgICA8ZGl2IGNsYXNzTmFtZT1cIm1iLTQgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTJcIj5cbiAgICAgICAgPEljb24gY2xhc3NOYW1lPXtgaC00IHctNCAke2ljb25Db2xvcn1gfSAvPlxuICAgICAgICA8VGV4dCB3ZWlnaHQ9XCJzZW1pYm9sZFwiPnt0aXRsZX08L1RleHQ+XG4gICAgICA8L2Rpdj5cbiAgICAgIHtyb3dzLmxlbmd0aCA9PT0gMCA/IChcbiAgICAgICAgPFRleHQgdG9uZT1cInNlY29uZGFyeVwiPntlbXB0eU5vdGV9PC9UZXh0PlxuICAgICAgKSA6IChcbiAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJzcGFjZS15LTNcIj5cbiAgICAgICAgICB7cm93cy5tYXAociA9PiB7XG4gICAgICAgICAgICBjb25zdCBjb2xvciA9IEVNT1RJT05fQ09MT1JTW3IubGFiZWwudG9Mb3dlckNhc2UoKV0gPz8gREVGQVVMVF9FTU9USU9OX0NPTE9SXG4gICAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgICA8ZGl2IGtleT17ci5sYWJlbH0gY2xhc3NOYW1lPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTNcIj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9e2NuKCdoLTIgdy0yIHNocmluay0wIHJvdW5kZWQtZnVsbCcsIGNvbG9yKX0gLz5cbiAgICAgICAgICAgICAgICA8VGV4dCBhcz1cInNwYW5cIiB2YXJpYW50PVwibGFiZWxcIiBjbGFzc05hbWU9XCJ3LTE2IHNocmluay0wXCI+e3IubGFiZWx9PC9UZXh0PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiaC0xLjUgZmxleC0xIG92ZXJmbG93LWhpZGRlbiByb3VuZGVkLWZ1bGwgYmctZ3JheS0xMDAgZGFyazpiZy1ncmF5LTcwMFwiPlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9e2NuKCdoLWZ1bGwgcm91bmRlZC1mdWxsJywgY29sb3IpfSBzdHlsZT17eyB3aWR0aDogYCR7ci5wZXJjZW50fSVgIH19IC8+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPFRleHQgYXM9XCJzcGFuXCIgdmFyaWFudD1cImxhYmVsXCIgd2VpZ2h0PVwic2VtaWJvbGRcIiBjbGFzc05hbWU9XCJ3LTEwIHNocmluay0wIHRleHQtcmlnaHRcIj57ci5wZXJjZW50fSU8L1RleHQ+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKVxuICAgICAgICAgI
827H0pfVxuICAgICAgICA8L2Rpdj5cbiAgICAgICl9XG4gICAgPC9kaXY+XG4gIClcbn1cblxuZnVuY3Rpb24gY292ZXJhZ2VOb3RlKHM6IEFuYWx5dGljc1Jlc3BvbnNlWydwb3NpdGl2ZVNlbnRpbWVudCddKTogc3RyaW5nIHtcbiAgaWYgKHMudG90YWxNYXRjaGVkIDw9IDApIHJldHVybiAnTm8gbWF0Y2hlZCBwb3N0cyB5ZXQuJ1xuICBpZiAocy5zYW1wbGVUb29TbWFsbCkgcmV0dXJuIGBvbmx5ICR7cy5jbGFzc2lmaWVkQ291bnR9IG9mICR7cy50b3RhbE1hdGNoZWR9IHBvc3RzIGNsYXNzaWZpZWRgXG4gIGNvbnN0IGNvdmVyYWdlUGVyY2VudCA9IE1hdGgucm91bmQoKHMuY2xhc3NpZmllZENvdW50IC8gcy50b3RhbE1hdGNoZWQpICogMTAwKVxuICByZXR1cm4gYMKxJHtzLm1hcmdpblBvaW50c30gcHRzIMK3IGJhc2VkIG9uICR7Y292ZXJhZ2VQZXJjZW50fSUgb2YgbWF0Y2hlZCBwb3N0c2Bcbn1cblxuLyoqIFRoZSBtYXJnaW4gc2VudGVuY2UgdGhhdCBzaXRzIHdpdGggdGhlIG51bWJlciwgbm90IG9uIGFub3RoZXIgc2NyZWVuOiBob3dcbiAqICBmYXIgdGhpcyBwZXJjZW50YWdlIGNvdWxkIGJlIGZyb20gdGhlIHRydXRoLCBhbmQgd2hhdCBpdCB3YXMgbWVhc3VyZWQgb3Zlci5cbiAqICBLZXB0IHZlcmJhbGx5IGRpc3RpbmN0IGZyb20gcGVyLWl0ZW0gbW9kZWwgY29uZmlkZW5jZSDigJQgdGhlIHR3byBhcmVcbiAqICBkaWZmZXJlbnQgcXVhbnRpdGllcyBhbmQgYSByZWFkZXIgbXVzdCBuZXZlciBtZXJnZSB0aGVtLiAqL1xuZnVuY3Rpb24gbWFyZ2luTm90ZShzOiBBbmFseXRpY3NSZXNwb25zZVsncG9zaXRpdmVTZW50aW1lbnQnXSk6IHN0cmluZyB7XG4gIGlmIChzLnRvdGFsTWF0Y2hlZCA8PSAwKSByZXR1cm4gJ05vIG1hdGNoZWQgcG9zdHMgeWV0LidcbiAgaWYgKHMuc2FtcGxlVG9vU21hbGwpIHtcbiAgICByZXR1cm4gYE5vdCBlbm91Z2ggY2xhc3NpZmllZCBwb3N0cyB0byBxdW90ZSBhIHBlcmNlbnRhZ2Ug4oCUICR7cy5jbGFzc2lmaWVkQ291bnR9IG9mICR7cy50b3RhbE1hdGNoZWR9IGNsYXNzaWZpZWQgc28gZmFyLmBcbiAgfVxuICByZXR1cm4gKFxuICAgIGDCsSR7cy5tYXJnaW5Qb2ludHN9IHBvaW50cyBhdCA5NSUgY29uZmlkZW5jZSwgZnJvbSAke3MuY2xhc3NpZmllZENvdW50fSBvZiBgICtcbiAgICBgJHtzLnRvdGFsTWF0Y2hlZH0gbWF0Y2hlZCBwb3N0cyBjbGFzc2lmaWVkLiBUaGlzIGlzIGhvdyBzdXJlIHdlIGFyZSBvZiB0aGUgYCArXG4gICAgYHBlcmNlbnRhZ2UsIG5vdCBob3cgc3VyZSB0aGUgbW9kZWwgaXMgYWJvdXQgYW55IG9uZSBwb3N0LiBQZXJjZW50YWdlcyBgICtcbiAgICBgZGVzY3JpYmUgcG9zdCBjYXB0aW9uczsgYXVkaWVuY2UgcmVhY3Rpb24gaW4gdGhlIGNvbW1lbnRzIGlzIG5vdCBjb3VudGVkIGhlcmUuYFxuICApXG59XG5cbnR5cGUgR3JhbnVsYXJpdHkgPSAnZGF5JyB8ICd3ZWVrJyB8ICdtb250aCdcblxuZnVuY3Rpb24gZm9ybWF0QnVja2V0TGFiZWwoaXNvOiBzdHJpbmcsIGdyYW51bGFyaXR5OiBHcmFudWxhcml0eSk6IHN0cmluZyB7XG4gIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShpc28pXG4gIGlmIChncmFudWxhcml0eSA9PT0gJ21vbnRoJykgcmV0dXJuIGRhdGUudG9Mb2NhbGVEYXRlU3RyaW5nKHVuZGVmaW5lZCwgeyBtb250aDogJ3Nob3J0JywgeWVhcjogJ251bWVyaWMnIH0pXG4gIHJldHVybiBkYXRlLnRvTG9jYWxlRGF0ZVN0cmluZyh1bmRlZmluZWQsIHsgbW9udGg6ICdzaG9ydCcsIGRheTogJ251bWVyaWMnIH0pXG59XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIFF1ZXJ5QW5hbHl0aWNzUGFnZSgpIHtcbiAgY29uc3QgbmF2aWdhdGUgPSB1c2VOYXZpZ2F0ZSgpXG4gIGNvbnN0IHsgaWQgfSA9IHVzZVBhcmFtczx7IGlkOiBzdHJpbmcgfT4oKVxuICBjb25zdCB7XG4gICAgZGF0YTogcXVlcnksXG4gICAgaXNMb2FkaW5nOiBxdWVyeUxvYWRpbmcsXG4gICAgaXNGZXRjaGluZzogcXVlcnlGZXRjaGluZyxcbiAgfSA9IHVzZUdldFF1ZXJ5UXVlcnkoaWQhLCB7IHNraXA6ICFpZCB9KVxuXG4gIGNvbnN0IFtmcm9tRGF0ZSwgc2V0RnJvbURhdGVdID0gdXNlU3RhdGUoJycpXG4gIGNvbnN0IFt0b0RhdGUsIHNldFRvRGF0ZV0gPSB1c2VTdGF0ZSgnJylcbiAgY29uc3QgW2dyYW51bGFyaXR5LCBzZXRHcmFudWxhcml0eV0gPSB1c2VTdGF0ZTxHcmFudWxhcml0eT4oJ21vbnRoJylcbiAgY29uc3QgW2FwcGx5RmlsdGVycywgc2V0QXBwbHlGaWx0ZXJzXSA9IHVzZVN0YXRlKHRydWUpXG5cbiAgY29uc3Qge1xuICAgIGRhdGE6IGFuYWx5dGljcyxcbiAgICBpc0xvYWRpbmc6IGFuYWx5dGljc0xvYWRpbmcsXG4gICAgaXNGZXRjaGluZzogYW5hbHl0aWNzRmV0Y2hpbmcsXG4gICAgaXNFcnJvcjogYW5hbHl0aWNzRXJyb3IsXG4gIH0gPSB1c2VHZXRBbmFseXRpY3NRdWVyeShcbiAgICB7IGlkOiBpZCEsIGZyb206IGZyb21EYXRlIHx8IHVuZGVmaW5lZCwgdG86IHRvRGF0ZSB8fCB1bmRlZmluZWQsIGdyYW51bGFyaXR5LCBhcHBseUZpbHRlcnMgfSxcbiAgICB7IHNraXA6ICFpZCB9LFxuICApXG5cbiAgLy8gaXNGZXRjaGluZyAobm90IGp1c3QgaXNMb2FkaW5nKSBzbyBzd2l0Y2hpbmcgYmFjayB0byBhblxuICAvLyBhbHJlYWR5LWNhY2hlZCBkYXRlIHJhbmdlL2dyYW51bGFyaXR5IHN0aWxsIHNob3dzIHRoZSBzaGFyZWQgcGFnZVxuICAvLyBsb2FkZXIgaW5zdGVhZCBvZiBzaWxlbnRseSBzaXR0aW5nIG9uIHRoZSBwcmV2aW91cyBzZWxlY3Rpb24ncyBkYXRhLlxuICBpZiAocXVlcnlMb2FkaW5nIHx8IHF1ZXJ5RmV0Y2hpbmcpIHtcbiAgICByZXR1cm4gPFBhZ2VTcGlubmVyIC8+XG4gIH1cblxuICBpZiAoIXF1ZXJ5KSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxkaXYgY2xhc3NOYW1lPVwicC02XCI+XG4gICAgICAgIDxUZXh0IHRvbmU9XCJzZWNvbmRhcnlcIj5RdWVyeSBub3QgZm91bmQuPC9UZXh0PlxuICAgICAgICA8QnV0dG9uIHZhcmlhbnQ9XCJvdXRsaW5lXCIgY2xhc3NOYW1lPVwibXQtM1wiIG9uQ2xpY2s9eygpID0+IG5hdmlnYXRlKCcvbGlzdGVuL3F1ZXJ5LWJ1aWxkZXInKX0+QmFjayB0byBRdWVyeSBCdWlsZGVyPC9CdXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICApXG4gIH1cblxuICAvLyBBIHBlcmNlbnRhZ2Ugb2ZmIGEgaGFuZGZ1bCBvZiBjbGFzc2lmaWVkIHBvc3RzIGlzIG5vdCBhbiBhbnN3ZXIsIGl0IGlzIGFcbiAgLy8gY29pbmNpZGVuY2Ug4oCUIGJlbG93IHRoZSBiYWNrZW5kJ3MgbWluaW11bSBzYW1wbGUgaXQgaXMgd2l0aGhlbGQgZW50aXJlbHlcbiAgLy8gcmF0aGVyIHR
827oYW4gc2hvd24gd2l0aCBhIGNhdmVhdCBub2JvZHkgcmVhZHMuXG4gIGNvbnN0IHRvb0Zld0NsYXNzaWZpZWQgPSBhbmFseXRpY3M/LnBvc2l0aXZlU2VudGltZW50LnNhbXBsZVRvb1NtYWxsID8/IGZhbHNlXG4gIGNvbnN0IHBvc2l0aXZlUGVyY2VudCA9IHRvb0Zld0NsYXNzaWZpZWQgPyBudWxsIDogYW5hbHl0aWNzPy5wb3NpdGl2ZVNlbnRpbWVudC5wZXJjZW50ID8/IG51bGxcbiAgY29uc3QgbmVnYXRpdmVQZXJjZW50ID0gdG9vRmV3Q2xhc3NpZmllZCA/IG51bGwgOiBhbmFseXRpY3M/Lm5lZ2F0aXZlU2VudGltZW50LnBlcmNlbnQgPz8gbnVsbFxuICBjb25zdCBuZXV0cmFsUGVyY2VudCA9XG4gICAgcG9zaXRpdmVQZXJjZW50ICE9PSBudWxsICYmIG5lZ2F0aXZlUGVyY2VudCAhPT0gbnVsbFxuICAgICAgPyBNYXRoLm1heCgwLCAxMDAgLSBwb3NpdGl2ZVBlcmNlbnQgLSBuZWdhdGl2ZVBlcmNlbnQpXG4gICAgICA6IG51bGxcblxuICBjb25zdCBzZW50aW1lbnRTcGxpdCA9IFtcbiAgICB7IGxhYmVsOiAnUG9zaXRpdmUnLCBwZXJjZW50OiBwb3NpdGl2ZVBlcmNlbnQgPz8gMCwgY29sb3I6ICcjMjJjNTVlJyB9LFxuICAgIHsgbGFiZWw6ICdOZXV0cmFsJywgcGVyY2VudDogbmV1dHJhbFBlcmNlbnQgPz8gMCwgY29sb3I6ICcjOWNhM2FmJyB9LFxuICAgIHsgbGFiZWw6ICdOZWdhdGl2ZScsIHBlcmNlbnQ6IG5lZ2F0aXZlUGVyY2VudCA/PyAwLCBjb2xvcjogJyNlZjQ0NDQnIH0sXG4gIF1cblxuICBjb25zdCBzdGF0Q2FyZHM6IHsgbGFiZWw6IHN0cmluZzsgdmFsdWU6IHN0cmluZzsgc3ViOiBzdHJpbmc7IGljb246IHR5cGVvZiBNZXNzYWdlQ2lyY2xlOyBjb2xvcjogc3RyaW5nIH1bXSA9IFtcbiAgICB7XG4gICAgICBsYWJlbDogJ1RvdGFsIE1lbnRpb25zJyxcbiAgICAgIHZhbHVlOiBhbmFseXRpY3MgPyBhbmFseXRpY3MudG9waWNWb2x1bWUudG9Mb2NhbGVTdHJpbmcoKSA6ICcwJyxcbiAgICAgIHN1YjogYW5hbHl0aWNzID8gJ01hdGNoZWQgdGhpcyBkYXRlIHJhbmdlJyA6ICdObyBkYXRhIHlldCcsXG4gICAgICBpY29uOiBNZXNzYWdlQ2lyY2xlLFxuICAgICAgY29sb3I6ICdiZy1waW5rLTEwMCB0ZXh0LXBpbmstNjAwJyxcbiAgICB9LFxuICAgIHtcbiAgICAgIGxhYmVsOiAnUG9zaXRpdmUgU2VudGltZW50JyxcbiAgICAgIHZhbHVlOiBwb3NpdGl2ZVBlcmNlbnQgIT09IG51bGwgPyBgJHtwb3NpdGl2ZVBlcmNlbnR9JWAgOiAn4oCUJyxcbiAgICAgIHN1YjogYW5hbHl0aWNzID8gY292ZXJhZ2VOb3RlKGFuYWx5dGljcy5wb3NpdGl2ZVNlbnRpbWVudCkgOiAnTm8gZGF0YSB5ZXQnLFxuICAgICAgaWNvbjogQWN0aXZpdHksXG4gICAgICBjb2xvcjogJ2JnLWdyZWVuLTEwMCB0ZXh0LWdyZWVuLTYwMCcsXG4gICAgfSxcbiAgICB7XG4gICAgICBsYWJlbDogJ0VuZ2FnZW1lbnRzJyxcbiAgICAgIHZhbHVlOiBhbmFseXRpY3MgPyBhbmFseXRpY3MuZW5nYWdlbWVudHMudG9Mb2NhbGVTdHJpbmcoKSA6ICcwJyxcbiAgICAgIHN1YjogJ0xpa2VzICsgY29tbWVudHMgKyBzaGFyZXMsIHRoaXMgZGF0ZSByYW5nZScsXG4gICAgICBpY29uOiBaYXAsXG4gICAgICBjb2xvcjogJ2JnLWFtYmVyLTEwMCB0ZXh0LWFtYmVyLTYwMCcsXG4gICAgfSxcbiAgXVxuXG4gIGNvbnN0IGVtb3Rpb25Sb3dzID0gYW5hbHl0aWNzPy5lbW90aW9uQnJlYWtkb3duID8/IFtdXG4gIGNvbnN0IGxhbmd1YWdlUm93cyA9IChhbmFseXRpY3M/Lmxhbmd1YWdlQnJlYWtkb3duID8/IFtdKS5tYXAociA9PiAoeyAuLi5yLCBsYWJlbDogbGFuZ3VhZ2VOYW1lKHIubGFiZWwpIH0pKVxuXG4gIHJldHVybiAoXG4gICAgPGRpdiBjbGFzc05hbWU9XCJzcGFjZS15LTYgcC02XCI+XG4gICAgICA8ZGl2IGNsYXNzTmFtZT1cImZsZXggZmxleC13cmFwIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gZ2FwLTNcIj5cbiAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtM1wiPlxuICAgICAgICAgIDxCdXR0b24gdmFyaWFudD1cImdob3N0XCIgc2l6ZT1cImljb25cIiBvbkNsaWNrPXsoKSA9PiBuYXZpZ2F0ZSgnL2xpc3Rlbi9xdWVyeS1idWlsZGVyJyl9IGFyaWEtbGFiZWw9XCJCYWNrXCI+XG4gICAgICAgICAgICA8QXJyb3dMZWZ0IGNsYXNzTmFtZT1cImgtNSB3LTVcIiAvPlxuICAgICAgICAgIDwvQnV0dG9uPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8SGVhZGluZyB2YXJpYW50PVwiaDJcIj57cXVlcnkubmFtZX0g4oCUIEFuYWx5dGljczwvSGVhZGluZz5cbiAgICAgICAgICAgIDxUZXh0IHRvbmU9XCJzZWNvbmRhcnlcIj5Gb2xsb3dzIHRoaXMgcXVlcnkncyBvd24gZGF0ZSByYW5nZTwvVGV4dD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJmbGV4IGZsZXgtd3JhcCBpdGVtcy1jZW50ZXIgZ2FwLTJcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImZsZXggaXRlbXMtY2VudGVyIGdhcC0yXCI+XG4gICAgICAgICAgICA8VGV4dCBhcz1cInNwYW5cIiB2YXJpYW50PVwiY2FwdGlvblwiIHRvbmU9XCJsaWdodFwiPkZyb208L1RleHQ+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImRhdGVcIlxuICAgICAgICAgICAgICB2YWx1ZT17ZnJvbURhdGV9XG4gICAgICAgICAgICAgIG9uQ2hhbmdlPXtlID0+IHNldEZyb21EYXRlKGUudGFyZ2V0LnZhbHVlKX1cbiAgICAgICAgICAgICAgY2xhc3NOYW1lPVwiaC05IHJvdW5kZWQtbGcgYm9yZGVyIGJvcmRlci1ncmF5LTMwMCBweC0yIHRleHQtc20gZGFyazpib3JkZXItZ3JheS02MDAgZGFyazpiZy1ncmF5LTgwMFwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPFRleHQgYXM9XCJzcGFuXCIgdmFyaWFudD1cImNhcHRpb25cIiB0b25lPVwibGlnaHRcIj5UbzwvVGV4dD5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwiZGF0ZVwiXG4gICAgICAgICAgICAgIHZhbHVlPXt0b0RhdGV9XG4gICAgICAgICAgICAgIG9uQ2hhbmdlPXtlID0+IHNldFRvRGF0ZShlLnRhcmdldC52YWx1ZSl9XG4gICAgICAgICAgICAgIGNsYXNzTmFtZT1cImgtOSByb3VuZGVkLWxnIGJvcmRlciBib3JkZXItZ3JheS0zMDAgcHgtMiB0ZXh0LXNtIGRhcms6Ym9yZGVyLWdyYXktNjAwIGRhcms6YmctZ3JheS04MDBcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImZsZXggaXRlbXMtY2VudGVyIGdhcC0x
827IHJvdW5kZWQtbGcgYm9yZGVyIGJvcmRlci1ncmF5LTIwMCBwLTEgZGFyazpib3JkZXItZ3JheS03MDBcIj5cbiAgICAgICAgICAgIHsoWydkYXknLCAnd2VlaycsICdtb250aCddIGFzIEdyYW51bGFyaXR5W10pLm1hcChnID0+IChcbiAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgIGtleT17Z31cbiAgICAgICAgICAgICAgICBvbkNsaWNrPXsoKSA9PiBzZXRHcmFudWxhcml0eShnKX1cbiAgICAgICAgICAgICAgICBjbGFzc05hbWU9e2NuKFxuICAgICAgICAgICAgICAgICAgJ3JvdW5kZWQtbWQgcHgtMyBweS0xIHRleHQtc20gZm9udC1tZWRpdW0gY2FwaXRhbGl6ZSB0cmFuc2l0aW9uLWNvbG9ycycsXG4gICAgICAgICAgICAgICAgICBncmFudWxhcml0eSA9PT0gZyA/ICdiZy1wcmltYXJ5IHRleHQtd2hpdGUnIDogJ3RleHQtdGV4dC1zZWNvbmRhcnkgaG92ZXI6Ymctc2Vjb25kYXJ5JyxcbiAgICAgICAgICAgICAgICApfVxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAge2d9XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgKSl9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzTmFtZT1cImZsZXggY3Vyc29yLXBvaW50ZXIgaXRlbXMtY2VudGVyIGdhcC0yIHJvdW5kZWQtbGcgYm9yZGVyIGJvcmRlci1ncmF5LTIwMCBweC0zIHB5LTEuNSB0ZXh0LXNtIGRhcms6Ym9yZGVyLWdyYXktNzAwXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cImNoZWNrYm94XCJcbiAgICAgICAgICAgICAgY2hlY2tlZD17YXBwbHlGaWx0ZXJzfVxuICAgICAgICAgICAgICBvbkNoYW5nZT17ZSA9PiBzZXRBcHBseUZpbHRlcnMoZS50YXJnZXQuY2hlY2tlZCl9XG4gICAgICAgICAgICAgIGNsYXNzTmFtZT1cImgtNCB3LTQgcm91bmRlZCBib3JkZXItZ3JheS0zMDAgdGV4dC1wcmltYXJ5IGZvY3VzOnJpbmctcHJpbWFyeVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPVwidGV4dC10ZXh0LXNlY29uZGFyeVwiPlNob3cgd2l0aCBmaWx0ZXJzIG9ubHk8L3NwYW4+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAge2FuYWx5dGljc0xvYWRpbmcgfHwgYW5hbHl0aWNzRmV0Y2hpbmcgPyAoXG4gICAgICAgIDxQYWdlU3Bpbm5lciAvPlxuICAgICAgKSA6IGFuYWx5dGljc0Vycm9yID8gKFxuICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cInJvdW5kZWQteGwgYm9yZGVyIGJvcmRlci1ncmF5LTIwMCBiZy13aGl0ZSBwLTggdGV4dC1jZW50ZXIgZGFyazpib3JkZXItZ3JheS03MDAgZGFyazpiZy1ncmF5LTgwMFwiPlxuICAgICAgICAgIDxUZXh0IGNsYXNzTmFtZT1cInRleHQtcmVkLTUwMFwiPkZhaWxlZCB0byBsb2FkIGFuYWx5dGljcy48L1RleHQ+XG4gICAgICAgIDwvZGl2PlxuICAgICAgKSA6IChcbiAgICAgICAgPD5cbiAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImdyaWQgZ3JpZC1jb2xzLTEgZ2FwLTQgc206Z3JpZC1jb2xzLTIgbGc6Z3JpZC1jb2xzLTRcIj5cbiAgICAgICAgICAgIHtzdGF0Q2FyZHMubWFwKGMgPT4gKFxuICAgICAgICAgICAgICA8ZGl2IGtleT17Yy5sYWJlbH0gY2xhc3NOYW1lPVwicm91bmRlZC14bCBib3JkZXIgYm9yZGVyLWdyYXktMjAwIGJnLXdoaXRlIHAtNSBkYXJrOmJvcmRlci1ncmF5LTcwMCBkYXJrOmJnLWdyYXktODAwXCI+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9e2BtYi0zIGZsZXggaC0xMCB3LTEwIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLWxnICR7Yy5jb2xvcn1gfT5cbiAgICAgICAgICAgICAgICAgIDxjLmljb24gY2xhc3NOYW1lPVwiaC01IHctNVwiIC8+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPFRleHQgYXM9XCJzcGFuXCIgdmFyaWFudD1cImJvZHktbGdcIiB3ZWlnaHQ9XCJib2xkXCI+e2MudmFsdWV9PC9UZXh0PlxuICAgICAgICAgICAgICAgIDxUZXh0IHRvbmU9XCJzZWNvbmRhcnlcIiBjbGFzc05hbWU9XCJibG9ja1wiPntjLmxhYmVsfTwvVGV4dD5cbiAgICAgICAgICAgICAgICA8VGV4dCB2YXJpYW50PVwiY2FwdGlvblwiIHRvbmU9XCJsaWdodFwiIGNsYXNzTmFtZT1cIm10LTAuNSBibG9ja1wiPntjLnN1Yn08L1RleHQ+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKSl9XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImdyaWQgZ3JpZC1jb2xzLTEgZ2FwLTRcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwicm91bmRlZC14bCBib3JkZXIgYm9yZGVyLWdyYXktMjAwIGJnLXdoaXRlIHAtNSBkYXJrOmJvcmRlci1ncmF5LTcwMCBkYXJrOmJnLWdyYXktODAwXCI+XG4gICAgICAgICAgICAgIDxUZXh0IHdlaWdodD1cInNlbWlib2xkXCIgY2xhc3NOYW1lPVwibWItNCBibG9ja1wiPlNlbnRpbWVudCBPdmVydmlldzwvVGV4dD5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtNlwiPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwicmVsYXRpdmUgaC0zMiB3LTMyIHNocmluay0wXCI+XG4gICAgICAgICAgICAgICAgICA8RG91Z2hudXRcbiAgICAgICAgICAgICAgICAgICAgZGF0YT17e1xuICAgICAgICAgICAgICAgICAgICAgIGxhYmVsczogc2VudGltZW50U3BsaXQubWFwKHMgPT4gcy5sYWJlbCksXG4gICAgICAgICAgICAgICAgICAgICAgZGF0YXNldHM6IFt7XG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiBzZW50aW1lbnRTcGxpdC5tYXAocyA9PiBzLnBlcmNlbnQpLFxuICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZENvbG9yOiBzZW50aW1lbnRTcGxpdC5tYXAocyA9PiBzLmNvbG9yKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlcldpZHRoOiAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2l0cyBvbiB0aGUgcmluZyBpdHNlbGYsIHNvIGl0IGRvZXNuJ3QgY29sbGlkZSB3aXRoIHRoZSBjZW50ZXIgb3ZlcmxheSB0ZXh0LlxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YWxhYmVsczogc2xpY2VWYWx1ZUxhYmVscygodikgPT4gYCR7dn0lYCwgOSksXG4gICAgICAgICAgICAgICAgICAgICAgfV0sXG4gICAgICAgICAgICAgICAgICAgI
827H19XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnM9e3tcbiAgICAgICAgICAgICAgICAgICAgICBjdXRvdXQ6ICc3MiUnLFxuICAgICAgICAgICAgICAgICAgICAgIHBsdWdpbnM6IHsgbGVnZW5kOiB7IGRpc3BsYXk6IGZhbHNlIH0sIHRvb2x0aXA6IHsgZW5hYmxlZDogdHJ1ZSB9IH0sXG4gICAgICAgICAgICAgICAgICAgIH19XG4gICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJwb2ludGVyLWV2ZW50cy1ub25lIGFic29sdXRlIGluc2V0LTAgZmxleCBmbGV4LWNvbCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXJcIj5cbiAgICAgICAgICAgICAgICAgICAgPFRleHQgYXM9XCJzcGFuXCIgdmFyaWFudD1cImJvZHktbGdcIiB3ZWlnaHQ9XCJib2xkXCI+XG4gICAgICAgICAgICAgICAgICAgICAge3Bvc2l0aXZlUGVyY2VudCAhPT0gbnVsbCA/IGAke3Bvc2l0aXZlUGVyY2VudH0lYCA6ICfigJQnfVxuICAgICAgICAgICAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICAgICAgICAgICAgIDxUZXh0IGFzPVwic3BhblwiIHZhcmlhbnQ9XCJjYXB0aW9uXCIgdG9uZT1cImxpZ2h0XCI+XG4gICAgICAgICAgICAgICAgICAgICAge3Bvc2l0aXZlUGVyY2VudCAhPT0gbnVsbCA/ICdQb3NpdGl2ZScgOiB0b29GZXdDbGFzc2lmaWVkID8gJ1RvbyBmZXcnIDogJ05vIGRhdGEnfVxuICAgICAgICAgICAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImZsZXgtMSBzcGFjZS15LTJcIj5cbiAgICAgICAgICAgICAgICAgIHtzZW50aW1lbnRTcGxpdC5tYXAocyA9PiAoXG4gICAgICAgICAgICAgICAgICAgIDxkaXYga2V5PXtzLmxhYmVsfSBjbGFzc05hbWU9XCJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMlwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT1cImgtMiB3LTIgc2hyaW5rLTAgcm91bmRlZC1mdWxsXCIgc3R5bGU9e3sgYmFja2dyb3VuZENvbG9yOiBzLmNvbG9yIH19IC8+XG4gICAgICAgICAgICAgICAgICAgICAgPFRleHQgYXM9XCJzcGFuXCIgdmFyaWFudD1cImxhYmVsXCIgY2xhc3NOYW1lPVwidy0xNiBzaHJpbmstMFwiPntzLmxhYmVsfTwvVGV4dD5cbiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImgtMS41IGZsZXgtMSBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1mdWxsIGJnLWdyYXktMTAwIGRhcms6YmctZ3JheS03MDBcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiaC1mdWxsIHJvdW5kZWQtZnVsbFwiIHN0eWxlPXt7IHdpZHRoOiBgJHtzLnBlcmNlbnR9JWAsIGJhY2tncm91bmRDb2xvcjogcy5jb2xvciB9fSAvPlxuICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICAgIDxUZXh0IGFzPVwic3BhblwiIHZhcmlhbnQ9XCJsYWJlbFwiIHdlaWdodD1cInNlbWlib2xkXCIgY2xhc3NOYW1lPVwidy0xMCBzaHJpbmstMCB0ZXh0LXJpZ2h0XCI+e3MucGVyY2VudH0lPC9UZXh0PlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICkpfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPFRleHQgdmFyaWFudD1cImNhcHRpb25cIiB0b25lPVwibGlnaHRcIiBjbGFzc05hbWU9XCJtdC0zIGJsb2NrXCI+XG4gICAgICAgICAgICAgICAge2FuYWx5dGljcyA/IG1hcmdpbk5vdGUoYW5hbHl0aWNzLnBvc2l0aXZlU2VudGltZW50KSA6ICdObyBkYXRhIHlldCd9XG4gICAgICAgICAgICAgIDwvVGV4dD5cblxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm10LTUgcm91bmRlZC1sZyBiZy1zZWNvbmRhcnkgcC00IGRhcms6YmctZ3JheS05MDBcIj5cbiAgICAgICAgICAgICAgICA8VGV4dCB2YXJpYW50PVwiY2FwdGlvblwiIHdlaWdodD1cInNlbWlib2xkXCIgdG9uZT1cInNlY29uZGFyeVwiIGNsYXNzTmFtZT1cImJsb2NrXCI+U2VudGltZW50IFRyZW5kPC9UZXh0PlxuICAgICAgICAgICAgICAgIHshYW5hbHl0aWNzIHx8IGFuYWx5dGljcy50cmVuZC5idWNrZXRzLmxlbmd0aCA9PT0gMCA/IChcbiAgICAgICAgICAgICAgICAgIDxUZXh0IHZhcmlhbnQ9XCJjYXB0aW9uXCIgdG9uZT1cImxpZ2h0XCIgY2xhc3NOYW1lPVwibXQtMSBibG9jayB0ZXh0LWNlbnRlclwiPk5vIHRyZW5kIGRhdGEgZm9yIHRoaXMgZGF0ZSByYW5nZSB5ZXQuPC9UZXh0PlxuICAgICAgICAgICAgICAgICkgOiAoXG4gICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm10LTIgaC00MFwiPlxuICAgICAgICAgICAgICAgICAgICA8TGluZVxuICAgICAgICAgICAgICAgICAgICAgIGRhdGE9e3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsczogYW5hbHl0aWNzLnRyZW5kLmJ1Y2tldHMubWFwKChiKSA9PiBmb3JtYXRCdWNrZXRMYWJlbChiLCBncmFudWxhcml0eSkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YXNldHM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsOiAnUG9zaXRpdmUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IGFuYWx5dGljcy50cmVuZC5wb3NpdGl2ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXJDb2xvcjogJyMyMmM1NWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogJyMyMmM1NWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlbnNpb246IDAuMyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb2ludFJhZGl1czogMixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhbGFiZWxzOiBsaW5lRW5kcG9pbnRMYWJlbHMoU3RyaW5nLCA4KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsOiAnTmVnYXRpdmUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IGFuYWx5dGljcy50cmVuZC5uZWdhdGl2ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXJDb2xvcjogJyNlZjQ0NDQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogJyNlZjQ0NDQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgI
827HRlbnNpb246IDAuMyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb2ludFJhZGl1czogMixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhbGFiZWxzOiBsaW5lRW5kcG9pbnRMYWJlbHMoU3RyaW5nLCA4KSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsOiAnTmV1dHJhbCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogYW5hbHl0aWNzLnRyZW5kLm5ldXRyYWwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyQ29sb3I6ICcjOWNhM2FmJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6ICcjOWNhM2FmJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZW5zaW9uOiAwLjMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRSYWRpdXM6IDIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YWxhYmVsczogbGluZUVuZHBvaW50TGFiZWxzKFN0cmluZywgOCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbDogJ1VuY2xhc3NpZmllZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogYW5hbHl0aWNzLnRyZW5kLnVuY2xhc3NpZmllZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXJDb2xvcjogJyNkMWQ1ZGInLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogJyNkMWQ1ZGInLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlckRhc2g6IFs0LCA0XSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZW5zaW9uOiAwLjMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRSYWRpdXM6IDIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGV4dCB1c2VzIGEgZGFya2VyIGdyYXkgdGhhbiB0aGUgbGluZSBpdHNlbGYg4oCUIHRoZSBsaW5lJ3Mgb3duXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGFsZSBodWUgd291bGQgYmUgaWxsZWdpYmxlIGFzIGxhYmVsIHRleHQgb24gYSB3aGl0ZSBzdXJmYWNlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFsYWJlbHM6IGxpbmVFbmRwb2ludExhYmVscyhTdHJpbmcsIDgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgICB9fVxuICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnM9e3tcbiAgICAgICAgICAgICAgICAgICAgICAgIG1haW50YWluQXNwZWN0UmF0aW86IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0OiB7IHBhZGRpbmc6IHsgdG9wOiAxNCB9IH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZXM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgeDogeyB0aWNrczogeyBmb250OiB7IHNpemU6IDEwIH0gfSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICB5OiB7IGJlZ2luQXRaZXJvOiB0cnVlLCBncmFjZTogJzEwJScsIHRpY2tzOiB7IGZvbnQ6IHsgc2l6ZTogMTAgfSB9IH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgcGx1Z2luczogeyBsZWdlbmQ6IHsgcG9zaXRpb246ICdib3R0b20nLCBsYWJlbHM6IHsgYm94V2lkdGg6IDgsIGZvbnQ6IHsgc2l6ZTogMTAgfSB9IH0gfSxcbiAgICAgICAgICAgICAgICAgICAgICB9fVxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgKX1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiZ3JpZCBncmlkLWNvbHMtMSBnYXAtNCBsZzpncmlkLWNvbHMtMlwiPlxuICAgICAgICAgICAgPEJyZWFrZG93bkNhcmRcbiAgICAgICAgICAgICAgdGl0bGU9XCJFbW90aW9uIEJyZWFrZG93blwiXG4gICAgICAgICAgICAgIGljb249e0hlYXJ0fVxuICAgICAgICAgICAgICBpY29uQ29sb3I9XCJ0ZXh0LXBpbmstNTAwXCJcbiAgICAgICAgICAgICAgcm93cz17ZW1vdGlvblJvd3N9XG4gICAgICAgICAgICAgIGVtcHR5Tm90ZT1cIk5vIGVtb3Rpb24gZGF0YSB5ZXQuXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8QnJlYWtkb3duQ2FyZFxuICAgICAgICAgICAgICB0aXRsZT1cIkxhbmd1YWdlIEJyZWFrZG93blwiXG4gICAgICAgICAgICAgIGljb249e0dsb2JlfVxuICAgICAgICAgICAgICBpY29uQ29sb3I9XCJ0ZXh0LXB1cnBsZS01MDBcIlxuICAgICAgICAgICAgICByb3dzPXtsYW5ndWFnZVJvd3N9XG4gICAgICAgICAgICAgIGVtcHR5Tm90ZT1cIk5vIGxhbmd1YWdlIGRhdGEgeWV0LlwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8Lz5cbiAgICAgICl9XG4gICAgPC9kaXY+XG4gIClcbn1cbiJdfQ==

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.