kanmi-perf-revenue 1.0.0 → 1.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 (90) hide show
  1. package/README.md +196 -186
  2. package/dist/empirical/ab-testing.d.ts +83 -0
  3. package/dist/empirical/ab-testing.d.ts.map +1 -0
  4. package/dist/empirical/ab-testing.js +281 -0
  5. package/dist/empirical/ab-testing.js.map +1 -0
  6. package/dist/empirical/alerting.d.ts +85 -0
  7. package/dist/empirical/alerting.d.ts.map +1 -0
  8. package/dist/empirical/alerting.js +358 -0
  9. package/dist/empirical/alerting.js.map +1 -0
  10. package/dist/empirical/attribution.d.ts +80 -0
  11. package/dist/empirical/attribution.d.ts.map +1 -0
  12. package/dist/empirical/attribution.js +305 -0
  13. package/dist/empirical/attribution.js.map +1 -0
  14. package/dist/empirical/cohort.d.ts +75 -0
  15. package/dist/empirical/cohort.d.ts.map +1 -0
  16. package/dist/empirical/cohort.js +305 -0
  17. package/dist/empirical/cohort.js.map +1 -0
  18. package/dist/empirical/conversion-curve.d.ts +7 -10
  19. package/dist/empirical/conversion-curve.d.ts.map +1 -1
  20. package/dist/empirical/conversion-curve.js +37 -4
  21. package/dist/empirical/conversion-curve.js.map +1 -1
  22. package/dist/empirical/correlation.d.ts +91 -0
  23. package/dist/empirical/correlation.d.ts.map +1 -0
  24. package/dist/empirical/correlation.js +461 -0
  25. package/dist/empirical/correlation.js.map +1 -0
  26. package/dist/empirical/data-import.d.ts +22 -0
  27. package/dist/empirical/data-import.d.ts.map +1 -1
  28. package/dist/empirical/data-import.js +44 -0
  29. package/dist/empirical/data-import.js.map +1 -1
  30. package/dist/empirical/datadog-session-query.d.ts +32 -0
  31. package/dist/empirical/datadog-session-query.d.ts.map +1 -1
  32. package/dist/empirical/datadog-session-query.js +238 -17
  33. package/dist/empirical/datadog-session-query.js.map +1 -1
  34. package/dist/empirical/engagement-analysis.d.ts +112 -0
  35. package/dist/empirical/engagement-analysis.d.ts.map +1 -0
  36. package/dist/empirical/engagement-analysis.js +354 -0
  37. package/dist/empirical/engagement-analysis.js.map +1 -0
  38. package/dist/empirical/export.d.ts +75 -0
  39. package/dist/empirical/export.d.ts.map +1 -0
  40. package/dist/empirical/export.js +392 -0
  41. package/dist/empirical/export.js.map +1 -0
  42. package/dist/empirical/forecasting.d.ts +80 -0
  43. package/dist/empirical/forecasting.d.ts.map +1 -0
  44. package/dist/empirical/forecasting.js +287 -0
  45. package/dist/empirical/forecasting.js.map +1 -0
  46. package/dist/empirical/funnel.d.ts +66 -0
  47. package/dist/empirical/funnel.d.ts.map +1 -0
  48. package/dist/empirical/funnel.js +293 -0
  49. package/dist/empirical/funnel.js.map +1 -0
  50. package/dist/empirical/history.d.ts +198 -0
  51. package/dist/empirical/history.d.ts.map +1 -0
  52. package/dist/empirical/history.js +396 -0
  53. package/dist/empirical/history.js.map +1 -0
  54. package/dist/empirical/index.d.ts +39 -16
  55. package/dist/empirical/index.d.ts.map +1 -1
  56. package/dist/empirical/index.js +95 -13
  57. package/dist/empirical/index.js.map +1 -1
  58. package/dist/empirical/interactions.d.ts +89 -0
  59. package/dist/empirical/interactions.d.ts.map +1 -0
  60. package/dist/empirical/interactions.js +346 -0
  61. package/dist/empirical/interactions.js.map +1 -0
  62. package/dist/empirical/opportunity-calculator.d.ts +6 -18
  63. package/dist/empirical/opportunity-calculator.d.ts.map +1 -1
  64. package/dist/empirical/opportunity-calculator.js +19 -1
  65. package/dist/empirical/opportunity-calculator.js.map +1 -1
  66. package/dist/empirical/report.d.ts +3 -11
  67. package/dist/empirical/report.d.ts.map +1 -1
  68. package/dist/empirical/report.js +11 -7
  69. package/dist/empirical/report.js.map +1 -1
  70. package/dist/empirical/roi-calculator.d.ts +104 -0
  71. package/dist/empirical/roi-calculator.d.ts.map +1 -0
  72. package/dist/empirical/roi-calculator.js +403 -0
  73. package/dist/empirical/roi-calculator.js.map +1 -0
  74. package/dist/empirical/seasonality.d.ts +80 -0
  75. package/dist/empirical/seasonality.d.ts.map +1 -0
  76. package/dist/empirical/seasonality.js +340 -0
  77. package/dist/empirical/seasonality.js.map +1 -0
  78. package/dist/empirical/segmentation.d.ts +135 -0
  79. package/dist/empirical/segmentation.d.ts.map +1 -0
  80. package/dist/empirical/segmentation.js +379 -0
  81. package/dist/empirical/segmentation.js.map +1 -0
  82. package/dist/empirical/statistics.d.ts +118 -0
  83. package/dist/empirical/statistics.d.ts.map +1 -0
  84. package/dist/empirical/statistics.js +344 -0
  85. package/dist/empirical/statistics.js.map +1 -0
  86. package/dist/empirical/sweet-spot.d.ts +81 -0
  87. package/dist/empirical/sweet-spot.d.ts.map +1 -0
  88. package/dist/empirical/sweet-spot.js +198 -0
  89. package/dist/empirical/sweet-spot.js.map +1 -0
  90. package/package.json +1 -1
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Attribution Models
3
+ *
4
+ * First-touch vs last-touch session attribution for understanding
5
+ * how performance at different touchpoints affects conversions.
6
+ *
7
+ * @author Kanmi Obasa <i@kanmiobasa.com>
8
+ */
9
+ // =============================================================================
10
+ // CORE ATTRIBUTION
11
+ // =============================================================================
12
+ /**
13
+ * Build user journeys from session data.
14
+ */
15
+ export function buildUserJourneys(sessions) {
16
+ // Group by user
17
+ const userMap = new Map();
18
+ for (const session of sessions) {
19
+ const userId = session.user_id || session.session_id;
20
+ if (!userMap.has(userId)) {
21
+ userMap.set(userId, []);
22
+ }
23
+ userMap.get(userId).push(session);
24
+ }
25
+ const journeys = [];
26
+ for (const [userId, userSessions] of userMap) {
27
+ // Sort by timestamp
28
+ const sorted = [...userSessions].sort((a, b) => (a.timestamp || '').localeCompare(b.timestamp || ''));
29
+ const touchpoints = sorted.map(s => ({
30
+ timestamp: s.timestamp || '',
31
+ pageType: s.page_type || 'unknown',
32
+ trafficSource: s.traffic_source || 'unknown',
33
+ lcp: s.lcp_ms,
34
+ converted: s.has_purchase,
35
+ value: s.purchase_value,
36
+ }));
37
+ const converted = touchpoints.some(t => t.converted);
38
+ const totalValue = touchpoints.reduce((sum, t) => sum + t.value, 0);
39
+ journeys.push({
40
+ userId,
41
+ touchpoints,
42
+ converted,
43
+ totalValue,
44
+ });
45
+ }
46
+ return journeys;
47
+ }
48
+ /**
49
+ * Calculate attribution for all touchpoints.
50
+ */
51
+ export function calculateAttribution(journeys, groupBy = 'pageType') {
52
+ const statsMap = new Map();
53
+ for (const journey of journeys) {
54
+ if (journey.touchpoints.length === 0)
55
+ continue;
56
+ // Get unique touchpoints in order
57
+ const touchpointOrder = journey.touchpoints.map(t => groupBy === 'pageType' ? t.pageType : t.trafficSource);
58
+ // Track sessions at each touchpoint
59
+ for (const tp of journey.touchpoints) {
60
+ const key = groupBy === 'pageType' ? tp.pageType : tp.trafficSource;
61
+ if (!statsMap.has(key)) {
62
+ statsMap.set(key, {
63
+ sessions: 0,
64
+ firstTouch: 0,
65
+ lastTouch: 0,
66
+ linear: 0,
67
+ positionBased: 0,
68
+ lcpValues: [],
69
+ convertingJourneys: 0,
70
+ totalJourneys: 0,
71
+ });
72
+ }
73
+ const stats = statsMap.get(key);
74
+ stats.sessions++;
75
+ if (tp.lcp !== null) {
76
+ stats.lcpValues.push(tp.lcp);
77
+ }
78
+ }
79
+ // Attribute conversions
80
+ if (journey.converted) {
81
+ const uniqueTouchpoints = [...new Set(touchpointOrder)];
82
+ const n = uniqueTouchpoints.length;
83
+ if (n === 0)
84
+ continue;
85
+ // First touch
86
+ const firstKey = touchpointOrder[0];
87
+ const firstStats = statsMap.get(firstKey);
88
+ if (firstStats) {
89
+ firstStats.firstTouch++;
90
+ firstStats.convertingJourneys++;
91
+ }
92
+ // Last touch
93
+ const lastKey = touchpointOrder[touchpointOrder.length - 1];
94
+ const lastStats = statsMap.get(lastKey);
95
+ if (lastStats) {
96
+ lastStats.lastTouch++;
97
+ if (lastKey !== firstKey) {
98
+ lastStats.convertingJourneys++;
99
+ }
100
+ }
101
+ // Linear (equal credit)
102
+ const linearCredit = 1 / n;
103
+ for (const tp of uniqueTouchpoints) {
104
+ const stats = statsMap.get(tp);
105
+ if (stats) {
106
+ stats.linear += linearCredit;
107
+ if (tp !== firstKey && tp !== lastKey) {
108
+ stats.convertingJourneys++;
109
+ }
110
+ }
111
+ }
112
+ // Position-based (40% first, 40% last, 20% distributed)
113
+ for (let i = 0; i < uniqueTouchpoints.length; i++) {
114
+ const tp = uniqueTouchpoints[i];
115
+ const stats = statsMap.get(tp);
116
+ if (!stats)
117
+ continue;
118
+ if (i === 0) {
119
+ stats.positionBased += 0.4;
120
+ }
121
+ else if (i === uniqueTouchpoints.length - 1) {
122
+ stats.positionBased += 0.4;
123
+ }
124
+ else {
125
+ const middleShare = 0.2 / Math.max(1, uniqueTouchpoints.length - 2);
126
+ stats.positionBased += middleShare;
127
+ }
128
+ }
129
+ }
130
+ // Track total journeys through each touchpoint
131
+ for (const tp of new Set(touchpointOrder)) {
132
+ const stats = statsMap.get(tp);
133
+ if (stats) {
134
+ stats.totalJourneys++;
135
+ }
136
+ }
137
+ }
138
+ // Convert to array
139
+ const result = [];
140
+ for (const [touchpoint, stats] of statsMap) {
141
+ const avgLcp = stats.lcpValues.length > 0
142
+ ? stats.lcpValues.reduce((a, b) => a + b, 0) / stats.lcpValues.length
143
+ : null;
144
+ // Performance impact: how much better do converting journeys perform here?
145
+ const conversionRate = stats.totalJourneys > 0
146
+ ? stats.convertingJourneys / stats.totalJourneys
147
+ : 0;
148
+ result.push({
149
+ touchpoint,
150
+ sessions: stats.sessions,
151
+ firstTouchConversions: stats.firstTouch,
152
+ lastTouchConversions: stats.lastTouch,
153
+ linearConversions: stats.linear,
154
+ positionBasedConversions: stats.positionBased,
155
+ avgLcp,
156
+ performanceImpactScore: conversionRate,
157
+ });
158
+ }
159
+ // Sort by first-touch conversions
160
+ result.sort((a, b) => b.firstTouchConversions - a.firstTouchConversions);
161
+ return result;
162
+ }
163
+ /**
164
+ * Analyze performance impact at different journey stages.
165
+ */
166
+ export function analyzePerformanceInfluence(journeys) {
167
+ // Get first-touch LCP for converting vs non-converting journeys
168
+ const convertingFirstLcp = [];
169
+ const nonConvertingFirstLcp = [];
170
+ const convertingLastLcp = [];
171
+ const nonConvertingLastLcp = [];
172
+ for (const journey of journeys) {
173
+ if (journey.touchpoints.length === 0)
174
+ continue;
175
+ const first = journey.touchpoints[0];
176
+ const last = journey.touchpoints[journey.touchpoints.length - 1];
177
+ if (journey.converted) {
178
+ if (first.lcp !== null)
179
+ convertingFirstLcp.push(first.lcp);
180
+ if (last.lcp !== null)
181
+ convertingLastLcp.push(last.lcp);
182
+ }
183
+ else {
184
+ if (first.lcp !== null)
185
+ nonConvertingFirstLcp.push(first.lcp);
186
+ if (last.lcp !== null)
187
+ nonConvertingLastLcp.push(last.lcp);
188
+ }
189
+ }
190
+ // Simple correlation: difference in means
191
+ const firstDiff = average(nonConvertingFirstLcp) - average(convertingFirstLcp);
192
+ const lastDiff = average(nonConvertingLastLcp) - average(convertingLastLcp);
193
+ // Normalize to 0-1 scale (higher = more impact)
194
+ const maxDiff = Math.max(Math.abs(firstDiff), Math.abs(lastDiff), 1);
195
+ const firstTouchCorrelation = Math.min(1, Math.abs(firstDiff) / maxDiff);
196
+ const lastTouchCorrelation = Math.min(1, Math.abs(lastDiff) / maxDiff);
197
+ const criticalTouchpoint = firstTouchCorrelation > lastTouchCorrelation
198
+ ? 'first_touch'
199
+ : 'last_touch';
200
+ return {
201
+ firstTouchCorrelation,
202
+ lastTouchCorrelation,
203
+ criticalTouchpoint,
204
+ };
205
+ }
206
+ /**
207
+ * Generate full attribution report.
208
+ */
209
+ export function generateAttributionReport(sessions, model = 'first_touch', groupBy = 'pageType') {
210
+ const journeys = buildUserJourneys(sessions);
211
+ const touchpointStats = calculateAttribution(journeys, groupBy);
212
+ const performanceInfluence = analyzePerformanceInfluence(journeys);
213
+ const insights = [];
214
+ const recommendations = [];
215
+ // Top performers by different models
216
+ const byFirstTouch = [...touchpointStats].sort((a, b) => b.firstTouchConversions - a.firstTouchConversions);
217
+ const byLastTouch = [...touchpointStats].sort((a, b) => b.lastTouchConversions - a.lastTouchConversions);
218
+ if (byFirstTouch.length > 0 && byLastTouch.length > 0) {
219
+ if (byFirstTouch[0].touchpoint !== byLastTouch[0].touchpoint) {
220
+ insights.push(`Attribution varies: ${byFirstTouch[0].touchpoint} leads first-touch, ${byLastTouch[0].touchpoint} leads last-touch`);
221
+ }
222
+ }
223
+ // Performance insight
224
+ if (performanceInfluence.firstTouchCorrelation > performanceInfluence.lastTouchCorrelation) {
225
+ insights.push('First impression performance has higher conversion impact');
226
+ recommendations.push('Prioritize landing page performance optimization');
227
+ }
228
+ else {
229
+ insights.push('Final touchpoint performance has higher conversion impact');
230
+ recommendations.push('Focus on checkout/conversion page performance');
231
+ }
232
+ // High-value touchpoints with poor performance
233
+ const highValuePoorPerf = touchpointStats.filter(tp => tp.firstTouchConversions > 0 && tp.avgLcp !== null && tp.avgLcp > 3000);
234
+ if (highValuePoorPerf.length > 0) {
235
+ recommendations.push(`Performance opportunity: ${highValuePoorPerf[0].touchpoint} has high conversions but ${highValuePoorPerf[0].avgLcp.toFixed(0)}ms LCP`);
236
+ }
237
+ return {
238
+ model,
239
+ touchpointStats,
240
+ insights,
241
+ recommendations,
242
+ performanceInfluence,
243
+ };
244
+ }
245
+ // =============================================================================
246
+ // REPORT GENERATION
247
+ // =============================================================================
248
+ /**
249
+ * Generate markdown report for attribution analysis.
250
+ */
251
+ export function generateAttributionMarkdown(report) {
252
+ const lines = [];
253
+ lines.push('## Attribution Analysis');
254
+ lines.push('');
255
+ lines.push(`**Model**: ${report.model.replace('_', ' ')}`);
256
+ lines.push('');
257
+ // Insights
258
+ if (report.insights.length > 0) {
259
+ lines.push('### Insights');
260
+ lines.push('');
261
+ for (const insight of report.insights) {
262
+ lines.push(`- ${insight}`);
263
+ }
264
+ lines.push('');
265
+ }
266
+ // Recommendations
267
+ if (report.recommendations.length > 0) {
268
+ lines.push('### Recommendations');
269
+ lines.push('');
270
+ for (const rec of report.recommendations) {
271
+ lines.push(`- ${rec}`);
272
+ }
273
+ lines.push('');
274
+ }
275
+ // Performance influence
276
+ lines.push('### Performance Influence');
277
+ lines.push('');
278
+ lines.push(`| Touchpoint | Correlation |`);
279
+ lines.push(`|------------|-------------|`);
280
+ lines.push(`| First Touch | ${(report.performanceInfluence.firstTouchCorrelation * 100).toFixed(1)}% |`);
281
+ lines.push(`| Last Touch | ${(report.performanceInfluence.lastTouchCorrelation * 100).toFixed(1)}% |`);
282
+ lines.push('');
283
+ lines.push(`**Critical touchpoint**: ${report.performanceInfluence.criticalTouchpoint.replace('_', ' ')}`);
284
+ lines.push('');
285
+ // Attribution table
286
+ lines.push('### Touchpoint Attribution');
287
+ lines.push('');
288
+ lines.push('| Touchpoint | Sessions | First | Last | Linear | Position | LCP |');
289
+ lines.push('|------------|----------|-------|------|--------|----------|-----|');
290
+ for (const tp of report.touchpointStats.slice(0, 10)) {
291
+ const lcp = tp.avgLcp ? `${tp.avgLcp.toFixed(0)}ms` : 'N/A';
292
+ lines.push(`| ${tp.touchpoint} | ${tp.sessions.toLocaleString()} | ${tp.firstTouchConversions} | ${tp.lastTouchConversions} | ${tp.linearConversions.toFixed(1)} | ${tp.positionBasedConversions.toFixed(1)} | ${lcp} |`);
293
+ }
294
+ lines.push('');
295
+ return lines.join('\n');
296
+ }
297
+ // =============================================================================
298
+ // HELPERS
299
+ // =============================================================================
300
+ function average(values) {
301
+ if (values.length === 0)
302
+ return 0;
303
+ return values.reduce((a, b) => a + b, 0) / values.length;
304
+ }
305
+ //# sourceMappingURL=attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/empirical/attribution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Cohort Analysis
3
+ *
4
+ * Track same users over time to understand:
5
+ * - How does performance affect repeat purchases?
6
+ * - Do users with good first-experience return more?
7
+ * - Lifetime value by performance cohort
8
+ *
9
+ * @author Kanmi Obasa <i@kanmiobasa.com>
10
+ */
11
+ import type { SessionData } from './datadog-session-query.js';
12
+ export type CohortType = 'performance' | 'time' | 'acquisition';
13
+ export interface PerformanceCohort {
14
+ /** Cohort identifier */
15
+ cohortId: string;
16
+ /** Cohort description */
17
+ description: string;
18
+ /** Performance range (e.g., 0-2500ms LCP) */
19
+ range: {
20
+ min: number;
21
+ max: number;
22
+ };
23
+ /** Unique users in cohort */
24
+ uniqueUsers: number;
25
+ /** Total sessions */
26
+ totalSessions: number;
27
+ /** Sessions per user */
28
+ avgSessionsPerUser: number;
29
+ /** First-session conversion rate */
30
+ firstSessionCvr: number;
31
+ /** Repeat purchase rate */
32
+ repeatPurchaseRate: number;
33
+ /** Average order value */
34
+ aov: number;
35
+ /** Lifetime value (estimated) */
36
+ ltv: number;
37
+ }
38
+ export interface TimeCohort {
39
+ /** Week identifier (e.g., "2025-W01") */
40
+ weekId: string;
41
+ /** Users acquired this week */
42
+ newUsers: number;
43
+ /** Week 0 conversions (same week) */
44
+ week0Conversions: number;
45
+ /** Week 1 conversions */
46
+ week1Conversions: number;
47
+ /** Week 2 conversions */
48
+ week2Conversions: number;
49
+ /** Week 3+ conversions */
50
+ week3PlusConversions: number;
51
+ /** Total conversions */
52
+ totalConversions: number;
53
+ /** Retention rate */
54
+ retentionRate: number;
55
+ }
56
+ export interface CohortAnalysis {
57
+ type: CohortType;
58
+ performanceCohorts?: PerformanceCohort[];
59
+ timeCohorts?: TimeCohort[];
60
+ insights: string[];
61
+ recommendations: string[];
62
+ }
63
+ /**
64
+ * Analyze users by performance cohort.
65
+ */
66
+ export declare function analyzePerformanceCohorts(sessions: SessionData[], metric?: 'lcp' | 'inp' | 'cls'): CohortAnalysis;
67
+ /**
68
+ * Analyze users by acquisition time cohort.
69
+ */
70
+ export declare function analyzeTimeCohorts(sessions: SessionData[]): CohortAnalysis;
71
+ /**
72
+ * Generate markdown report for cohort analysis.
73
+ */
74
+ export declare function generateCohortMarkdown(analysis: CohortAnalysis): string;
75
+ //# sourceMappingURL=cohort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cohort.d.ts","sourceRoot":"","sources":["../../src/empirical/cohort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAM9D,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,MAAM,GAAG,aAAa,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oCAAoC;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,0BAA0B;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,wBAAwB;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACzC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAMD;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,GAAE,KAAK,GAAG,KAAK,GAAG,KAAa,GACpC,cAAc,CAuHhB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,cAAc,CA4G1E;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAyDvE"}