medusa-stats 1.0.5
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.
- package/.medusa/server/src/admin/composite.png +0 -0
- package/.medusa/server/src/admin/index.js +10512 -0
- package/.medusa/server/src/admin/index.mjs +10510 -0
- package/.medusa/server/src/admin/params.png +0 -0
- package/.medusa/server/src/admin/view.png +0 -0
- package/.medusa/server/src/admin/visualizations.png +0 -0
- package/.medusa/server/src/api/admin/statistics/alert-logs/[id]/route.d.ts +6 -0
- package/.medusa/server/src/api/admin/statistics/alert-logs/[id]/route.js +18 -0
- package/.medusa/server/src/api/admin/statistics/alert-logs/route.d.ts +6 -0
- package/.medusa/server/src/api/admin/statistics/alert-logs/route.js +33 -0
- package/.medusa/server/src/api/admin/statistics/alerts/[id]/logs/route.d.ts +6 -0
- package/.medusa/server/src/api/admin/statistics/alerts/[id]/logs/route.js +23 -0
- package/.medusa/server/src/api/admin/statistics/alerts/[id]/route.d.ts +17 -0
- package/.medusa/server/src/api/admin/statistics/alerts/[id]/route.js +64 -0
- package/.medusa/server/src/api/admin/statistics/alerts/[id]/toggle/route.d.ts +6 -0
- package/.medusa/server/src/api/admin/statistics/alerts/[id]/toggle/route.js +18 -0
- package/.medusa/server/src/api/admin/statistics/alerts/route.d.ts +12 -0
- package/.medusa/server/src/api/admin/statistics/alerts/route.js +94 -0
- package/.medusa/server/src/api/admin/statistics/charts/[id]/route.d.ts +17 -0
- package/.medusa/server/src/api/admin/statistics/charts/[id]/route.js +50 -0
- package/.medusa/server/src/api/admin/statistics/charts/[id]/statistics/route.d.ts +15 -0
- package/.medusa/server/src/api/admin/statistics/charts/[id]/statistics/route.js +40 -0
- package/.medusa/server/src/api/admin/statistics/charts/route.d.ts +4 -0
- package/.medusa/server/src/api/admin/statistics/charts/route.js +55 -0
- package/.medusa/server/src/api/admin/statistics/options/[id]/calculate/route.d.ts +7 -0
- package/.medusa/server/src/api/admin/statistics/options/[id]/calculate/route.js +23 -0
- package/.medusa/server/src/api/admin/statistics/options/[id]/clone/route.d.ts +7 -0
- package/.medusa/server/src/api/admin/statistics/options/[id]/clone/route.js +15 -0
- package/.medusa/server/src/api/admin/statistics/options/[id]/route.d.ts +17 -0
- package/.medusa/server/src/api/admin/statistics/options/[id]/route.js +69 -0
- package/.medusa/server/src/api/admin/statistics/options/route.d.ts +12 -0
- package/.medusa/server/src/api/admin/statistics/options/route.js +87 -0
- package/.medusa/server/src/api/admin/statistics/providers/[id]/route.d.ts +6 -0
- package/.medusa/server/src/api/admin/statistics/providers/[id]/route.js +18 -0
- package/.medusa/server/src/api/admin/statistics/providers/[id]/statistics/route.d.ts +6 -0
- package/.medusa/server/src/api/admin/statistics/providers/[id]/statistics/route.js +18 -0
- package/.medusa/server/src/api/admin/statistics/providers/route.d.ts +7 -0
- package/.medusa/server/src/api/admin/statistics/providers/route.js +57 -0
- package/.medusa/server/src/api/admin/statistics/utils/option-graph.d.ts +3 -0
- package/.medusa/server/src/api/admin/statistics/utils/option-graph.js +34 -0
- package/.medusa/server/src/api/admin/statistics/views/[id]/calculate/route.d.ts +7 -0
- package/.medusa/server/src/api/admin/statistics/views/[id]/calculate/route.js +21 -0
- package/.medusa/server/src/api/admin/statistics/views/[id]/clone/route.d.ts +7 -0
- package/.medusa/server/src/api/admin/statistics/views/[id]/clone/route.js +21 -0
- package/.medusa/server/src/api/admin/statistics/views/[id]/route.d.ts +17 -0
- package/.medusa/server/src/api/admin/statistics/views/[id]/route.js +71 -0
- package/.medusa/server/src/api/admin/statistics/views/route.d.ts +12 -0
- package/.medusa/server/src/api/admin/statistics/views/route.js +74 -0
- package/.medusa/server/src/api/middlewares.d.ts +2 -0
- package/.medusa/server/src/api/middlewares.js +194 -0
- package/.medusa/server/src/api/validation/statistics/schemas.d.ts +1013 -0
- package/.medusa/server/src/api/validation/statistics/schemas.js +288 -0
- package/.medusa/server/src/index.d.ts +1 -0
- package/.medusa/server/src/index.js +18 -0
- package/.medusa/server/src/jobs/evaluate-statistics-alerts.d.ts +6 -0
- package/.medusa/server/src/jobs/evaluate-statistics-alerts.js +110 -0
- package/.medusa/server/src/links/statistics-alert-user.d.ts +2 -0
- package/.medusa/server/src/links/statistics-alert-user.js +16 -0
- package/.medusa/server/src/links/statistics-option-user.d.ts +2 -0
- package/.medusa/server/src/links/statistics-option-user.js +16 -0
- package/.medusa/server/src/loaders/statistics/index.d.ts +5 -0
- package/.medusa/server/src/loaders/statistics/index.js +47 -0
- package/.medusa/server/src/modules/statistics/index.d.ts +107 -0
- package/.medusa/server/src/modules/statistics/index.js +32 -0
- package/.medusa/server/src/modules/statistics/migrations/Migration20260223131741.d.ts +5 -0
- package/.medusa/server/src/modules/statistics/migrations/Migration20260223131741.js +57 -0
- package/.medusa/server/src/modules/statistics/models/alert-log.d.ts +74 -0
- package/.medusa/server/src/modules/statistics/models/alert-log.js +16 -0
- package/.medusa/server/src/modules/statistics/models/alert.d.ts +74 -0
- package/.medusa/server/src/modules/statistics/models/alert.js +24 -0
- package/.medusa/server/src/modules/statistics/models/chart.d.ts +81 -0
- package/.medusa/server/src/modules/statistics/models/chart.js +28 -0
- package/.medusa/server/src/modules/statistics/models/index.d.ts +7 -0
- package/.medusa/server/src/modules/statistics/models/index.js +24 -0
- package/.medusa/server/src/modules/statistics/models/option-input.d.ts +135 -0
- package/.medusa/server/src/modules/statistics/models/option-input.js +27 -0
- package/.medusa/server/src/modules/statistics/models/option.d.ts +78 -0
- package/.medusa/server/src/modules/statistics/models/option.js +41 -0
- package/.medusa/server/src/modules/statistics/models/provider.d.ts +75 -0
- package/.medusa/server/src/modules/statistics/models/provider.js +15 -0
- package/.medusa/server/src/modules/statistics/models/view.d.ts +79 -0
- package/.medusa/server/src/modules/statistics/models/view.js +30 -0
- package/.medusa/server/src/modules/statistics/providers/index.d.ts +1 -0
- package/.medusa/server/src/modules/statistics/providers/index.js +18 -0
- package/.medusa/server/src/modules/statistics/providers/provider.d.ts +254 -0
- package/.medusa/server/src/modules/statistics/providers/provider.js +307 -0
- package/.medusa/server/src/modules/statistics/service.d.ts +953 -0
- package/.medusa/server/src/modules/statistics/service.js +190 -0
- package/.medusa/server/src/modules/statistics/utils/dependency-option-map.d.ts +13 -0
- package/.medusa/server/src/modules/statistics/utils/dependency-option-map.js +67 -0
- package/.medusa/server/src/modules/statistics/utils/period-utils.d.ts +23 -0
- package/.medusa/server/src/modules/statistics/utils/period-utils.js +78 -0
- package/.medusa/server/src/modules/statistics/utils/time-series-utils.d.ts +6 -0
- package/.medusa/server/src/modules/statistics/utils/time-series-utils.js +8 -0
- package/.medusa/server/src/providers/common/index.d.ts +2 -0
- package/.medusa/server/src/providers/common/index.js +1232 -0
- package/.medusa/server/src/providers/composite/index.d.ts +2 -0
- package/.medusa/server/src/providers/composite/index.js +147 -0
- package/.medusa/server/src/workflows/statistics/calculate-single-statistic.d.ts +15 -0
- package/.medusa/server/src/workflows/statistics/calculate-single-statistic.js +28 -0
- package/.medusa/server/src/workflows/statistics/calculate-statistics.d.ts +20 -0
- package/.medusa/server/src/workflows/statistics/calculate-statistics.js +15 -0
- package/.medusa/server/src/workflows/statistics/calculate-view.d.ts +31 -0
- package/.medusa/server/src/workflows/statistics/calculate-view.js +30 -0
- package/.medusa/server/src/workflows/statistics/clone-view.d.ts +227 -0
- package/.medusa/server/src/workflows/statistics/clone-view.js +10 -0
- package/.medusa/server/src/workflows/statistics/create-alert.d.ts +139 -0
- package/.medusa/server/src/workflows/statistics/create-alert.js +12 -0
- package/.medusa/server/src/workflows/statistics/create-chart.d.ts +122 -0
- package/.medusa/server/src/workflows/statistics/create-chart.js +14 -0
- package/.medusa/server/src/workflows/statistics/create-view-with-options.d.ts +1342 -0
- package/.medusa/server/src/workflows/statistics/create-view-with-options.js +29 -0
- package/.medusa/server/src/workflows/statistics/delete-chart.d.ts +10 -0
- package/.medusa/server/src/workflows/statistics/delete-chart.js +14 -0
- package/.medusa/server/src/workflows/statistics/evaluate-alerts.d.ts +28 -0
- package/.medusa/server/src/workflows/statistics/evaluate-alerts.js +67 -0
- package/.medusa/server/src/workflows/statistics/get-available-statistics.d.ts +5 -0
- package/.medusa/server/src/workflows/statistics/get-available-statistics.js +10 -0
- package/.medusa/server/src/workflows/statistics/index.d.ts +14 -0
- package/.medusa/server/src/workflows/statistics/index.js +31 -0
- package/.medusa/server/src/workflows/statistics/manage-chart-statistics.d.ts +12 -0
- package/.medusa/server/src/workflows/statistics/manage-chart-statistics.js +14 -0
- package/.medusa/server/src/workflows/statistics/steps/calculate-statistics.d.ts +37 -0
- package/.medusa/server/src/workflows/statistics/steps/calculate-statistics.js +222 -0
- package/.medusa/server/src/workflows/statistics/steps/clone-view.d.ts +227 -0
- package/.medusa/server/src/workflows/statistics/steps/clone-view.js +39 -0
- package/.medusa/server/src/workflows/statistics/steps/create-alert-log-entries.d.ts +17 -0
- package/.medusa/server/src/workflows/statistics/steps/create-alert-log-entries.js +50 -0
- package/.medusa/server/src/workflows/statistics/steps/create-alert.d.ts +120 -0
- package/.medusa/server/src/workflows/statistics/steps/create-alert.js +21 -0
- package/.medusa/server/src/workflows/statistics/steps/create-chart.d.ts +118 -0
- package/.medusa/server/src/workflows/statistics/steps/create-chart.js +19 -0
- package/.medusa/server/src/workflows/statistics/steps/create-statistics-options.d.ts +117 -0
- package/.medusa/server/src/workflows/statistics/steps/create-statistics-options.js +16 -0
- package/.medusa/server/src/workflows/statistics/steps/create-statistics-view.d.ts +119 -0
- package/.medusa/server/src/workflows/statistics/steps/create-statistics-view.js +16 -0
- package/.medusa/server/src/workflows/statistics/steps/dedupe-alerts.d.ts +22 -0
- package/.medusa/server/src/workflows/statistics/steps/dedupe-alerts.js +64 -0
- package/.medusa/server/src/workflows/statistics/steps/delete-chart.d.ts +6 -0
- package/.medusa/server/src/workflows/statistics/steps/delete-chart.js +17 -0
- package/.medusa/server/src/workflows/statistics/steps/emit-alert-events.d.ts +17 -0
- package/.medusa/server/src/workflows/statistics/steps/emit-alert-events.js +41 -0
- package/.medusa/server/src/workflows/statistics/steps/evaluate-each-condition.d.ts +15 -0
- package/.medusa/server/src/workflows/statistics/steps/evaluate-each-condition.js +109 -0
- package/.medusa/server/src/workflows/statistics/steps/extract-alert-values.d.ts +12 -0
- package/.medusa/server/src/workflows/statistics/steps/extract-alert-values.js +86 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-active-alerts-for-option.d.ts +112 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-active-alerts-for-option.js +16 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-available-statistics.d.ts +4 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-available-statistics.js +39 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-option-with-relations.d.ts +112 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-option-with-relations.js +11 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-view-with-options.d.ts +112 -0
- package/.medusa/server/src/workflows/statistics/steps/fetch-view-with-options.js +20 -0
- package/.medusa/server/src/workflows/statistics/steps/manage-chart-statistics.d.ts +8 -0
- package/.medusa/server/src/workflows/statistics/steps/manage-chart-statistics.js +26 -0
- package/.medusa/server/src/workflows/statistics/steps/update-chart.d.ts +117 -0
- package/.medusa/server/src/workflows/statistics/steps/update-chart.js +32 -0
- package/.medusa/server/src/workflows/statistics/steps/update-view.d.ts +120 -0
- package/.medusa/server/src/workflows/statistics/steps/update-view.js +18 -0
- package/.medusa/server/src/workflows/statistics/steps/validate-alert-input.d.ts +1 -0
- package/.medusa/server/src/workflows/statistics/steps/validate-alert-input.js +34 -0
- package/.medusa/server/src/workflows/statistics/steps/validate-option-parameters.d.ts +21 -0
- package/.medusa/server/src/workflows/statistics/steps/validate-option-parameters.js +43 -0
- package/.medusa/server/src/workflows/statistics/steps/validate-view-input.d.ts +10 -0
- package/.medusa/server/src/workflows/statistics/steps/validate-view-input.js +15 -0
- package/.medusa/server/src/workflows/statistics/update-chart.d.ts +120 -0
- package/.medusa/server/src/workflows/statistics/update-chart.js +13 -0
- package/.medusa/server/src/workflows/statistics/update-view-configuration.d.ts +128 -0
- package/.medusa/server/src/workflows/statistics/update-view-configuration.js +18 -0
- package/.medusa/server/src/workflows/statistics/utils/cache-utils.d.ts +60 -0
- package/.medusa/server/src/workflows/statistics/utils/cache-utils.js +66 -0
- package/.medusa/server/src/workflows/statistics/utils/dependency-graph.d.ts +51 -0
- package/.medusa/server/src/workflows/statistics/utils/dependency-graph.js +131 -0
- package/.medusa/server/src/workflows/statistics/utils/parameter-utils.d.ts +54 -0
- package/.medusa/server/src/workflows/statistics/utils/parameter-utils.js +147 -0
- package/.medusa/server/src/workflows/statistics/validate-option-configuration.d.ts +9 -0
- package/.medusa/server/src/workflows/statistics/validate-option-configuration.js +35 -0
- package/README.md +310 -0
- package/package.json +87 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export type ParameterFieldType = "text" | "number" | "select" | "multiselect" | "boolean" | "date" | "daterange" | "currency" | "json" | "entity" | "entities" | "custom" | "stat";
|
|
3
|
+
export interface EntityReference {
|
|
4
|
+
entity: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ParameterFieldDefinition {
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
schema?: z.ZodType<any>;
|
|
12
|
+
fieldType: ParameterFieldType;
|
|
13
|
+
options?: Array<{
|
|
14
|
+
value: string | number | boolean;
|
|
15
|
+
label: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
}> | ((context: Record<string, any>) => Promise<Array<any>> | Array<any>);
|
|
19
|
+
entityReference?: EntityReference;
|
|
20
|
+
dependsOn?: Array<{
|
|
21
|
+
field: string;
|
|
22
|
+
condition: (value: any, allValues: Record<string, any>) => boolean;
|
|
23
|
+
effect?: "show" | "hide" | "enable" | "disable" | "require";
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
export interface AvailableStatistic {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
parameters: {
|
|
31
|
+
fields: ParameterFieldDefinition[];
|
|
32
|
+
defaults?: Record<string, any>;
|
|
33
|
+
};
|
|
34
|
+
display: {
|
|
35
|
+
visualization?: {
|
|
36
|
+
preferredChartType?: "line" | "bar" | "area" | "pie" | "gauge" | "number" | string;
|
|
37
|
+
xAxisType?: "time" | "category";
|
|
38
|
+
[key: string]: any;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
metadata?: Record<string, any>;
|
|
42
|
+
}
|
|
43
|
+
export interface CalculateStatisticInput {
|
|
44
|
+
id: string;
|
|
45
|
+
parameters: Record<string, any>;
|
|
46
|
+
fields: ParameterFieldDefinition[];
|
|
47
|
+
periodStart: Date;
|
|
48
|
+
periodEnd: Date;
|
|
49
|
+
interval: number;
|
|
50
|
+
metadata?: Record<string, any>;
|
|
51
|
+
}
|
|
52
|
+
export type TimeSeries = Array<{
|
|
53
|
+
x: Date;
|
|
54
|
+
value: any;
|
|
55
|
+
}>;
|
|
56
|
+
export type CategoricalSeries = Array<{
|
|
57
|
+
x: string | number;
|
|
58
|
+
value: any;
|
|
59
|
+
}>;
|
|
60
|
+
export type GaugeValue = {
|
|
61
|
+
value: number;
|
|
62
|
+
};
|
|
63
|
+
export interface StatisticResult {
|
|
64
|
+
value: TimeSeries | CategoricalSeries | GaugeValue | any;
|
|
65
|
+
metadata?: Record<string, any>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Builder class for constructing AvailableStatistic objects with a fluent API.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* const statistic = new StatBuilder("total_revenue", "Total Revenue")
|
|
72
|
+
* .description("Calculate total revenue for the period")
|
|
73
|
+
* .field({
|
|
74
|
+
* name: "currency_code",
|
|
75
|
+
* label: "Currency",
|
|
76
|
+
* fieldType: "select",
|
|
77
|
+
* options: [{ value: "usd", label: "USD" }]
|
|
78
|
+
* })
|
|
79
|
+
* .chart("line")
|
|
80
|
+
* .dimension("time")
|
|
81
|
+
* .build();
|
|
82
|
+
*/
|
|
83
|
+
export declare class StatBuilder {
|
|
84
|
+
private statistic;
|
|
85
|
+
constructor(id: string, name: string);
|
|
86
|
+
/**
|
|
87
|
+
* Set the description for this statistic
|
|
88
|
+
*/
|
|
89
|
+
description(description: string): this;
|
|
90
|
+
/**
|
|
91
|
+
* Add a single parameter field to this statistic
|
|
92
|
+
*/
|
|
93
|
+
field(field: ParameterFieldDefinition, defaultValue?: any): this;
|
|
94
|
+
/**
|
|
95
|
+
* Set the preferred chart type for visualization
|
|
96
|
+
*/
|
|
97
|
+
chart(chartType: "line" | "bar" | "area" | "pie" | "gauge" | "number" | string): this;
|
|
98
|
+
/**
|
|
99
|
+
* Set the X-axis type for time series or categorical data
|
|
100
|
+
*/
|
|
101
|
+
dimension(type: "time" | "category"): this;
|
|
102
|
+
/**
|
|
103
|
+
* Set visualization configuration (merges with existing config)
|
|
104
|
+
*/
|
|
105
|
+
visualization(config: Partial<AvailableStatistic['display']['visualization']>): this;
|
|
106
|
+
/**
|
|
107
|
+
* Set metadata for this statistic
|
|
108
|
+
*/
|
|
109
|
+
metadata(metadata: Record<string, any>): this;
|
|
110
|
+
/**
|
|
111
|
+
* Build and return the final AvailableStatistic object
|
|
112
|
+
*/
|
|
113
|
+
build(): AvailableStatistic;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Helper: Group an array of data by a property or function result
|
|
117
|
+
*
|
|
118
|
+
* @param data - Array of data items to group
|
|
119
|
+
* @param keySelector - Property name or function to extract grouping key
|
|
120
|
+
* @param aggregator - Optional function to aggregate grouped values
|
|
121
|
+
* @returns Map of grouped data
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
*
|
|
125
|
+
* const byDate = groupBy(orders, 'created_at')
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
*
|
|
129
|
+
* const revenueByDay = groupBy(
|
|
130
|
+
* orders,
|
|
131
|
+
* (order) => order.created_at.toISOString().split('T')[0],
|
|
132
|
+
* (items) => items.reduce((sum, item) => sum + item.total, 0)
|
|
133
|
+
* )
|
|
134
|
+
*/
|
|
135
|
+
export declare function groupBy<T, K extends string | number = string>(data: T[], keySelector: keyof T | ((item: T) => K), aggregator?: (items: T[], key: K) => any): Map<K, any>;
|
|
136
|
+
/**
|
|
137
|
+
* Helper: Generate interval timestamps for a period
|
|
138
|
+
*
|
|
139
|
+
* @param periodStart - Start date of the period
|
|
140
|
+
* @param periodEnd - End date of the period
|
|
141
|
+
* @param interval - Interval in seconds (3600 = hourly, 86400 = daily, 604800 = weekly)
|
|
142
|
+
* @returns Array of timestamps at each interval
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* const intervals = generateIntervals(
|
|
146
|
+
* new Date('2024-01-01'),
|
|
147
|
+
* new Date('2024-01-31'),
|
|
148
|
+
* 604800
|
|
149
|
+
* )
|
|
150
|
+
*/
|
|
151
|
+
export declare function generateIntervals(periodStart: Date, periodEnd: Date, interval: number): Date[];
|
|
152
|
+
/**
|
|
153
|
+
* Helper: Get the interval bucket for a given date
|
|
154
|
+
*
|
|
155
|
+
* @param date - Date to bucket
|
|
156
|
+
* @param periodStart - Start of the period
|
|
157
|
+
* @param interval - Interval in seconds
|
|
158
|
+
* @returns The bucket date (start of interval)
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* const bucketDate = getIntervalBucket(
|
|
162
|
+
* new Date('2024-01-05'),
|
|
163
|
+
* new Date('2024-01-01'),
|
|
164
|
+
* 604800
|
|
165
|
+
* )
|
|
166
|
+
*/
|
|
167
|
+
export declare function getIntervalBucket(date: Date, periodStart: Date, interval: number): Date;
|
|
168
|
+
/**
|
|
169
|
+
* Creates a time series by efficiently mapping data to time intervals.
|
|
170
|
+
* Generates intervals internally and processes data in a single pass.
|
|
171
|
+
*
|
|
172
|
+
* @param data - Array of data items to aggregate
|
|
173
|
+
* @param periodStart - Start of the time period
|
|
174
|
+
* @param periodEnd - End of the time period
|
|
175
|
+
* @param intervalSeconds - Duration of each interval in seconds
|
|
176
|
+
* @param accumulator - Function to aggregate items within each interval
|
|
177
|
+
* @param options - Optional configuration
|
|
178
|
+
* @param options.timestampField - Field name or function to extract timestamp (defaults to 'created_at')
|
|
179
|
+
* @returns Array of time series points with x (Date) and value (number)
|
|
180
|
+
*/
|
|
181
|
+
export declare function createTimeSeries<T extends Record<string, any>>(data: T[], periodStart: Date, periodEnd: Date, intervalSeconds: number, accumulator: (items: T[]) => number, options?: {
|
|
182
|
+
timestampField?: string | ((item: T) => number);
|
|
183
|
+
}): Array<{
|
|
184
|
+
x: Date;
|
|
185
|
+
value: number;
|
|
186
|
+
}>;
|
|
187
|
+
/**
|
|
188
|
+
* Creates a count accumulator that returns the number of items.
|
|
189
|
+
*
|
|
190
|
+
* @returns Accumulator function that counts items
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* createTimeSeries(orders, start, end, interval, count())
|
|
194
|
+
*/
|
|
195
|
+
export declare function count<T>(): (items: T[]) => number;
|
|
196
|
+
/**
|
|
197
|
+
* Creates a sum accumulator that sums values of a specific field.
|
|
198
|
+
*
|
|
199
|
+
* @param field - Name of the field to sum
|
|
200
|
+
* @returns Accumulator function that sums field values
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* createTimeSeries(orders, start, end, interval, sum('total'))
|
|
204
|
+
*/
|
|
205
|
+
export declare function sum<T extends Record<string, any>>(field: string): (items: T[]) => number;
|
|
206
|
+
/**
|
|
207
|
+
* Creates an average accumulator that calculates mean of a specific field.
|
|
208
|
+
* Optionally excludes outliers using IQR method (requires at least 3 data points).
|
|
209
|
+
*
|
|
210
|
+
* @param field - Name of the field to average
|
|
211
|
+
* @param options - Optional configuration
|
|
212
|
+
* @param options.excludeOutliers - If true, excludes outliers using IQR method
|
|
213
|
+
* @returns Accumulator function that calculates average
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* createTimeSeries(orders, start, end, interval, average('total'))
|
|
217
|
+
* createTimeSeries(orders, start, end, interval, average('total', { excludeOutliers: true }))
|
|
218
|
+
*/
|
|
219
|
+
export declare function average<T extends Record<string, any>>(field: string, options?: {
|
|
220
|
+
excludeOutliers?: boolean;
|
|
221
|
+
}): (items: T[]) => number;
|
|
222
|
+
/**
|
|
223
|
+
* Abstract provider for calculating statistics.
|
|
224
|
+
* Extend this class to implement custom statistics providers.
|
|
225
|
+
*/
|
|
226
|
+
export declare abstract class AbstractStatisticsProvider {
|
|
227
|
+
protected readonly container: any;
|
|
228
|
+
static identifier: string;
|
|
229
|
+
static displayName: string;
|
|
230
|
+
protected query: any;
|
|
231
|
+
constructor(container: any);
|
|
232
|
+
/**
|
|
233
|
+
* Get available statistics for a given sales channel.
|
|
234
|
+
*
|
|
235
|
+
* @param input - Input parameters
|
|
236
|
+
* @param input.sales_channel_id - Optional sales channel ID to filter statistics
|
|
237
|
+
* @returns Array of available statistics with their configuration
|
|
238
|
+
*/
|
|
239
|
+
abstract getAvailableStatistics(): Promise<AvailableStatistic[]> | AvailableStatistic[];
|
|
240
|
+
/**
|
|
241
|
+
* Calculate a specific statistic for a given period.
|
|
242
|
+
*
|
|
243
|
+
* @param input - Input parameters
|
|
244
|
+
* @param input.id - The statistic ID to calculate
|
|
245
|
+
* @param input.parameters - Validated and merged parameter values
|
|
246
|
+
* @param input.fields - Field definitions for reference
|
|
247
|
+
* @param input.periodStart - Start date of the period
|
|
248
|
+
* @param input.periodEnd - End date of the period
|
|
249
|
+
* @param input.interval - Interval in seconds (3600 = hourly, 86400 = daily, 604800 = weekly)
|
|
250
|
+
* @param input.metadata - Additional calculation metadata
|
|
251
|
+
* @returns The calculated statistic with rendering configuration
|
|
252
|
+
*/
|
|
253
|
+
abstract calculateStatistic(input: CalculateStatisticInput): Promise<StatisticResult> | StatisticResult;
|
|
254
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AbstractStatisticsProvider = exports.StatBuilder = void 0;
|
|
4
|
+
exports.groupBy = groupBy;
|
|
5
|
+
exports.generateIntervals = generateIntervals;
|
|
6
|
+
exports.getIntervalBucket = getIntervalBucket;
|
|
7
|
+
exports.createTimeSeries = createTimeSeries;
|
|
8
|
+
exports.count = count;
|
|
9
|
+
exports.sum = sum;
|
|
10
|
+
exports.average = average;
|
|
11
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
12
|
+
/**
|
|
13
|
+
* Builder class for constructing AvailableStatistic objects with a fluent API.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const statistic = new StatBuilder("total_revenue", "Total Revenue")
|
|
17
|
+
* .description("Calculate total revenue for the period")
|
|
18
|
+
* .field({
|
|
19
|
+
* name: "currency_code",
|
|
20
|
+
* label: "Currency",
|
|
21
|
+
* fieldType: "select",
|
|
22
|
+
* options: [{ value: "usd", label: "USD" }]
|
|
23
|
+
* })
|
|
24
|
+
* .chart("line")
|
|
25
|
+
* .dimension("time")
|
|
26
|
+
* .build();
|
|
27
|
+
*/
|
|
28
|
+
class StatBuilder {
|
|
29
|
+
constructor(id, name) {
|
|
30
|
+
this.statistic = {
|
|
31
|
+
id,
|
|
32
|
+
name,
|
|
33
|
+
parameters: {
|
|
34
|
+
fields: []
|
|
35
|
+
},
|
|
36
|
+
display: {}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Set the description for this statistic
|
|
41
|
+
*/
|
|
42
|
+
description(description) {
|
|
43
|
+
this.statistic.description = description;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Add a single parameter field to this statistic
|
|
48
|
+
*/
|
|
49
|
+
field(field, defaultValue) {
|
|
50
|
+
this.statistic.parameters.fields.push(field);
|
|
51
|
+
if (defaultValue !== undefined) {
|
|
52
|
+
if (!this.statistic.parameters.defaults) {
|
|
53
|
+
this.statistic.parameters.defaults = {};
|
|
54
|
+
}
|
|
55
|
+
this.statistic.parameters.defaults[field.name] = defaultValue;
|
|
56
|
+
}
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Set the preferred chart type for visualization
|
|
61
|
+
*/
|
|
62
|
+
chart(chartType) {
|
|
63
|
+
if (!this.statistic.display.visualization) {
|
|
64
|
+
this.statistic.display.visualization = {};
|
|
65
|
+
}
|
|
66
|
+
this.statistic.display.visualization.preferredChartType = chartType;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Set the X-axis type for time series or categorical data
|
|
71
|
+
*/
|
|
72
|
+
dimension(type) {
|
|
73
|
+
if (!this.statistic.display.visualization) {
|
|
74
|
+
this.statistic.display.visualization = {};
|
|
75
|
+
}
|
|
76
|
+
this.statistic.display.visualization.xAxisType = type;
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Set visualization configuration (merges with existing config)
|
|
81
|
+
*/
|
|
82
|
+
visualization(config) {
|
|
83
|
+
this.statistic.display.visualization = {
|
|
84
|
+
...this.statistic.display.visualization,
|
|
85
|
+
...config
|
|
86
|
+
};
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Set metadata for this statistic
|
|
91
|
+
*/
|
|
92
|
+
metadata(metadata) {
|
|
93
|
+
this.statistic.metadata = metadata;
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build and return the final AvailableStatistic object
|
|
98
|
+
*/
|
|
99
|
+
build() {
|
|
100
|
+
if (!this.statistic.id || !this.statistic.name) {
|
|
101
|
+
throw new Error("AvailableStatistic requires 'id' and 'name'");
|
|
102
|
+
}
|
|
103
|
+
return { ...this.statistic };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.StatBuilder = StatBuilder;
|
|
107
|
+
/**
|
|
108
|
+
* Helper: Group an array of data by a property or function result
|
|
109
|
+
*
|
|
110
|
+
* @param data - Array of data items to group
|
|
111
|
+
* @param keySelector - Property name or function to extract grouping key
|
|
112
|
+
* @param aggregator - Optional function to aggregate grouped values
|
|
113
|
+
* @returns Map of grouped data
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
*
|
|
117
|
+
* const byDate = groupBy(orders, 'created_at')
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
*
|
|
121
|
+
* const revenueByDay = groupBy(
|
|
122
|
+
* orders,
|
|
123
|
+
* (order) => order.created_at.toISOString().split('T')[0],
|
|
124
|
+
* (items) => items.reduce((sum, item) => sum + item.total, 0)
|
|
125
|
+
* )
|
|
126
|
+
*/
|
|
127
|
+
function groupBy(data, keySelector, aggregator) {
|
|
128
|
+
const groups = new Map();
|
|
129
|
+
for (const item of data) {
|
|
130
|
+
const key = typeof keySelector === 'function'
|
|
131
|
+
? keySelector(item)
|
|
132
|
+
: item[keySelector];
|
|
133
|
+
if (!groups.has(key)) {
|
|
134
|
+
groups.set(key, []);
|
|
135
|
+
}
|
|
136
|
+
groups.get(key).push(item);
|
|
137
|
+
}
|
|
138
|
+
if (aggregator) {
|
|
139
|
+
const result = new Map();
|
|
140
|
+
for (const [key, items] of groups.entries()) {
|
|
141
|
+
result.set(key, aggregator(items, key));
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
return groups;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Helper: Generate interval timestamps for a period
|
|
149
|
+
*
|
|
150
|
+
* @param periodStart - Start date of the period
|
|
151
|
+
* @param periodEnd - End date of the period
|
|
152
|
+
* @param interval - Interval in seconds (3600 = hourly, 86400 = daily, 604800 = weekly)
|
|
153
|
+
* @returns Array of timestamps at each interval
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* const intervals = generateIntervals(
|
|
157
|
+
* new Date('2024-01-01'),
|
|
158
|
+
* new Date('2024-01-31'),
|
|
159
|
+
* 604800
|
|
160
|
+
* )
|
|
161
|
+
*/
|
|
162
|
+
function generateIntervals(periodStart, periodEnd, interval) {
|
|
163
|
+
const intervals = [];
|
|
164
|
+
const current = new Date(periodStart);
|
|
165
|
+
const end = new Date(periodEnd);
|
|
166
|
+
const intervalMs = interval * 1000;
|
|
167
|
+
while (current <= end) {
|
|
168
|
+
intervals.push(new Date(current));
|
|
169
|
+
current.setTime(current.getTime() + intervalMs);
|
|
170
|
+
}
|
|
171
|
+
return intervals;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Helper: Get the interval bucket for a given date
|
|
175
|
+
*
|
|
176
|
+
* @param date - Date to bucket
|
|
177
|
+
* @param periodStart - Start of the period
|
|
178
|
+
* @param interval - Interval in seconds
|
|
179
|
+
* @returns The bucket date (start of interval)
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* const bucketDate = getIntervalBucket(
|
|
183
|
+
* new Date('2024-01-05'),
|
|
184
|
+
* new Date('2024-01-01'),
|
|
185
|
+
* 604800
|
|
186
|
+
* )
|
|
187
|
+
*/
|
|
188
|
+
function getIntervalBucket(date, periodStart, interval) {
|
|
189
|
+
const msSinceStart = date.getTime() - periodStart.getTime();
|
|
190
|
+
const secondsSinceStart = Math.floor(msSinceStart / 1000);
|
|
191
|
+
const bucketIndex = Math.floor(secondsSinceStart / interval);
|
|
192
|
+
const bucketDate = new Date(periodStart);
|
|
193
|
+
bucketDate.setTime(bucketDate.getTime() + bucketIndex * interval * 1000);
|
|
194
|
+
return bucketDate;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Creates a time series by efficiently mapping data to time intervals.
|
|
198
|
+
* Generates intervals internally and processes data in a single pass.
|
|
199
|
+
*
|
|
200
|
+
* @param data - Array of data items to aggregate
|
|
201
|
+
* @param periodStart - Start of the time period
|
|
202
|
+
* @param periodEnd - End of the time period
|
|
203
|
+
* @param intervalSeconds - Duration of each interval in seconds
|
|
204
|
+
* @param accumulator - Function to aggregate items within each interval
|
|
205
|
+
* @param options - Optional configuration
|
|
206
|
+
* @param options.timestampField - Field name or function to extract timestamp (defaults to 'created_at')
|
|
207
|
+
* @returns Array of time series points with x (Date) and value (number)
|
|
208
|
+
*/
|
|
209
|
+
function createTimeSeries(data, periodStart, periodEnd, intervalSeconds, accumulator, options = {}) {
|
|
210
|
+
let getTimestamp;
|
|
211
|
+
if (typeof options.timestampField === 'function') {
|
|
212
|
+
getTimestamp = options.timestampField;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const field = options.timestampField || 'created_at';
|
|
216
|
+
getTimestamp = (item) => new Date(item[field]).getTime();
|
|
217
|
+
}
|
|
218
|
+
const sorted = [...data]
|
|
219
|
+
.map(item => ({ item, timestamp: getTimestamp(item) }))
|
|
220
|
+
.sort((a, b) => a.timestamp - b.timestamp);
|
|
221
|
+
const result = [];
|
|
222
|
+
const startMs = periodStart.getTime();
|
|
223
|
+
const endMs = periodEnd.getTime();
|
|
224
|
+
const intervalMs = intervalSeconds * 1000;
|
|
225
|
+
let dataIdx = 0;
|
|
226
|
+
for (let currentMs = startMs; currentMs < endMs; currentMs += intervalMs) {
|
|
227
|
+
const nextMs = Math.min(currentMs + intervalMs, endMs);
|
|
228
|
+
const itemsInInterval = [];
|
|
229
|
+
const startIdx = dataIdx;
|
|
230
|
+
while (dataIdx < sorted.length && sorted[dataIdx].timestamp < nextMs) {
|
|
231
|
+
if (sorted[dataIdx].timestamp >= currentMs) {
|
|
232
|
+
itemsInInterval.push(sorted[dataIdx].item);
|
|
233
|
+
}
|
|
234
|
+
dataIdx++;
|
|
235
|
+
}
|
|
236
|
+
dataIdx = startIdx;
|
|
237
|
+
result.push({
|
|
238
|
+
x: new Date(currentMs),
|
|
239
|
+
value: accumulator(itemsInInterval)
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Creates a count accumulator that returns the number of items.
|
|
246
|
+
*
|
|
247
|
+
* @returns Accumulator function that counts items
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* createTimeSeries(orders, start, end, interval, count())
|
|
251
|
+
*/
|
|
252
|
+
function count() {
|
|
253
|
+
return (items) => items.length;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Creates a sum accumulator that sums values of a specific field.
|
|
257
|
+
*
|
|
258
|
+
* @param field - Name of the field to sum
|
|
259
|
+
* @returns Accumulator function that sums field values
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* createTimeSeries(orders, start, end, interval, sum('total'))
|
|
263
|
+
*/
|
|
264
|
+
function sum(field) {
|
|
265
|
+
return (items) => items.reduce((sum, item) => sum + (Number(item[field]) || 0), 0);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Creates an average accumulator that calculates mean of a specific field.
|
|
269
|
+
* Optionally excludes outliers using IQR method (requires at least 3 data points).
|
|
270
|
+
*
|
|
271
|
+
* @param field - Name of the field to average
|
|
272
|
+
* @param options - Optional configuration
|
|
273
|
+
* @param options.excludeOutliers - If true, excludes outliers using IQR method
|
|
274
|
+
* @returns Accumulator function that calculates average
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* createTimeSeries(orders, start, end, interval, average('total'))
|
|
278
|
+
* createTimeSeries(orders, start, end, interval, average('total', { excludeOutliers: true }))
|
|
279
|
+
*/
|
|
280
|
+
function average(field, options = {}) {
|
|
281
|
+
return (items) => {
|
|
282
|
+
if (items.length === 0)
|
|
283
|
+
return 0;
|
|
284
|
+
const values = items.map(item => Number(item[field]) || 0);
|
|
285
|
+
if (options.excludeOutliers && values.length > 2) {
|
|
286
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
287
|
+
const q1 = sorted[Math.floor(sorted.length * 0.25)];
|
|
288
|
+
const q3 = sorted[Math.floor(sorted.length * 0.75)];
|
|
289
|
+
const iqr = q3 - q1;
|
|
290
|
+
const filtered = values.filter(v => v >= q1 - 1.5 * iqr && v <= q3 + 1.5 * iqr);
|
|
291
|
+
return filtered.reduce((sum, v) => sum + v, 0) / filtered.length;
|
|
292
|
+
}
|
|
293
|
+
return values.reduce((sum, v) => sum + v, 0) / values.length;
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Abstract provider for calculating statistics.
|
|
298
|
+
* Extend this class to implement custom statistics providers.
|
|
299
|
+
*/
|
|
300
|
+
class AbstractStatisticsProvider {
|
|
301
|
+
constructor(container) {
|
|
302
|
+
this.container = container;
|
|
303
|
+
this.query = container[utils_1.ContainerRegistrationKeys.QUERY];
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
exports.AbstractStatisticsProvider = AbstractStatisticsProvider;
|
|
307
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9zdGF0aXN0aWNzL3Byb3ZpZGVycy9wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFrT0EsMEJBNkJDO0FBaUJELDhDQWdCQztBQWlCRCw4Q0FXQztBQWVELDRDQWtEQztBQVVELHNCQUVDO0FBV0Qsa0JBRUM7QUFlRCwwQkFvQkM7QUF4YkQscURBQXNFO0FBZ0d0RTs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxNQUFhLFdBQVc7SUFHcEIsWUFBWSxFQUFVLEVBQUUsSUFBWTtRQUNoQyxJQUFJLENBQUMsU0FBUyxHQUFHO1lBQ2IsRUFBRTtZQUNGLElBQUk7WUFDSixVQUFVLEVBQUU7Z0JBQ1IsTUFBTSxFQUFFLEVBQUU7YUFDYjtZQUNELE9BQU8sRUFBRSxFQUFFO1NBQ2QsQ0FBQztJQUNOLENBQUM7SUFFRDs7T0FFRztJQUNILFdBQVcsQ0FBQyxXQUFtQjtRQUMzQixJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDekMsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLEtBQStCLEVBQUUsWUFBa0I7UUFDckQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUU3QyxJQUFJLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM3QixJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ3RDLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLFFBQVEsR0FBRyxFQUFFLENBQUM7WUFDNUMsQ0FBQztZQUNELElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsWUFBWSxDQUFDO1FBQ2xFLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0lBR0Q7O09BRUc7SUFDSCxLQUFLLENBQUMsU0FBd0U7UUFDMUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3hDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGFBQWEsR0FBRyxFQUFFLENBQUM7UUFDOUMsQ0FBQztRQUNELElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxrQkFBa0IsR0FBRyxTQUFTLENBQUM7UUFDcEUsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsU0FBUyxDQUFDLElBQXlCO1FBQy9CLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN4QyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEdBQUcsRUFBRSxDQUFDO1FBQzlDLENBQUM7UUFDRCxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztRQUN0RCxPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhLENBQUMsTUFBK0Q7UUFDekUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsYUFBYSxHQUFHO1lBQ25DLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsYUFBYTtZQUN2QyxHQUFHLE1BQU07U0FDWixDQUFDO1FBQ0YsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsUUFBUSxDQUFDLFFBQTZCO1FBQ2xDLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUNuQyxPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBRUQsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUM3QyxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7UUFDbkUsQ0FBQztRQUVELE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0NBQ0o7QUEzRkQsa0NBMkZDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFDSCxTQUFnQixPQUFPLENBQ25CLElBQVMsRUFDVCxXQUF1QyxFQUN2QyxVQUF3QztJQUV4QyxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0lBR2pDLEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUM7UUFDdEIsTUFBTSxHQUFHLEdBQUcsT0FBTyxXQUFXLEtBQUssVUFBVTtZQUN6QyxDQUFDLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQztZQUNuQixDQUFDLENBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBa0IsQ0FBQztRQUUxQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ25CLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3hCLENBQUM7UUFDRCxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBR0QsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNiLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDakMsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQzFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDbEIsQ0FBQztJQUVELE9BQU8sTUFBcUIsQ0FBQztBQUNqQyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxTQUFnQixpQkFBaUIsQ0FDN0IsV0FBaUIsRUFDakIsU0FBZSxFQUNmLFFBQWdCO0lBRWhCLE1BQU0sU0FBUyxHQUFXLEVBQUUsQ0FBQztJQUM3QixNQUFNLE9BQU8sR0FBRyxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN0QyxNQUFNLEdBQUcsR0FBRyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNoQyxNQUFNLFVBQVUsR0FBRyxRQUFRLEdBQUcsSUFBSSxDQUFDO0lBRW5DLE9BQU8sT0FBTyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUNsQyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsR0FBRyxVQUFVLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQsT0FBTyxTQUFTLENBQUM7QUFDckIsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQzdCLElBQVUsRUFDVixXQUFpQixFQUNqQixRQUFnQjtJQUVoQixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLEdBQUcsV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzVELE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDMUQsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsR0FBRyxRQUFRLENBQUMsQ0FBQztJQUM3RCxNQUFNLFVBQVUsR0FBRyxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN6QyxVQUFVLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxXQUFXLEdBQUcsUUFBUSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ3pFLE9BQU8sVUFBVSxDQUFDO0FBQ3RCLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FDNUIsSUFBUyxFQUNULFdBQWlCLEVBQ2pCLFNBQWUsRUFDZixlQUF1QixFQUN2QixXQUFtQyxFQUNuQyxVQUVJLEVBQUU7SUFFTixJQUFJLFlBQWlDLENBQUM7SUFDdEMsSUFBSSxPQUFPLE9BQU8sQ0FBQyxjQUFjLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDL0MsWUFBWSxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUM7SUFDMUMsQ0FBQztTQUFNLENBQUM7UUFDSixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsY0FBYyxJQUFJLFlBQVksQ0FBQztRQUNyRCxZQUFZLEdBQUcsQ0FBQyxJQUFPLEVBQUUsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2hFLENBQUM7SUFHRCxNQUFNLE1BQU0sR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO1NBQ25CLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7U0FDdEQsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUM7SUFHL0MsTUFBTSxNQUFNLEdBQXNDLEVBQUUsQ0FBQztJQUNyRCxNQUFNLE9BQU8sR0FBRyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDdEMsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2xDLE1BQU0sVUFBVSxHQUFHLGVBQWUsR0FBRyxJQUFJLENBQUM7SUFFMUMsSUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBQ2hCLEtBQUssSUFBSSxTQUFTLEdBQUcsT0FBTyxFQUFFLFNBQVMsR0FBRyxLQUFLLEVBQUUsU0FBUyxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQ3ZFLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxHQUFHLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN2RCxNQUFNLGVBQWUsR0FBUSxFQUFFLENBQUM7UUFFaEMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDO1FBQ3pCLE9BQU8sT0FBTyxHQUFHLE1BQU0sQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLFNBQVMsR0FBRyxNQUFNLEVBQUUsQ0FBQztZQUNuRSxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxTQUFTLElBQUksU0FBUyxFQUFFLENBQUM7Z0JBQ3pDLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQy9DLENBQUM7WUFDRCxPQUFPLEVBQUUsQ0FBQztRQUNkLENBQUM7UUFDRCxPQUFPLEdBQUcsUUFBUSxDQUFDO1FBRW5CLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFDUixDQUFDLEVBQUUsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQ3RCLEtBQUssRUFBRSxXQUFXLENBQUMsZUFBZSxDQUFDO1NBQ3RDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQztBQUNsQixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQWdCLEtBQUs7SUFDakIsT0FBTyxDQUFDLEtBQVUsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztBQUN4QyxDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFnQixHQUFHLENBQWdDLEtBQWE7SUFDNUQsT0FBTyxDQUFDLEtBQVUsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUM1RixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsU0FBZ0IsT0FBTyxDQUNuQixLQUFhLEVBQ2IsVUFBeUMsRUFBRTtJQUUzQyxPQUFPLENBQUMsS0FBVSxFQUFFLEVBQUU7UUFDbEIsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7WUFBRSxPQUFPLENBQUMsQ0FBQztRQUVqQyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBRTNELElBQUksT0FBTyxDQUFDLGVBQWUsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQy9DLE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDakQsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3BELE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUNwRCxNQUFNLEdBQUcsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDO1lBQ3BCLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxHQUFHLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDaEYsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDO1FBQ3JFLENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDakUsQ0FBQyxDQUFDO0FBQ04sQ0FBQztBQUdEOzs7R0FHRztBQUNILE1BQXNCLDBCQUEwQjtJQUs1QyxZQUErQixTQUFjO1FBQWQsY0FBUyxHQUFULFNBQVMsQ0FBSztRQUV6QyxJQUFJLENBQUMsS0FBSyxHQUFHLFNBQVMsQ0FBQyxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM1RCxDQUFDO0NBMkJKO0FBbkNELGdFQW1DQyJ9
|