@stigg/node-server-sdk 3.36.0 → 3.37.1
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.
|
@@ -8,6 +8,7 @@ declare type EdgeApiClientConfiguration = {
|
|
|
8
8
|
enableEdge: boolean;
|
|
9
9
|
};
|
|
10
10
|
export declare class EdgeApiClient {
|
|
11
|
+
private readonly loggerService;
|
|
11
12
|
private readonly httpClient;
|
|
12
13
|
private constructor();
|
|
13
14
|
static create(config: EdgeApiClientConfiguration, loggerService: LoggerService): EdgeApiClient | null;
|
|
@@ -21,5 +22,6 @@ export declare class EdgeApiClient {
|
|
|
21
22
|
* Public for mocking in tests
|
|
22
23
|
*/
|
|
23
24
|
enableRetries(axiosInstance: AxiosInstance): void;
|
|
25
|
+
private canRetryRequest;
|
|
24
26
|
}
|
|
25
27
|
export {};
|
|
@@ -30,12 +30,13 @@ const axios_retry_1 = __importDefault(require("axios-retry"));
|
|
|
30
30
|
const http = __importStar(require("http"));
|
|
31
31
|
const https = __importStar(require("https"));
|
|
32
32
|
const lodash_1 = require("lodash");
|
|
33
|
-
const REQUEST_TIMEOUT_MS =
|
|
33
|
+
const REQUEST_TIMEOUT_MS = 15 * 1000; // 15 seconds
|
|
34
34
|
const REQUEST_RETRY_COUNT = 3;
|
|
35
35
|
class EdgeApiClient {
|
|
36
36
|
constructor(config, loggerService) {
|
|
37
|
+
this.loggerService = loggerService;
|
|
37
38
|
const { apiKey, baseEdgeUri } = config;
|
|
38
|
-
this.httpClient = this.initHttpClient(baseEdgeUri, apiKey
|
|
39
|
+
this.httpClient = this.initHttpClient(baseEdgeUri, apiKey);
|
|
39
40
|
}
|
|
40
41
|
static create(config, loggerService) {
|
|
41
42
|
return config.enableEdge ? new EdgeApiClient(config, loggerService) : null;
|
|
@@ -78,10 +79,10 @@ class EdgeApiClient {
|
|
|
78
79
|
}
|
|
79
80
|
return data;
|
|
80
81
|
}
|
|
81
|
-
initHttpClient(baseEdgeUri, apiKey
|
|
82
|
+
initHttpClient(baseEdgeUri, apiKey) {
|
|
82
83
|
const axiosInstance = axios_1.default.create({
|
|
83
84
|
baseURL: baseEdgeUri,
|
|
84
|
-
headers: Object.assign(Object.assign({}, (0, requestHeaders_1.buildRequestHeaders)(apiKey, loggerService.getInstanceId())), { 'X-API-VERSION': '1' }),
|
|
85
|
+
headers: Object.assign(Object.assign({}, (0, requestHeaders_1.buildRequestHeaders)(apiKey, this.loggerService.getInstanceId())), { 'X-API-VERSION': '1' }),
|
|
85
86
|
timeout: REQUEST_TIMEOUT_MS,
|
|
86
87
|
httpAgent: new http.Agent({ keepAlive: true }),
|
|
87
88
|
httpsAgent: new https.Agent({ keepAlive: true }),
|
|
@@ -95,10 +96,16 @@ class EdgeApiClient {
|
|
|
95
96
|
enableRetries(axiosInstance) {
|
|
96
97
|
(0, axios_retry_1.default)(axiosInstance, {
|
|
97
98
|
retries: REQUEST_RETRY_COUNT,
|
|
99
|
+
retryCondition: (error) => this.canRetryRequest(error),
|
|
98
100
|
retryDelay: (retryNumber, error) => axios_retry_1.default.exponentialDelay(retryNumber, error, 2000),
|
|
99
101
|
shouldResetTimeout: true,
|
|
102
|
+
onRetry: async (retryCount, error, requestConfig) => this.loggerService.log(`Retrying request ${requestConfig.url} - attempt ${retryCount}`),
|
|
100
103
|
});
|
|
101
104
|
}
|
|
105
|
+
canRetryRequest(error) {
|
|
106
|
+
const isTimeoutError = error.code === 'ECONNABORTED' && error.message.includes('timeout');
|
|
107
|
+
return isTimeoutError || axios_retry_1.default.isNetworkOrIdempotentRequestError(error);
|
|
108
|
+
}
|
|
102
109
|
}
|
|
103
110
|
exports.EdgeApiClient = EdgeApiClient;
|
|
104
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
111
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRWRnZUFwaUNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9FZGdlQXBpQ2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxrREFBZ0U7QUFDaEUsOENBQXFFO0FBUXJFLDREQUE4RDtBQUU5RCw4REFBcUM7QUFDckMsMkNBQTZCO0FBQzdCLDZDQUErQjtBQUMvQixtQ0FBb0Q7QUFFcEQsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsYUFBYTtBQUVuRCxNQUFNLG1CQUFtQixHQUFHLENBQUMsQ0FBQztBQVE5QixNQUFhLGFBQWE7SUFHeEIsWUFBb0IsTUFBa0MsRUFBbUIsYUFBNEI7UUFBNUIsa0JBQWEsR0FBYixhQUFhLENBQWU7UUFDbkcsTUFBTSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsR0FBRyxNQUFNLENBQUM7UUFDdkMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFdBQVcsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFrQyxFQUFFLGFBQTRCO1FBQzVFLE9BQU8sTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSxhQUFhLENBQUMsTUFBTSxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDN0UsQ0FBQztJQUVELFVBQVUsQ0FDUixTQUFrQixFQUNsQixrQkFBMkIsRUFDM0IsdUJBQWlDLEVBQ2pDLGtCQUE0QjtRQUU1QixNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLE1BQU0sU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNsRCxNQUFNLGlDQUFpQyxHQUFHLDJCQUEyQix1QkFBdUIsRUFBRSxDQUFDO1FBRS9GLElBQUksR0FBRyxHQUFHLE1B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
|
|
@@ -12,16 +12,19 @@ export declare class RedisCacheService implements CacheService {
|
|
|
12
12
|
private readonly redlock;
|
|
13
13
|
readonly distributedRefetchEntitlementsService: RedisSingleExecutionService | undefined;
|
|
14
14
|
constructor(options: StiggRedisOptions, loggerService: LoggerService);
|
|
15
|
-
updateFeatureUsage(
|
|
15
|
+
updateFeatureUsage(params: UpdateFeatureUsagePayload): Promise<boolean>;
|
|
16
|
+
private getFeatureUsageItemToUpdate;
|
|
16
17
|
setCustomer(customerId: string, customerEntitlements: Map<string, CachedEntitlement>, resourceId: string | undefined, entitlementsTimestamp: number, featureIdToUsageTimestamp: Map<string, number>): Promise<void>;
|
|
18
|
+
private extractFeatureUsagesToUpdate;
|
|
17
19
|
getCustomerEntitlementsWithoutUsage(customerId: string, resourceId: string | undefined): Promise<EntitlementsResponse>;
|
|
18
20
|
private isGlobalCustomerMissingInCache;
|
|
19
21
|
getCustomerEntitlements(customerId: string, resourceId: string | undefined): Promise<EntitlementsResponse>;
|
|
20
22
|
private getFeaturesUsage;
|
|
21
23
|
clearCache(): void | Promise<void>;
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
+
private updateCacheItems;
|
|
25
|
+
private getKeysLatestTimestamp;
|
|
24
26
|
private parseTimestamp;
|
|
25
27
|
cleanup(): Promise<void>;
|
|
26
28
|
getCustomerEntitlement(featureId: string, customerId: string, resourceId: string | undefined): Promise<EntitlementResponse>;
|
|
29
|
+
private mergeEntitlementWithUsage;
|
|
27
30
|
}
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.RedisCacheService = void 0;
|
|
7
7
|
const ioredis_1 = __importDefault(require("ioredis"));
|
|
8
8
|
const lodash_1 = require("lodash");
|
|
9
|
-
const sdk_1 = require("@stigg/api-client-js/src/generated/sdk");
|
|
10
9
|
const redlock_1 = __importDefault(require("redlock"));
|
|
11
10
|
const cacheKeysHelpers_1 = require("../../utils/cacheKeysHelpers");
|
|
12
11
|
const RedisSingleExecutionService_1 = require("./RedisSingleExecutionService");
|
|
@@ -29,74 +28,72 @@ class RedisCacheService {
|
|
|
29
28
|
this.distributedRefetchEntitlementsService = new RedisSingleExecutionService_1.RedisSingleExecutionService(redisCacheService_constants_1.REFETCH_OPERATION_NAME, this.environmentPrefix, notificationTimeoutMs, this.redisClient, this.redlock, this.loggerService);
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
|
-
async updateFeatureUsage(
|
|
33
|
-
const
|
|
34
|
-
|
|
31
|
+
async updateFeatureUsage(params) {
|
|
32
|
+
const item = this.getFeatureUsageItemToUpdate(params);
|
|
33
|
+
await this.updateCacheItems([item]);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
getFeatureUsageItemToUpdate({ featureId, currentUsage, customerId, nextResetDate, resourceId, timestamp, }) {
|
|
37
|
+
const value = {
|
|
35
38
|
currentUsage,
|
|
36
39
|
nextResetDate,
|
|
37
40
|
};
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
return {
|
|
42
|
+
messageTimestamp: timestamp,
|
|
43
|
+
key: (0, cacheKeysHelpers_1.buildUsageKey)(this.environmentPrefix, customerId, featureId, resourceId),
|
|
44
|
+
value,
|
|
45
|
+
};
|
|
40
46
|
}
|
|
41
47
|
async setCustomer(customerId, customerEntitlements, resourceId, entitlementsTimestamp, featureIdToUsageTimestamp) {
|
|
42
48
|
const lockKey = (0, cacheKeysHelpers_1.buildLockKey)(this.environmentPrefix, customerId, resourceId);
|
|
43
|
-
const entitlementsDbKey = (0, cacheKeysHelpers_1.buildCustomerKey)(this.environmentPrefix, customerId, resourceId);
|
|
44
|
-
const customerEntitlementsAsObject = Object.fromEntries(customerEntitlements);
|
|
45
49
|
await this.redlock.using([lockKey], redisCacheService_constants_1.LOCK_DURATION, async () => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
const { calculatedEntitlement: { feature }, featureUsage: { currentUsage, nextResetDate }, } = entitlement;
|
|
58
|
-
if ((0, lodash_1.isEmpty)(feature === null || feature === void 0 ? void 0 : feature.id)) {
|
|
59
|
-
throw new Error(`Customer key (${entitlementsDbKey}) has an entitlement without feature data`);
|
|
60
|
-
}
|
|
61
|
-
const featureId = feature.id;
|
|
62
|
-
const featureUsageTimestamp = featureIdToUsageTimestamp.get(featureId);
|
|
63
|
-
if (featureUsageTimestamp) {
|
|
64
|
-
return this.updateFeatureUsage({
|
|
65
|
-
featureId,
|
|
66
|
-
customerId,
|
|
67
|
-
timestamp: new Date(featureUsageTimestamp),
|
|
68
|
-
currentUsage,
|
|
69
|
-
nextResetDate: nextResetDate,
|
|
70
|
-
resourceId,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
this.loggerService.error(`Usage timestamp for feature ${featureId} is missing`, {
|
|
75
|
-
customerId,
|
|
76
|
-
resourceId,
|
|
77
|
-
featureId,
|
|
78
|
-
});
|
|
79
|
-
return Promise.resolve();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (err) {
|
|
83
|
-
this.loggerService.error(`Failed to update feature usage after fetching entitlements via network`, {
|
|
84
|
-
error: err,
|
|
85
|
-
customerId,
|
|
86
|
-
resourceId,
|
|
87
|
-
timestamp: entitlementsTimestamp,
|
|
88
|
-
featureId: (_a = entitlement.calculatedEntitlement.feature) === null || _a === void 0 ? void 0 : _a.id,
|
|
89
|
-
});
|
|
90
|
-
throw err;
|
|
91
|
-
}
|
|
50
|
+
const entitlementsItem = {
|
|
51
|
+
messageTimestamp: new Date(entitlementsTimestamp),
|
|
52
|
+
key: (0, cacheKeysHelpers_1.buildCustomerKey)(this.environmentPrefix, customerId, resourceId),
|
|
53
|
+
value: Object.fromEntries(customerEntitlements),
|
|
54
|
+
};
|
|
55
|
+
const featureUsagesItems = this.extractFeatureUsagesToUpdate({
|
|
56
|
+
customerId,
|
|
57
|
+
resourceId,
|
|
58
|
+
customerEntitlements,
|
|
59
|
+
featureIdToUsageTimestamp,
|
|
92
60
|
});
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
updateUsagesResult
|
|
96
|
-
.filter((result) => result.status === 'rejected')
|
|
97
|
-
.forEach((result) => this.loggerService.error(`Failed to update feature usage result: ${result.reason}`));
|
|
61
|
+
``;
|
|
62
|
+
await this.updateCacheItems([entitlementsItem, ...featureUsagesItems]);
|
|
98
63
|
});
|
|
99
64
|
}
|
|
65
|
+
extractFeatureUsagesToUpdate({ customerId, resourceId, customerEntitlements, featureIdToUsageTimestamp, }) {
|
|
66
|
+
return (0, lodash_1.compact)(new Array(...customerEntitlements.values())
|
|
67
|
+
.filter(({ calculatedEntitlement }) => (0, isMetered_1.isMetered)(calculatedEntitlement.feature))
|
|
68
|
+
.map((entitlement) => {
|
|
69
|
+
const { calculatedEntitlement: { feature }, featureUsage: { currentUsage, nextResetDate }, } = entitlement;
|
|
70
|
+
if ((0, lodash_1.isEmpty)(feature === null || feature === void 0 ? void 0 : feature.id)) {
|
|
71
|
+
this.loggerService.error(`entitlement without feature id`, {
|
|
72
|
+
customerId,
|
|
73
|
+
resourceId,
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const featureId = feature.id;
|
|
78
|
+
const featureUsageTimestamp = featureIdToUsageTimestamp.get(featureId);
|
|
79
|
+
if (!featureUsageTimestamp) {
|
|
80
|
+
this.loggerService.error(`Usage timestamp for feature is missing`, {
|
|
81
|
+
customerId,
|
|
82
|
+
resourceId,
|
|
83
|
+
featureId,
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
return this.getFeatureUsageItemToUpdate({
|
|
88
|
+
customerId,
|
|
89
|
+
resourceId,
|
|
90
|
+
featureId,
|
|
91
|
+
currentUsage,
|
|
92
|
+
nextResetDate,
|
|
93
|
+
timestamp: new Date(featureUsageTimestamp),
|
|
94
|
+
});
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
100
97
|
async getCustomerEntitlementsWithoutUsage(customerId, resourceId) {
|
|
101
98
|
const customerKey = (0, cacheKeysHelpers_1.buildCustomerKey)(this.environmentPrefix, customerId, resourceId);
|
|
102
99
|
const keysToFetch = [customerKey];
|
|
@@ -148,12 +145,8 @@ class RedisCacheService {
|
|
|
148
145
|
}
|
|
149
146
|
const { entitlements } = response;
|
|
150
147
|
const meteredFeatureIds = Array.from(entitlements.values())
|
|
151
|
-
.filter((
|
|
152
|
-
|
|
153
|
-
return ((_a = entitlement.calculatedEntitlement.feature) === null || _a === void 0 ? void 0 : _a.meterType) &&
|
|
154
|
-
((_b = entitlement.calculatedEntitlement.feature) === null || _b === void 0 ? void 0 : _b.meterType) !== sdk_1.MeterType.None;
|
|
155
|
-
})
|
|
156
|
-
.map((entitlement) => entitlement.calculatedEntitlement.feature.id);
|
|
148
|
+
.filter(({ calculatedEntitlement }) => (0, isMetered_1.isMetered)(calculatedEntitlement.feature))
|
|
149
|
+
.map(({ calculatedEntitlement }) => calculatedEntitlement.feature.id);
|
|
157
150
|
if (!(0, lodash_1.isEmpty)(meteredFeatureIds)) {
|
|
158
151
|
const featuresUsageByFeatureKey = await this.getFeaturesUsage(this.environmentPrefix, customerId, resourceId, meteredFeatureIds);
|
|
159
152
|
const foundFeatureIds = Array.from(featuresUsageByFeatureKey.keys());
|
|
@@ -169,8 +162,7 @@ class RedisCacheService {
|
|
|
169
162
|
featuresUsageByFeatureKey.forEach((usageValue, featureKey) => {
|
|
170
163
|
const cachedEntitlement = entitlements.get(featureKey);
|
|
171
164
|
if (cachedEntitlement) {
|
|
172
|
-
|
|
173
|
-
entitlements.set(featureKey, { calculatedEntitlement, featureUsage: Object.assign(Object.assign({}, featureUsage), usageValue) });
|
|
165
|
+
entitlements.set(featureKey, this.mergeEntitlementWithUsage(cachedEntitlement, usageValue));
|
|
174
166
|
}
|
|
175
167
|
else {
|
|
176
168
|
this.loggerService.log(`Found usage for a feature the customer is not entitled to.`, {
|
|
@@ -200,29 +192,46 @@ class RedisCacheService {
|
|
|
200
192
|
clearCache() {
|
|
201
193
|
return;
|
|
202
194
|
}
|
|
203
|
-
async
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
messageTimestamp.getTime() === entitlementsService_utils_1.DATE_IN_FAR_PAST.getTime() ||
|
|
207
|
-
latestTimestamp.getTime() <= messageTimestamp.getTime()) {
|
|
208
|
-
const writeableValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
209
|
-
await this.redisClient
|
|
210
|
-
.multi()
|
|
211
|
-
.set(key, writeableValue, 'EX', this.ttl)
|
|
212
|
-
.set(`${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`, messageTimestamp.getTime(), 'EX', this.ttl)
|
|
213
|
-
.exec();
|
|
195
|
+
async updateCacheItems(items) {
|
|
196
|
+
if ((0, lodash_1.isEmpty)(items)) {
|
|
197
|
+
return;
|
|
214
198
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
199
|
+
const latestTimestampByKey = await this.getKeysLatestTimestamp(items.map((item) => item.key));
|
|
200
|
+
const itemsToUpdate = [];
|
|
201
|
+
items.forEach(({ messageTimestamp, key, value }) => {
|
|
202
|
+
const latestTimestamp = latestTimestampByKey.get(key);
|
|
203
|
+
if (!latestTimestamp ||
|
|
204
|
+
messageTimestamp.getTime() === entitlementsService_utils_1.DATE_IN_FAR_PAST.getTime() ||
|
|
205
|
+
latestTimestamp.getTime() <= messageTimestamp.getTime()) {
|
|
206
|
+
const writeableValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
207
|
+
itemsToUpdate.push({ key, value: writeableValue });
|
|
208
|
+
itemsToUpdate.push({ key: `${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`, value: messageTimestamp.getTime() });
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.loggerService.log('Cache data timestamp is after message timestamp, skipping key update', {
|
|
212
|
+
messageTimestamp,
|
|
213
|
+
latestTimestamp,
|
|
214
|
+
key,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
if ((0, lodash_1.isEmpty)(itemsToUpdate)) {
|
|
219
|
+
return;
|
|
221
220
|
}
|
|
221
|
+
const batch = this.redisClient.multi();
|
|
222
|
+
itemsToUpdate.forEach(({ key, value }) => {
|
|
223
|
+
batch.set(key, value, 'EX', this.ttl);
|
|
224
|
+
});
|
|
225
|
+
await batch.exec();
|
|
222
226
|
}
|
|
223
|
-
async
|
|
224
|
-
const
|
|
225
|
-
|
|
227
|
+
async getKeysLatestTimestamp(keys) {
|
|
228
|
+
const timestampKeys = keys.map((key) => `${key}#${redisCacheService_constants_1.TIMESTAMP_SUFFIX}`);
|
|
229
|
+
const value = await this.redisClient.mget(timestampKeys);
|
|
230
|
+
const result = new Map();
|
|
231
|
+
keys.forEach((key, index) => {
|
|
232
|
+
result.set(key, this.parseTimestamp(value[index]));
|
|
233
|
+
});
|
|
234
|
+
return result;
|
|
226
235
|
}
|
|
227
236
|
parseTimestamp(value) {
|
|
228
237
|
if ((0, lodash_1.isNil)(value)) {
|
|
@@ -243,11 +252,14 @@ class RedisCacheService {
|
|
|
243
252
|
const { entitlements, customerExists, cacheMiss, globalCustomerMissing } = await this.getCustomerEntitlementsWithoutUsage(customerId, resourceId);
|
|
244
253
|
const entitlement = !cacheMiss ? (entitlements === null || entitlements === void 0 ? void 0 : entitlements.get(featureId)) || null : null;
|
|
245
254
|
const result = { cacheMiss, customerExists, entitlement, globalCustomerMissing };
|
|
246
|
-
if (!(0, isMetered_1.isMetered)(entitlement === null || entitlement === void 0 ? void 0 : entitlement.calculatedEntitlement.feature)) {
|
|
255
|
+
if (!entitlement || !(0, isMetered_1.isMetered)(entitlement === null || entitlement === void 0 ? void 0 : entitlement.calculatedEntitlement.feature)) {
|
|
247
256
|
return result;
|
|
248
257
|
}
|
|
249
|
-
const
|
|
250
|
-
|
|
258
|
+
const featuresUsageByFeatureKey = await this.getFeaturesUsage(this.environmentPrefix, customerId, resourceId, [
|
|
259
|
+
featureId,
|
|
260
|
+
]);
|
|
261
|
+
const cachedFeatureUsage = featuresUsageByFeatureKey.get(featureId);
|
|
262
|
+
if ((0, lodash_1.isNil)(cachedFeatureUsage)) {
|
|
251
263
|
this.loggerService.error('Failed to find metered feature usage - considering it as cache miss', {
|
|
252
264
|
customerId,
|
|
253
265
|
resourceId,
|
|
@@ -255,13 +267,15 @@ class RedisCacheService {
|
|
|
255
267
|
});
|
|
256
268
|
return { cacheMiss: true, customerExists: false, entitlement: null, globalCustomerMissing: false };
|
|
257
269
|
}
|
|
258
|
-
|
|
270
|
+
return Object.assign(Object.assign({}, result), { entitlement: this.mergeEntitlementWithUsage(entitlement, cachedFeatureUsage) });
|
|
271
|
+
}
|
|
272
|
+
mergeEntitlementWithUsage(entitlement, cachedUsage) {
|
|
259
273
|
const { calculatedEntitlement, featureUsage } = entitlement;
|
|
260
|
-
return
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
274
|
+
return {
|
|
275
|
+
calculatedEntitlement,
|
|
276
|
+
featureUsage: Object.assign(Object.assign({}, featureUsage), cachedUsage),
|
|
277
|
+
};
|
|
264
278
|
}
|
|
265
279
|
}
|
|
266
280
|
exports.RedisCacheService = RedisCacheService;
|
|
267
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXNDYWNoZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvY2FjaGUvcmVkaXNDYWNoZVNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBRUEsc0RBQTRCO0FBQzVCLG1DQUE4RDtBQUM5RCxnRUFBbUU7QUFFbkUsc0RBQThCO0FBRTlCLG1FQUE2RjtBQUM3RiwrRUFBNEU7QUFDNUUsNEVBS3NDO0FBQ3RDLCtFQU11QztBQUN2QyxxREFBa0Q7QUFFbEQsTUFBYSxpQkFBaUI7SUFRNUIsWUFBWSxPQUEwQixFQUFtQixhQUE0QjtRQUE1QixrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQUNuRixNQUFNLEVBQUUsaUJBQWlCLEVBQUUsR0FBRyxHQUFHLDhDQUFnQixFQUFFLCtCQUErQixHQUFHLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQztRQUVwRyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksaUJBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0QyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksaUJBQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQztRQUMzQyxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUVmLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLGFBQWEsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsc0JBQXNCLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMvRixJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLHNCQUFzQixFQUFFLEdBQUcsQ0FBQyxDQUFDLENB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
|
|
281
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXNDYWNoZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvY2FjaGUvcmVkaXNDYWNoZVNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBRUEsc0RBQTRCO0FBQzVCLG1DQUF1RTtBQUV2RSxzREFBOEI7QUFFOUIsbUVBQTZGO0FBQzdGLCtFQUE0RTtBQUM1RSw0RUFLc0M7QUFDdEMsK0VBTXVDO0FBQ3ZDLHFEQUFrRDtBQWFsRCxNQUFhLGlCQUFpQjtJQVE1QixZQUFZLE9BQTBCLEVBQW1CLGFBQTRCO1FBQTVCLGtCQUFhLEdBQWIsYUFBYSxDQUFlO1FBQ25GLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxHQUFHLEdBQUcsOENBQWdCLEVBQUUsK0JBQStCLEdBQUcsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDO1FBRXBHLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxpQkFBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxpQkFBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7UUFDL0MsSUFBSSxDQUFDLGlCQUFpQixHQUFHLGlCQUFpQixDQUFDO1FBQzNDLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBRWYsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsYUFBYSxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQy9GLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsc0JBQXNCLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUM3RixJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMseUJBQXlCLENBQUMsQ0FBQyxDQUFDO1FBRXhGLElBQUksQ0FBQywrQkFBK0IsQ0FBQyxRQUFRLEVBQUU7WUFDN0MsTUFBTSxFQUFFLHFCQUFxQixHQUFHLDZEQUErQixFQUFFLEdBQUcsK0JBQStCLENBQUM7WUFDcEcsSUFBSSxDQUFDLHFDQUFxQyxHQUFHLElBQUkseURBQTJCLENBQzFFLG9EQUFzQixFQUN0QixJQUFJLENBQUMsaUJBQWlCLEVBQ3RCLHFCQUFxQixFQUNyQixJQUFJLENBQUMsV0FBVyxFQUNoQixJQUFJLENBQUMsT0FBTyxFQUNaLElBQUksQ0FBQyxhQUFhLENBQ25CLENBQUM7U0FDSDtJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsa0JBQWtCLENBQUMsTUFBaUM7UUFDeEQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLDJCQUEyQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RELE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNwQyxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFTywyQkFBMkIsQ0FBQyxFQUNsQyxTQUFTLEVBQ1QsWUFBWSxFQUNaLFVBQVUsRUFDVixhQUFhLEVBQ2IsVUFBVSxFQUNWLFNBQVMsR0FDaUI7UUFDMUIsTUFBTSxLQUFLLEdBQXVCO1lBQ2hDLFlBQVk7WUFDWixhQUFhO1NBQ2QsQ0FBQztRQUNGLE9BQU87WUFDTCxnQkFBZ0IsRUFBRSxTQUFTO1lBQzNCLEdBQUcsRUFBRSxJQUFBLGdDQUFhLEVBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsVUFBVSxDQUFDO1lBQzdFLEtBQUs7U0FDTixDQUFDO0lBQ0osQ0FBQztJQUVELEtBQUssQ0FBQyxXQUFXLENBQ2YsVUFBa0IsRUFDbEIsb0JBQW9ELEVBQ3BELFVBQThCLEVBQzlCLHFCQUE2QixFQUM3Qix5QkFBOEM7UUFFOUMsTUFBTSxPQUFPLEdBQUcsSUFBQSwrQkFBWSxFQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDN0UsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLDJDQUFhLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDNUQsTUFBTSxnQkFBZ0IsR0FBaUI7Z0JBQ3JDLGdCQUFnQixFQUFFLElBQUksSUFBSSxDQUFDLHFCQUFxQixDQUFDO2dCQUNqRCxHQUFHLEVBQUUsSUFBQSxtQ0FBZ0IsRUFBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQztnQkFDckUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsb0JBQW9CLENBQUM7YUFDaEQsQ0FBQztZQUNGLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLDRCQUE0QixDQUFDO2dCQUMzRCxVQUFVO2dCQUNWLFVBQVU7Z0JBQ1Ysb0JBQW9CO2dCQUNwQix5QkFBeUI7YUFDMUIsQ0FBQyxDQUFDO1lBQ0gsRUFBRSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLGtCQUFrQixDQUFDLENBQUMsQ0FBQztRQUN6RSxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyw0QkFBNEIsQ0FBQyxFQUNuQyxVQUFVLEVBQ1YsVUFBVSxFQUNWLG9CQUFvQixFQUNwQix5QkFBeUIsR0FNMUI7UUFDQyxPQUFPLElBQUEsZ0JBQU8sRUFDWixJQUFJLEtBQUssQ0FBQyxHQUFHLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQ3hDLE1BQU0sQ0FBQyxDQUFDLEVBQUUscUJBQXFCLEVBQUUsRUFBRSxFQUFFLENBQUMsSUFBQSxxQkFBUyxFQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO2FBQy9FLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQ25CLE1BQU0sRUFDSixxQkFBcUIsRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUNsQyxZQUFZLEVBQUUsRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLEdBQzlDLEdBQUcsV0FBVyxDQUFDO1lBQ2hCLElBQUksSUFBQSxnQkFBTyxFQUFDLE9BQU8sYUFBUCxPQUFPLHVCQUFQLE9BQU8sQ0FBRSxFQUFFLENBQUMsRUFBRTtnQkFDeEIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsZ0NBQWdDLEVBQUU7b0JBQ3pELFVBQVU7b0JBQ1YsVUFBVTtpQkFDWCxDQUFDLENBQUM7Z0JBQ0gsT0FBTzthQUNSO1lBQ0QsTUFBTSxTQUFTLEdBQUcsT0FBUSxDQUFDLEVBQUUsQ0FBQztZQUM5QixNQUFNLHFCQUFxQixHQUFHLHlCQUF5QixDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUV2RSxJQUFJLENBQUMscUJBQXFCLEVBQUU7Z0JBQzFCLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLHdDQUF3QyxFQUFFO29CQUNqRSxVQUFVO29CQUNWLFVBQVU7b0JBQ1YsU0FBUztpQkFDVixDQUFDLENBQUM7Z0JBQ0gsT0FBTzthQUNSO1lBRUQsT0FBTyxJQUFJLENBQUMsMkJBQTJCLENBQUM7Z0JBQ3RDLFVBQVU7Z0JBQ1YsVUFBVTtnQkFDVixTQUFTO2dCQUNULFlBQVk7Z0JBQ1osYUFBYTtnQkFDYixTQUFTLEVBQUUsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUM7YUFDM0MsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQ0wsQ0FBQztJQUNKLENBQUM7SUFFRCxLQUFLLENBQUMsbUNBQW1DLENBQ3ZDLFVBQWtCLEVBQ2xCLFVBQThCO1FBRTlCLE1BQU0sV0FBVyxHQUFHLElBQUEsbUNBQWdCLEVBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNyRixNQUFNLFdBQVcsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRWxDLElBQUksVUFBVSxFQUFFO1lBQ2QsTUFBTSxpQkFBaUIsR0FBRyxJQUFBLG1DQUFnQixFQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDMUYsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLFdBQVcsSUFBSSw4Q0FBZ0IsRUFBRSxDQUFDLENBQUM7WUFDdkQsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLGlCQUFpQixJQUFJLDhDQUFnQixFQUFFLENBQUMsQ0FBQztTQUM5RDtRQUVELE1BQU0sQ0FBQyxlQUFlLEVBQUUsMEJBQTBCLEVBQUUsZ0NBQWdDLENBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUNqSCxXQUFXLENBQ1osQ0FBQztRQUVGLE1BQU0sWUFBWSxHQUNoQixDQUFDLElBQUEsY0FBSyxFQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBQSxnQkFBTyxFQUFDLGVBQWUsQ0FBQztZQUNsRCxDQUFDLENBQUMsSUFBSSxHQUFHLENBQTRCLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDO1lBQ2pGLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDWCxNQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUM5RSxNQUFNLDJCQUEyQixHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztRQUMxRixNQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQyw4QkFBOEIsQ0FDL0QsVUFBVSxFQUNWLFVBQVUsRUFDVixZQUFZLEVBQ1oscUJBQXFCLEVBQ3JCLDJCQUEyQixDQUM1QixDQUFDO1FBRUYsSUFBSSxDQUFDLFlBQVksSUFBSSxxQkFBcUIsRUFBRTtZQUMxQyxPQUFPLHNEQUEwQixDQUFDLFNBQVMsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1NBQ3BFO1FBRUQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsb0RBQW9ELEVBQUUsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUMzRyxPQUFPLHNEQUEwQixDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBRUQsMEVBQTBFO0lBQzFFLGdGQUFnRjtJQUN4RSw4QkFBOEIsQ0FDcEMsVUFBa0IsRUFDbEIsVUFBOEIsRUFDOUIsWUFBbUQsRUFDbkQscUJBQXVDLEVBQ3ZDLDJCQUE2QztRQUU3QyxJQUFJLElBQUEsY0FBSyxFQUFDLFVBQVUsQ0FBQyxFQUFFO1lBQ3JCLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7UUFFRCxJQUFJLENBQUMsWUFBWSxFQUFFO1lBQ2pCLCtFQUErRTtZQUMvRSxrRUFBa0U7WUFDbEUsT0FBTyxDQUFDLDJCQUEyQixDQUFDO1NBQ3JDO1FBRUQsTUFBTSx1Q0FBdUMsR0FDM0MscUJBQXFCLElBQUksMkJBQTJCLElBQUkscUJBQXFCLElBQUksMkJBQTJCLENBQUM7UUFDL0csSUFBSSx1Q0FBdUMsRUFBRTtZQUMzQyxPQUFPLEtBQUssQ0FBQztTQUNkO1FBRUQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsZ0RBQWdELEVBQUU7WUFDdkUsVUFBVTtZQUNWLFVBQVU7WUFDVixxQkFBcUI7WUFDckIsMkJBQTJCO1NBQzVCLENBQUMsQ0FBQztRQUNILE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxVQUFrQixFQUFFLFVBQThCO1FBQzlFLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLG1DQUFtQyxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN4RixJQUFJLFFBQVEsQ0FBQyxTQUFTLEVBQUU7WUFDdEIsT0FBTyxRQUFRLENBQUM7U0FDakI7UUFFRCxNQUFNLEVBQUUsWUFBWSxFQUFFLEdBQUcsUUFBUSxDQUFDO1FBRWxDLE1BQU0saUJBQWlCLEdBQWtCLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQ3ZFLE1BQU0sQ0FBQyxDQUFDLEVBQUUscUJBQXFCLEVBQUUsRUFBRSxFQUFFLENBQUMsSUFBQSxxQkFBUyxFQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO2FBQy9FLEdBQUcsQ0FBQyxDQUFDLEVBQUUscUJBQXFCLEVBQUUsRUFBRSxFQUFFLENBQUMscUJBQXFCLENBQUMsT0FBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRXpFLElBQUksQ0FBQyxJQUFBLGdCQUFPLEVBQUMsaUJBQWlCLENBQUMsRUFBRTtZQUMvQixNQUFNLHlCQUF5QixHQUFHLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUMzRCxJQUFJLENBQUMsaUJBQWlCLEVBQ3RCLFVBQVUsRUFDVixVQUFVLEVBQ1YsaUJBQWlCLENBQ2xCLENBQUM7WUFFRixNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7WUFDckUsTUFBTSxpQkFBaUIsR0FBRyxJQUFBLG1CQUFVLEVBQUMsaUJBQWlCLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFFekUsSUFBSSxDQUFDLElBQUEsZ0JBQU8sRUFBQyxpQkFBaUIsQ0FBQyxFQUFFO2dCQUMvQixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxzRUFBc0UsRUFBRTtvQkFDL0YsVUFBVTtvQkFDVixVQUFVO29CQUNWLGlCQUFpQjtpQkFDbEIsQ0FBQyxDQUFDO2dCQUNILE9BQU8sc0RBQTBCLENBQUMsU0FBUyxFQUFFLENBQUM7YUFDL0M7WUFFRCx5QkFBeUIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLEVBQUUsVUFBVSxFQUFFLEVBQUU7Z0JBQzNELE1BQU0saUJBQWlCLEdBQUcsWUFBWSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDdkQsSUFBSSxpQkFBaUIsRUFBRTtvQkFDckIsWUFBWSxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLHlCQUF5QixDQUFDLGlCQUFpQixFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUM7aUJBQzdGO3FCQUFNO29CQUNMLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLDREQUE0RCxFQUFFO3dCQUNuRixVQUFVO3dCQUNWLFVBQVU7cUJBQ1gsQ0FBQyxDQUFDO2lCQUNKO1lBQ0gsQ0FBQyxDQUFDLENBQUM7U0FDSjtRQUVELE9BQU8sc0RBQTBCLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFFTyxLQUFLLENBQUMsZ0JBQWdCLENBQzVCLGlCQUF5QixFQUN6QixVQUFrQixFQUNsQixVQUE4QixFQUM5QixpQkFBZ0M7UUFFaEMsTUFBTSxXQUFXLEdBQUcsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FDdEQsSUFBQSxnQ0FBYSxFQUFDLGlCQUFpQixFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQ3BFLENBQUM7UUFDRixNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRTdELE1BQU0sdUJBQXVCLEdBQUcsSUFBSSxHQUFHLEVBQThCLENBQUM7UUFFdEUsb0ZBQW9GO1FBQ3BGLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUM3QyxNQUFNLGlCQUFpQixHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUU3QyxJQUFJLGlCQUFpQixLQUFLLElBQUksRUFBRTtnQkFDOUIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsNkNBQTZDLFNBQVMsRUFBRSxDQUFDLENBQUM7Z0JBQ2pGLE9BQU87YUFDUjtZQUVELHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUM7UUFDeEUsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLHVCQUF1QixDQUFDO0lBQ2pDLENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTztJQUNULENBQUM7SUFFTyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsS0FBcUI7UUFDbEQsSUFBSSxJQUFBLGdCQUFPLEVBQUMsS0FBSyxDQUFDLEVBQUU7WUFDbEIsT0FBTztTQUNSO1FBRUQsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUM5RixNQUFNLGFBQWEsR0FBbUQsRUFBRSxDQUFDO1FBRXpFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLGdCQUFnQixFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFO1lBQ2pELE1BQU0sZUFBZSxHQUFHLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN0RCxJQUNFLENBQUMsZUFBZTtnQkFDaEIsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEtBQUssNENBQWdCLENBQUMsT0FBTyxFQUFFO2dCQUN6RCxlQUFlLENBQUMsT0FBTyxFQUFFLElBQUksZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEVBQ3ZEO2dCQUNBLE1BQU0sY0FBYyxHQUFHLE9BQU8sS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUNqRixhQUFhLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO2dCQUNuRCxhQUFhLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsR0FBRyxJQUFJLDhDQUFnQixFQUFFLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQzthQUM5RjtpQkFBTTtnQkFDTCxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxzRUFBc0UsRUFBRTtvQkFDN0YsZ0JBQWdCO29CQUNoQixlQUFlO29CQUNmLEdBQUc7aUJBQ0osQ0FBQyxDQUFDO2FBQ0o7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILElBQUksSUFBQSxnQkFBTyxFQUFDLGFBQWEsQ0FBQyxFQUFFO1lBQzFCLE9BQU87U0FDUjtRQUVELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdkMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDdkMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEMsQ0FBQyxDQUFDLENBQUM7UUFDSCxNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRU8sS0FBSyxDQUFDLHNCQUFzQixDQUFDLElBQWM7UUFDakQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLElBQUksOENBQWdCLEVBQUUsQ0FBQyxDQUFDO1FBQ3RFLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFekQsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQTRCLENBQUM7UUFDbkQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUMxQixNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDckQsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRU8sY0FBYyxDQUFDLEtBQW9CO1FBQ3pDLElBQUksSUFBQSxjQUFLLEVBQUMsS0FBSyxDQUFDLEVBQUU7WUFDaEIsT0FBTyxTQUFTLENBQUM7U0FDbEI7UUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFBLGlCQUFRLEVBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ25DLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUN4QixPQUFPLFNBQVMsQ0FBQztTQUNsQjtRQUVELE9BQU8sSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFPOztRQUNYLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUMxQixNQUFNLENBQUEsTUFBQSxJQUFJLENBQUMscUNBQXFDLDBDQUFFLE9BQU8sRUFBRSxDQUFBLENBQUM7SUFDOUQsQ0FBQztJQUVELEtBQUssQ0FBQyxzQkFBc0IsQ0FDMUIsU0FBaUIsRUFDakIsVUFBa0IsRUFDbEIsVUFBOEI7UUFFOUIsTUFBTSxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixFQUFFLEdBQ3RFLE1BQU0sSUFBSSxDQUFDLG1DQUFtQyxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN6RSxNQUFNLFdBQVcsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQSxZQUFZLGFBQVosWUFBWSx1QkFBWixZQUFZLENBQUUsR0FBRyxDQUFDLFNBQVMsQ0FBQyxLQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQzdFLE1BQU0sTUFBTSxHQUFHLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxXQUFXLEVBQUUscUJBQXFCLEVBQUUsQ0FBQztRQUVqRixJQUFJLENBQUMsV0FBVyxJQUFJLENBQUMsSUFBQSxxQkFBUyxFQUFDLFdBQVcsYUFBWCxXQUFXLHVCQUFYLFdBQVcsQ0FBRSxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUMxRSxPQUFPLE1BQU0sQ0FBQztTQUNmO1FBRUQsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRTtZQUM1RyxTQUFTO1NBQ1YsQ0FBQyxDQUFDO1FBRUgsTUFBTSxrQkFBa0IsR0FBRyx5QkFBeUIsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFcEUsSUFBSSxJQUFBLGNBQUssRUFBQyxrQkFBa0IsQ0FBQyxFQUFFO1lBQzdCLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLHFFQUFxRSxFQUFFO2dCQUM5RixVQUFVO2dCQUNWLFVBQVU7Z0JBQ1YsU0FBUzthQUNWLENBQUMsQ0FBQztZQUNILE9BQU8sRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxxQkFBcUIsRUFBRSxLQUFLLEVBQUUsQ0FBQztTQUNwRztRQUVELHVDQUNLLE1BQU0sS0FDVCxXQUFXLEVBQUUsSUFBSSxDQUFDLHlCQUF5QixDQUFDLFdBQVcsRUFBRSxrQkFBa0IsQ0FBQyxJQUM1RTtJQUNKLENBQUM7SUFFTyx5QkFBeUIsQ0FDL0IsV0FBOEIsRUFDOUIsV0FBK0I7UUFFL0IsTUFBTSxFQUFFLHFCQUFxQixFQUFFLFlBQVksRUFBRSxHQUFHLFdBQVcsQ0FBQztRQUM1RCxPQUFPO1lBQ0wscUJBQXFCO1lBQ3JCLFlBQVksa0NBQ1AsWUFBWSxHQUNaLFdBQVcsQ0FDZjtTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUFsWkQsOENBa1pDIn0=
|