@rester159/blacktip 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 (63) hide show
  1. package/AGENTS.md +249 -0
  2. package/LICENSE +38 -0
  3. package/README.md +234 -0
  4. package/dist/behavioral/calibration.d.ts +145 -0
  5. package/dist/behavioral/calibration.d.ts.map +1 -0
  6. package/dist/behavioral/calibration.js +242 -0
  7. package/dist/behavioral/calibration.js.map +1 -0
  8. package/dist/behavioral-engine.d.ts +156 -0
  9. package/dist/behavioral-engine.d.ts.map +1 -0
  10. package/dist/behavioral-engine.js +521 -0
  11. package/dist/behavioral-engine.js.map +1 -0
  12. package/dist/blacktip.d.ts +289 -0
  13. package/dist/blacktip.d.ts.map +1 -0
  14. package/dist/blacktip.js +1574 -0
  15. package/dist/blacktip.js.map +1 -0
  16. package/dist/browser-core.d.ts +47 -0
  17. package/dist/browser-core.d.ts.map +1 -0
  18. package/dist/browser-core.js +375 -0
  19. package/dist/browser-core.js.map +1 -0
  20. package/dist/cli.d.ts +20 -0
  21. package/dist/cli.d.ts.map +1 -0
  22. package/dist/cli.js +226 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/element-finder.d.ts +42 -0
  25. package/dist/element-finder.d.ts.map +1 -0
  26. package/dist/element-finder.js +240 -0
  27. package/dist/element-finder.js.map +1 -0
  28. package/dist/evasion.d.ts +39 -0
  29. package/dist/evasion.d.ts.map +1 -0
  30. package/dist/evasion.js +488 -0
  31. package/dist/evasion.js.map +1 -0
  32. package/dist/fingerprint.d.ts +19 -0
  33. package/dist/fingerprint.d.ts.map +1 -0
  34. package/dist/fingerprint.js +171 -0
  35. package/dist/fingerprint.js.map +1 -0
  36. package/dist/index.d.ts +19 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +14 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/logging.d.ts +13 -0
  41. package/dist/logging.d.ts.map +1 -0
  42. package/dist/logging.js +42 -0
  43. package/dist/logging.js.map +1 -0
  44. package/dist/observability.d.ts +69 -0
  45. package/dist/observability.d.ts.map +1 -0
  46. package/dist/observability.js +189 -0
  47. package/dist/observability.js.map +1 -0
  48. package/dist/proxy-pool.d.ts +101 -0
  49. package/dist/proxy-pool.d.ts.map +1 -0
  50. package/dist/proxy-pool.js +156 -0
  51. package/dist/proxy-pool.js.map +1 -0
  52. package/dist/snapshot.d.ts +59 -0
  53. package/dist/snapshot.d.ts.map +1 -0
  54. package/dist/snapshot.js +91 -0
  55. package/dist/snapshot.js.map +1 -0
  56. package/dist/types.d.ts +243 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +15 -0
  59. package/dist/types.js.map +1 -0
  60. package/examples/01-basic-navigate.ts +40 -0
  61. package/examples/02-login-with-mfa.ts +68 -0
  62. package/examples/03-agent-serve-mode.md +98 -0
  63. package/package.json +62 -0
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Behavioral calibration — ingestion and parameter-fitting for real
3
+ * human mouse dynamics and keystroke dynamics datasets.
4
+ *
5
+ * This module is a scaffold. The actual dataset downloads (Balabit Mouse
6
+ * Dynamics Challenge, Chao Shen's mouse data, CMU Keystroke Dynamics,
7
+ * GREYC-NISLAB) are not bundled — they're free-for-research but have
8
+ * varying license terms and live on academic FTP sites that come and go.
9
+ * The structure here is designed so that when you DO have a dataset in
10
+ * hand (CSV, JSON, or the dataset's native format), you can write a tiny
11
+ * parser, feed it through `fitFromSamples`, and get back a
12
+ * `CalibratedProfile` that plugs directly into `BehavioralEngine`.
13
+ *
14
+ * The philosophy is: we don't ship training data, we ship the
15
+ * calibration pipeline. Users bring their own data, we turn it into a
16
+ * behavioral profile. This avoids license issues and lets different
17
+ * users calibrate against different populations (e.g., a bank's fraud
18
+ * team might calibrate against their own telemetry).
19
+ */
20
+ // ── Distribution fitting ──
21
+ /**
22
+ * Fit a `DistributionFit` to a 1D array of observations.
23
+ * Uses the empirical min/max/mean/stddev and samples the empirical CDF
24
+ * for the 5/50/95 percentiles rather than assuming normality — many
25
+ * behavioral measurements are right-skewed (log-normal-ish).
26
+ */
27
+ export function fitDistribution(samples) {
28
+ if (samples.length === 0) {
29
+ throw new Error('Cannot fit distribution: empty sample set');
30
+ }
31
+ const sorted = [...samples].sort((a, b) => a - b);
32
+ const n = sorted.length;
33
+ const min = sorted[0];
34
+ const max = sorted[n - 1];
35
+ const mean = sorted.reduce((s, v) => s + v, 0) / n;
36
+ const variance = sorted.reduce((s, v) => s + (v - mean) ** 2, 0) / n;
37
+ const sigma = Math.sqrt(variance);
38
+ const pct = (p) => {
39
+ const idx = Math.max(0, Math.min(n - 1, Math.floor(p * n)));
40
+ return sorted[idx];
41
+ };
42
+ return {
43
+ min,
44
+ max,
45
+ mean,
46
+ sigma,
47
+ p5: pct(0.05),
48
+ p50: pct(0.5),
49
+ p95: pct(0.95),
50
+ sampleCount: n,
51
+ };
52
+ }
53
+ // ── Mouse fitting ──
54
+ /**
55
+ * Fit Fitts' Law constants (a, b) from a set of mouse movements via
56
+ * ordinary least squares on (log2(D/W + 1), MT).
57
+ *
58
+ * Falls back to the canonical (a=90, b=140) if the dataset doesn't
59
+ * provide target widths.
60
+ */
61
+ export function fitFittsLaw(movements) {
62
+ const points = [];
63
+ for (const m of movements) {
64
+ if (m.samples.length < 2)
65
+ continue;
66
+ const first = m.samples[0];
67
+ const last = m.samples[m.samples.length - 1];
68
+ const mt = last.timestampMs - first.timestampMs;
69
+ if (mt <= 0)
70
+ continue;
71
+ // Require target info for this sample to contribute.
72
+ if (last.targetX == null || last.targetY == null || last.targetWidth == null || last.targetWidth <= 0)
73
+ continue;
74
+ const d = Math.hypot(last.targetX - first.x, last.targetY - first.y);
75
+ if (d <= 0)
76
+ continue;
77
+ const id = Math.log2(d / last.targetWidth + 1);
78
+ points.push({ x: id, y: mt });
79
+ }
80
+ if (points.length < 5) {
81
+ // Not enough data — return canonical desktop-mouse values.
82
+ return { a: 90, b: 140 };
83
+ }
84
+ // OLS fit: y = a + b*x
85
+ const n = points.length;
86
+ const sumX = points.reduce((s, p) => s + p.x, 0);
87
+ const sumY = points.reduce((s, p) => s + p.y, 0);
88
+ const sumXY = points.reduce((s, p) => s + p.x * p.y, 0);
89
+ const sumX2 = points.reduce((s, p) => s + p.x * p.x, 0);
90
+ const meanX = sumX / n;
91
+ const meanY = sumY / n;
92
+ const b = (sumXY - n * meanX * meanY) / (sumX2 - n * meanX * meanX);
93
+ const a = meanY - b * meanX;
94
+ return { a, b };
95
+ }
96
+ /**
97
+ * Compute path curvature (observed path length / straight-line distance)
98
+ * and max perpendicular deviation for a single movement.
99
+ */
100
+ function mouseMovementGeometry(m) {
101
+ const samples = m.samples;
102
+ if (samples.length < 2)
103
+ return null;
104
+ const start = samples[0];
105
+ const end = samples[samples.length - 1];
106
+ const straightDist = Math.hypot(end.x - start.x, end.y - start.y);
107
+ if (straightDist <= 0)
108
+ return null;
109
+ let pathLen = 0;
110
+ for (let i = 1; i < samples.length; i++) {
111
+ pathLen += Math.hypot(samples[i].x - samples[i - 1].x, samples[i].y - samples[i - 1].y);
112
+ }
113
+ // Perpendicular distance from each sample to the straight start→end line.
114
+ let maxPerp = 0;
115
+ const lineDX = end.x - start.x;
116
+ const lineDY = end.y - start.y;
117
+ const lineLen = Math.hypot(lineDX, lineDY);
118
+ for (const s of samples) {
119
+ const perp = Math.abs((s.x - start.x) * lineDY - (s.y - start.y) * lineDX) / lineLen;
120
+ if (perp > maxPerp)
121
+ maxPerp = perp;
122
+ }
123
+ return { curvature: pathLen / straightDist, maxPerpDeviation: maxPerp };
124
+ }
125
+ /**
126
+ * Fit mouse dynamics from a set of recorded movements.
127
+ */
128
+ export function fitMouseDynamics(movements) {
129
+ const curvatures = [];
130
+ const perpDeviations = [];
131
+ const overshoots = [];
132
+ for (const m of movements) {
133
+ const geo = mouseMovementGeometry(m);
134
+ if (!geo)
135
+ continue;
136
+ curvatures.push(geo.curvature);
137
+ perpDeviations.push(geo.maxPerpDeviation);
138
+ }
139
+ const { a: fittsA, b: fittsB } = fitFittsLaw(movements);
140
+ // Overshoot detection requires knowing which samples are past the
141
+ // target center. Skip for now — plug in once a dataset with target
142
+ // labeling is available.
143
+ const overshootFit = overshoots.length >= 5
144
+ ? fitDistribution(overshoots)
145
+ : fitDistribution([5, 8, 10, 12, 15]); // canonical fallback
146
+ return {
147
+ fittsA,
148
+ fittsB,
149
+ pathCurvatureRatio: curvatures.length >= 5
150
+ ? fitDistribution(curvatures)
151
+ : fitDistribution([1.05, 1.08, 1.10, 1.12, 1.15]),
152
+ perpendicularDeviation: perpDeviations.length >= 5
153
+ ? fitDistribution(perpDeviations)
154
+ : fitDistribution([10, 15, 20, 25, 30]),
155
+ overshootPx: overshootFit,
156
+ };
157
+ }
158
+ // ── Typing fitting ──
159
+ /**
160
+ * Fit typing dynamics from a set of recorded typing sessions.
161
+ */
162
+ export function fitTypingDynamics(sessions) {
163
+ const allFlights = [];
164
+ const allHolds = [];
165
+ const digraphBuckets = new Map();
166
+ let total = 0;
167
+ let typos = 0;
168
+ for (const session of sessions) {
169
+ for (let i = 0; i < session.keystrokes.length; i++) {
170
+ const ks = session.keystrokes[i];
171
+ allFlights.push(ks.flightTimeMs);
172
+ allHolds.push(ks.holdTimeMs);
173
+ total++;
174
+ // Record digraph if we have the previous character too.
175
+ if (i > 0) {
176
+ const prev = session.keystrokes[i - 1];
177
+ const digraph = (prev.key + ks.key).toLowerCase();
178
+ if (/^[a-z]{2}$/.test(digraph)) {
179
+ const list = digraphBuckets.get(digraph) ?? [];
180
+ list.push(ks.flightTimeMs);
181
+ digraphBuckets.set(digraph, list);
182
+ }
183
+ }
184
+ // A "typo" in this context is a key that was followed by a
185
+ // backspace within the next 2 keystrokes (if the dataset tracks
186
+ // that). Simple proxy: assume 2% mistake rate when we can't tell.
187
+ if (ks.key === 'Backspace')
188
+ typos++;
189
+ }
190
+ }
191
+ const digraphFit = {};
192
+ for (const [digraph, samples] of digraphBuckets) {
193
+ if (samples.length >= 5) {
194
+ digraphFit[digraph] = fitDistribution(samples);
195
+ }
196
+ }
197
+ return {
198
+ flightTime: allFlights.length >= 5 ? fitDistribution(allFlights) : fitDistribution([80, 100, 120, 150, 200]),
199
+ holdTime: allHolds.length >= 5 ? fitDistribution(allHolds) : fitDistribution([40, 60, 80, 100]),
200
+ digraphFlightTime: digraphFit,
201
+ mistakeRate: total > 0 ? typos / total : 0.02,
202
+ };
203
+ }
204
+ // ── Full profile derivation ──
205
+ /**
206
+ * Given fitted mouse and typing dynamics, derive a ProfileConfig that
207
+ * plugs into `new BehavioralEngine(profileConfig)`.
208
+ *
209
+ * The mapping is conservative: we use the 5th–95th percentiles from the
210
+ * fits as the `[min, max]` tuples for the engine's uniform-ish sampling.
211
+ */
212
+ export function deriveProfileConfig(mouse, typing) {
213
+ return {
214
+ typingSpeedMs: [Math.round(typing.flightTime.p5), Math.round(typing.flightTime.p95)],
215
+ pauseBetweenActionsMs: [300, 1000],
216
+ scrollSpeedMs: [150, 300],
217
+ mouseMovementCurve: 'bezier',
218
+ clickDwellMs: [Math.round(typing.holdTime.p5), Math.round(typing.holdTime.p95)],
219
+ readingWpm: [200, 300],
220
+ mistakeRate: Math.max(0.001, Math.min(0.1, typing.mistakeRate)),
221
+ recoveryBehavior: 'natural',
222
+ pasteThreshold: 50,
223
+ };
224
+ }
225
+ /**
226
+ * End-to-end calibration: take raw mouse movements and typing sessions,
227
+ * produce a CalibratedProfile.
228
+ */
229
+ export function fitFromSamples(name, source, movements, sessions) {
230
+ const mouse = fitMouseDynamics(movements);
231
+ const typing = fitTypingDynamics(sessions);
232
+ const profileConfig = deriveProfileConfig(mouse, typing);
233
+ return {
234
+ name,
235
+ source,
236
+ sampleCount: movements.length + sessions.length,
237
+ mouse,
238
+ typing,
239
+ profileConfig,
240
+ };
241
+ }
242
+ //# sourceMappingURL=calibration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calibration.js","sourceRoot":"","sources":["../../src/behavioral/calibration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,156 @@
1
+ import type { ProfileConfig, Point, BoundingBox } from './types';
2
+ /**
3
+ * Importance level for an action. Drives how long the pre-action hesitation
4
+ * is (humans hesitate more on consequential actions) and how careful the
5
+ * mouse path is (more overshoot correction for high-importance targets).
6
+ */
7
+ export type ActionImportance = 'low' | 'normal' | 'high';
8
+ export interface MouseStep {
9
+ x: number;
10
+ y: number;
11
+ delay: number;
12
+ }
13
+ export interface KeystrokeStep {
14
+ key: string;
15
+ delay: number;
16
+ holdDuration: number;
17
+ isTypo?: boolean;
18
+ correctionSequence?: {
19
+ key: string;
20
+ delay: number;
21
+ holdDuration: number;
22
+ }[];
23
+ }
24
+ export interface ScrollStep {
25
+ deltaY: number;
26
+ delay: number;
27
+ }
28
+ export declare const HUMAN_PROFILE: ProfileConfig;
29
+ export declare const SCRAPER_PROFILE: ProfileConfig;
30
+ /**
31
+ * Box-Muller transform: generates a normally-distributed random number
32
+ * centered on (min+max)/2 with sigma = (max-min)/6, clamped to [min, max].
33
+ *
34
+ * The 6-sigma span means ~99.7% of raw samples already fall within bounds;
35
+ * clamping handles the remaining tail.
36
+ */
37
+ export declare function sampleNormal(min: number, max: number): number;
38
+ export declare class BehavioralEngine {
39
+ private readonly profile;
40
+ constructor(profile: ProfileConfig);
41
+ /**
42
+ * Generate a cubic Bézier mouse path from `from` to `to`.
43
+ *
44
+ * - Two random control points are offset perpendicular to the straight line.
45
+ * - Step count scales with distance (20-50 steps).
46
+ * - Timing uses an ease-in/ease-out curve (accelerate then decelerate).
47
+ * - Micro-jitter (±1-3px) simulates hand tremor.
48
+ * - For distances < 50px to target the path overshoots by 5-15px, then
49
+ * curves back, simulating the corrective saccade real users perform.
50
+ */
51
+ generateMousePath(from: Point, to: Point): MouseStep[];
52
+ /**
53
+ * Generate a realistic keystroke sequence for the given text.
54
+ *
55
+ * Cadence rules:
56
+ * - Common digraphs → 60-80% of base delay (muscle-memory pairs)
57
+ * - Uncommon symbols → 130-170% of base delay (hunt-and-peck)
58
+ * - Numeric digits → 110-130% of base delay
59
+ * - Everything else → 100% of base delay (with normal-distribution jitter)
60
+ *
61
+ * Typos are injected at the configured `mistakeRate`. Each typo produces:
62
+ * wrong char → pause (200-500ms) → backspace → correct char
63
+ *
64
+ * Hold duration for every key is 40-100ms, normally distributed.
65
+ */
66
+ generateTypingSequence(text: string): KeystrokeStep[];
67
+ /**
68
+ * Pre-action pause: sampled from the profile's `pauseBetweenActionsMs` range
69
+ * using a normal distribution so most pauses cluster around the middle.
70
+ *
71
+ * If `importance` is provided, the pause is scaled:
72
+ * - 'low' → 0.5× (skim/browse actions)
73
+ * - 'normal' → 1.0× (default)
74
+ * - 'high' → 2.0–3.0× + a hesitation spike for consequential actions
75
+ *
76
+ * The rationale: real humans don't hesitate uniformly. They take longer
77
+ * before clicking "Submit Payment" than before scrolling. Behavioral
78
+ * biometrics systems profile this correlation — if every click has the
79
+ * same pre-pause distribution regardless of target importance, that's
80
+ * itself a bot signal.
81
+ */
82
+ generatePreActionPause(importance?: ActionImportance): number;
83
+ /**
84
+ * Post-action pause: shorter than pre-action (100-400ms).
85
+ */
86
+ generatePostActionPause(): number;
87
+ /**
88
+ * Fitts' Law-based movement time estimate for a pointing motion from
89
+ * the current mouse position to a target of width W at distance D.
90
+ *
91
+ * MT = a + b * log2(D / W + 1)
92
+ *
93
+ * Where a and b are device-specific constants. For mouse on desktop:
94
+ * a ≈ 90 ms (starting latency)
95
+ * b ≈ 140 ms (slope of the speed-accuracy tradeoff)
96
+ *
97
+ * These constants are from Card, English & Burr (1978) and have been
98
+ * reconfirmed many times for general mouse use. Fitts' Law is the best-
99
+ * validated model of human motor control for pointing tasks and is
100
+ * exactly what behavioral biometric systems calibrate against. Using
101
+ * it here means our mouse timings match the distribution real users
102
+ * produce.
103
+ *
104
+ * Returns an estimated movement time in milliseconds, clamped to a
105
+ * reasonable range so tiny/huge moves don't produce absurd values.
106
+ */
107
+ fittsLawMovementTime(distancePx: number, targetWidthPx: number): number;
108
+ /**
109
+ * Estimate how long it would take a human to read a given piece of text,
110
+ * based on the profile's WPM range and an average word length of ~5
111
+ * characters. Used for "reading pause" simulation before clicking a
112
+ * button that follows a block of text the user would plausibly scan
113
+ * (terms of service, error messages, important notices).
114
+ */
115
+ generateReadingPause(textLength: number): number;
116
+ /**
117
+ * Generate a mouse path that scans left-to-right across a text block
118
+ * like an eye tracker follows reading gaze. Used before clicking a
119
+ * button that follows important copy.
120
+ *
121
+ * Returns a series of mouse positions sweeping across each line of
122
+ * the text block, with short dwells at the end of each line (like
123
+ * a saccade back to the start of the next line).
124
+ */
125
+ generateReadingScanPath(textBox: BoundingBox, lineCount: number): MouseStep[];
126
+ /**
127
+ * Click dwell: time the button is held down, sampled from profile range.
128
+ */
129
+ generateClickDwell(): number;
130
+ /**
131
+ * Break a total scroll amount into 3-8 steps with deceleration:
132
+ * larger deltas first, tapering off toward the end (mimicking a
133
+ * flick-then-settle scroll gesture).
134
+ *
135
+ * Delay between steps is 30-100ms, sampled from the profile's scroll speed.
136
+ */
137
+ generateScrollSteps(amount: number, direction: 'up' | 'down'): ScrollStep[];
138
+ /**
139
+ * Should the engine paste rather than type? True when text length exceeds
140
+ * the profile's paste threshold.
141
+ */
142
+ shouldPaste(text: string): boolean;
143
+ /**
144
+ * Pick a click position inside `box`, biased toward the center via a
145
+ * normal distribution (sigma = dimension/6). A minimum ±2px offset from
146
+ * the exact center prevents pixel-perfect robotic clicks.
147
+ */
148
+ generateClickPosition(box: BoundingBox): Point;
149
+ /**
150
+ * Pick a plausible "wrong" key for a given character by looking at
151
+ * QWERTY adjacency. Falls back to a random alpha character if the
152
+ * target isn't in the adjacency map.
153
+ */
154
+ private pickAdjacentKey;
155
+ }
156
+ //# sourceMappingURL=behavioral-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"behavioral-engine.d.ts","sourceRoot":"","sources":["../src/behavioral-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAIjE;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7E;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAID,eAAO,MAAM,aAAa,EAAE,aAU3B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,aAU7B,CAAC;AAIF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAc7D;AAuDD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,OAAO,EAAE,aAAa;IAQlC;;;;;;;;;OASG;IACH,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,SAAS,EAAE;IA2GtD;;;;;;;;;;;;;OAaG;IACH,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE;IAiErD;;;;;;;;;;;;;;OAcG;IACH,sBAAsB,CAAC,UAAU,GAAE,gBAA2B,GAAG,MAAM;IAsBvE;;OAEG;IACH,uBAAuB,IAAI,MAAM;IAIjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;IASvE;;;;;;OAMG;IACH,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAahD;;;;;;;;OAQG;IACH,uBAAuB,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE;IAoC7E;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAS5B;;;;;;OAMG;IACH,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,UAAU,EAAE;IAmC3E;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQlC;;;;OAIG;IACH,qBAAqB,CAAC,GAAG,EAAE,WAAW,GAAG,KAAK;IAiC9C;;;;OAIG;IACH,OAAO,CAAC,eAAe;CAgDxB"}