ng-http-caching 1.0.14 → 13.0.2

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 (30) hide show
  1. package/README.md +31 -8
  2. package/esm2020/lib/ng-http-caching-interceptor.service.mjs +66 -0
  3. package/esm2020/lib/ng-http-caching.module.mjs +45 -0
  4. package/esm2020/lib/ng-http-caching.service.mjs +265 -0
  5. package/esm2020/lib/storage/ng-http-caching-local-storage.mjs +121 -0
  6. package/esm2020/lib/storage/ng-http-caching-memory-storage.mjs +28 -0
  7. package/esm2020/lib/storage/ng-http-caching-storage.interface.mjs +2 -0
  8. package/{esm2015/ng-http-caching.js → esm2020/ng-http-caching.mjs} +0 -0
  9. package/esm2020/public-api.mjs +10 -0
  10. package/fesm2015/ng-http-caching.mjs +530 -0
  11. package/fesm2015/ng-http-caching.mjs.map +1 -0
  12. package/{fesm2015/ng-http-caching.js → fesm2020/ng-http-caching.mjs} +181 -52
  13. package/fesm2020/ng-http-caching.mjs.map +1 -0
  14. package/lib/ng-http-caching-interceptor.service.d.ts +2 -2
  15. package/lib/ng-http-caching.module.d.ts +3 -2
  16. package/lib/ng-http-caching.service.d.ts +3 -3
  17. package/lib/storage/ng-http-caching-local-storage.d.ts +11 -0
  18. package/package.json +24 -14
  19. package/public-api.d.ts +1 -0
  20. package/bundles/ng-http-caching.umd.js +0 -430
  21. package/bundles/ng-http-caching.umd.js.map +0 -1
  22. package/bundles/ng-http-caching.umd.min.js +0 -2
  23. package/bundles/ng-http-caching.umd.min.js.map +0 -1
  24. package/esm2015/lib/ng-http-caching-interceptor.service.js +0 -65
  25. package/esm2015/lib/ng-http-caching.module.js +0 -44
  26. package/esm2015/lib/ng-http-caching.service.js +0 -260
  27. package/esm2015/lib/storage/ng-http-caching-memory-storage.js +0 -27
  28. package/esm2015/lib/storage/ng-http-caching-storage.interface.js +0 -1
  29. package/esm2015/public-api.js +0 -9
  30. package/fesm2015/ng-http-caching.js.map +0 -1
@@ -0,0 +1,530 @@
1
+ import { HttpResponse, HTTP_INTERCEPTORS, HttpHeaders, HttpParams, HttpRequest } from '@angular/common/http';
2
+ import * as i0 from '@angular/core';
3
+ import { InjectionToken, Injectable, Inject, Optional, NgModule } from '@angular/core';
4
+ import { of } from 'rxjs';
5
+ import { tap, finalize, share } from 'rxjs/operators';
6
+
7
+ class NgHttpCachingMemoryStorage {
8
+ constructor() {
9
+ this.store = new Map();
10
+ }
11
+ get size() {
12
+ return this.store.size;
13
+ }
14
+ clear() {
15
+ this.store.clear();
16
+ }
17
+ delete(key) {
18
+ return this.store.delete(key);
19
+ }
20
+ // eslint-disable-next-line no-unused-vars
21
+ forEach(callbackfn) {
22
+ return this.store.forEach(callbackfn);
23
+ }
24
+ get(key) {
25
+ return this.store.get(key);
26
+ }
27
+ has(key) {
28
+ return this.store.has(key);
29
+ }
30
+ set(key, value) {
31
+ this.store.set(key, value);
32
+ }
33
+ }
34
+
35
+ const NG_HTTP_CACHING_CONFIG = new InjectionToken('ng-http-caching.config');
36
+ var NgHttpCachingStrategy;
37
+ (function (NgHttpCachingStrategy) {
38
+ // eslint-disable-next-line no-unused-vars
39
+ NgHttpCachingStrategy["ALLOW_ALL"] = "ALLOW_ALL";
40
+ // eslint-disable-next-line no-unused-vars
41
+ NgHttpCachingStrategy["DISALLOW_ALL"] = "DISALLOW_ALL";
42
+ })(NgHttpCachingStrategy || (NgHttpCachingStrategy = {}));
43
+ var NgHttpCachingHeaders;
44
+ (function (NgHttpCachingHeaders) {
45
+ // eslint-disable-next-line no-unused-vars
46
+ NgHttpCachingHeaders["ALLOW_CACHE"] = "X-NG-HTTP-CACHING-ALLOW-CACHE";
47
+ // eslint-disable-next-line no-unused-vars
48
+ NgHttpCachingHeaders["DISALLOW_CACHE"] = "X-NG-HTTP-CACHING-DISALLOW-CACHE";
49
+ // eslint-disable-next-line no-unused-vars
50
+ NgHttpCachingHeaders["LIFETIME"] = "X-NG-HTTP-CACHING-LIFETIME";
51
+ // eslint-disable-next-line no-unused-vars
52
+ NgHttpCachingHeaders["TAG"] = "X-NG-HTTP-CACHING-TAG";
53
+ })(NgHttpCachingHeaders || (NgHttpCachingHeaders = {}));
54
+ const NgHttpCachingConfigDefault = {
55
+ store: new NgHttpCachingMemoryStorage(),
56
+ lifetime: 60 * 60 * 100,
57
+ allowedMethod: ['GET'],
58
+ cacheStrategy: NgHttpCachingStrategy.ALLOW_ALL,
59
+ };
60
+ class NgHttpCachingService {
61
+ constructor(config) {
62
+ this.queue = new Map();
63
+ this.config = NgHttpCachingConfigDefault;
64
+ if (config) {
65
+ this.config = Object.assign(Object.assign({}, NgHttpCachingConfigDefault), config);
66
+ }
67
+ }
68
+ /**
69
+ * Return the config
70
+ */
71
+ getConfig() {
72
+ return this.config;
73
+ }
74
+ /**
75
+ * Return the queue map
76
+ */
77
+ getQueue() {
78
+ return this.queue;
79
+ }
80
+ /**
81
+ * Return the cache store
82
+ */
83
+ getStore() {
84
+ return this.config.store;
85
+ }
86
+ /**
87
+ * Return response from cache
88
+ */
89
+ getFromCache(req) {
90
+ var _a;
91
+ const key = this.getKey(req);
92
+ const cached = (_a = this.config.store) === null || _a === void 0 ? void 0 : _a.get(key);
93
+ if (!cached) {
94
+ return undefined;
95
+ }
96
+ if (this.isExpired(cached)) {
97
+ this.clearCacheByKey(key);
98
+ return undefined;
99
+ }
100
+ return cached.response;
101
+ }
102
+ /**
103
+ * Add response to cache
104
+ */
105
+ addToCache(req, res) {
106
+ var _a;
107
+ const key = this.getKey(req);
108
+ const entry = {
109
+ url: req.urlWithParams,
110
+ response: res,
111
+ request: req,
112
+ addedTime: Date.now(),
113
+ };
114
+ if (this.isValid(entry)) {
115
+ (_a = this.config.store) === null || _a === void 0 ? void 0 : _a.set(key, entry);
116
+ return true;
117
+ }
118
+ return false;
119
+ }
120
+ /**
121
+ * Delete response from cache
122
+ */
123
+ deleteFromCache(req) {
124
+ const key = this.getKey(req);
125
+ return this.clearCacheByKey(key);
126
+ }
127
+ /**
128
+ * Clear the cache
129
+ */
130
+ clearCache() {
131
+ var _a;
132
+ (_a = this.config.store) === null || _a === void 0 ? void 0 : _a.clear();
133
+ }
134
+ /**
135
+ * Clear the cache by key
136
+ */
137
+ clearCacheByKey(key) {
138
+ return this.config.store.delete(key);
139
+ }
140
+ /**
141
+ * Clear the cache by regex
142
+ */
143
+ clearCacheByRegex(regex) {
144
+ this.config.store.forEach((entry, key) => {
145
+ if (regex.test(key)) {
146
+ this.clearCacheByKey(key);
147
+ }
148
+ });
149
+ }
150
+ /**
151
+ * Clear the cache by TAG
152
+ */
153
+ clearCacheByTag(tag) {
154
+ this.config.store.forEach((entry, key) => {
155
+ const tagHeader = entry.request.headers.get(NgHttpCachingHeaders.TAG);
156
+ if (tagHeader && tagHeader.split(',').includes(tag)) {
157
+ this.clearCacheByKey(key);
158
+ }
159
+ });
160
+ }
161
+ /**
162
+ * Run garbage collector (delete expired cache entry)
163
+ */
164
+ runGc() {
165
+ this.config.store.forEach((entry, key) => {
166
+ if (this.isExpired(entry)) {
167
+ this.clearCacheByKey(key);
168
+ }
169
+ });
170
+ }
171
+ /**
172
+ * Return true if cache entry is expired
173
+ */
174
+ isExpired(entry) {
175
+ // if user provide custom method, use it
176
+ if (typeof this.config.isExpired === 'function') {
177
+ const result = this.config.isExpired(entry);
178
+ // if result is undefined, normal behaviour is provided
179
+ if (typeof result !== 'undefined') {
180
+ return result;
181
+ }
182
+ }
183
+ // config/default lifetime
184
+ let lifetime = this.config.lifetime;
185
+ // request has own lifetime
186
+ if (entry.request.headers.has(NgHttpCachingHeaders.LIFETIME)) {
187
+ lifetime = +(entry.request.headers.get(NgHttpCachingHeaders.LIFETIME) || '');
188
+ }
189
+ // never expire if 0
190
+ if (lifetime === 0) {
191
+ return false;
192
+ }
193
+ // wrong lifetime
194
+ if (lifetime < 0) {
195
+ throw new Error('lifetime must be greater than or equal 0');
196
+ }
197
+ return entry.addedTime + lifetime < Date.now();
198
+ }
199
+ /**
200
+ * Return true if cache entry is valid for store in the cache
201
+ */
202
+ isValid(entry) {
203
+ // if user provide custom method, use it
204
+ if (typeof this.config.isValid === 'function') {
205
+ const result = this.config.isValid(entry);
206
+ // if result is undefined, normal behaviour is provided
207
+ if (typeof result !== 'undefined') {
208
+ return result;
209
+ }
210
+ }
211
+ return true;
212
+ }
213
+ /**
214
+ * Return true if the request is cacheable
215
+ */
216
+ isCacheable(req) {
217
+ // if user provide custom method, use it
218
+ if (typeof this.config.isCacheable === 'function') {
219
+ const result = this.config.isCacheable(req);
220
+ // if result is undefined, normal behaviour is provided
221
+ if (typeof result !== 'undefined') {
222
+ return result;
223
+ }
224
+ }
225
+ // request has disallow cache header
226
+ if (req.headers.has(NgHttpCachingHeaders.DISALLOW_CACHE)) {
227
+ return false;
228
+ }
229
+ // strategy is disallow all...
230
+ if (this.config.cacheStrategy === NgHttpCachingStrategy.DISALLOW_ALL) {
231
+ // request isn't allowed if come without allow header
232
+ if (!req.headers.has(NgHttpCachingHeaders.ALLOW_CACHE)) {
233
+ return false;
234
+ }
235
+ }
236
+ // if allowed method is only ALL, allow all http methos
237
+ if (this.config.allowedMethod) {
238
+ if (this.config.allowedMethod.length === 1) {
239
+ if (this.config.allowedMethod[0] === 'ALL') {
240
+ return true;
241
+ }
242
+ }
243
+ // request is allowed if method is in allowedMethod
244
+ return this.config.allowedMethod.indexOf(req.method) !== -1;
245
+ }
246
+ return true;
247
+ }
248
+ /**
249
+ * Return the cache key
250
+ */
251
+ getKey(req) {
252
+ // if user provide custom method, use it
253
+ if (typeof this.config.getKey === 'function') {
254
+ const result = this.config.getKey(req);
255
+ // if result is undefined, normal behaviour is provided
256
+ if (typeof result !== 'undefined') {
257
+ return result;
258
+ }
259
+ }
260
+ // default key id is url with query parameters
261
+ return req.urlWithParams;
262
+ }
263
+ /**
264
+ * Return observable from cache
265
+ */
266
+ getFromQueue(req) {
267
+ const key = this.getKey(req);
268
+ const cached = this.queue.get(key);
269
+ if (!cached) {
270
+ return undefined;
271
+ }
272
+ return cached;
273
+ }
274
+ /**
275
+ * Add observable to cache
276
+ */
277
+ addToQueue(req, obs) {
278
+ const key = this.getKey(req);
279
+ this.queue.set(key, obs);
280
+ }
281
+ /**
282
+ * Delete observable from cache
283
+ */
284
+ deleteFromQueue(req) {
285
+ const key = this.getKey(req);
286
+ return this.queue.delete(key);
287
+ }
288
+ }
289
+ NgHttpCachingService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingService, deps: [{ token: NG_HTTP_CACHING_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
290
+ NgHttpCachingService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingService });
291
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingService, decorators: [{
292
+ type: Injectable
293
+ }], ctorParameters: function () {
294
+ return [{ type: undefined, decorators: [{
295
+ type: Inject,
296
+ args: [NG_HTTP_CACHING_CONFIG]
297
+ }, {
298
+ type: Optional
299
+ }] }];
300
+ } });
301
+
302
+ class NgHttpCachingInterceptorService {
303
+ // eslint-disable-next-line no-unused-vars
304
+ constructor(cacheService) {
305
+ this.cacheService = cacheService;
306
+ }
307
+ intercept(req, next) {
308
+ // run garbage collector
309
+ this.cacheService.runGc();
310
+ // Don't cache if it's not cacheable
311
+ if (!this.cacheService.isCacheable(req)) {
312
+ return this.sendRequest(req, next);
313
+ }
314
+ // Checked if there is pending response for this request
315
+ const cachedObservable = this.cacheService.getFromQueue(req);
316
+ if (cachedObservable) {
317
+ // console.log('cachedObservable', req);
318
+ return cachedObservable;
319
+ }
320
+ // Checked if there is cached response for this request
321
+ const cachedResponse = this.cacheService.getFromCache(req);
322
+ if (cachedResponse) {
323
+ // console.log('cachedResponse', req);
324
+ return of(cachedResponse.clone());
325
+ }
326
+ // If the request of going through for first time
327
+ // then let the request proceed and cache the response
328
+ // console.log('sendRequest', req);
329
+ const shared = this.sendRequest(req, next).pipe(tap(event => {
330
+ if (event instanceof HttpResponse) {
331
+ this.cacheService.addToCache(req, event.clone());
332
+ }
333
+ }), finalize(() => {
334
+ // delete pending request
335
+ this.cacheService.deleteFromQueue(req);
336
+ }), share());
337
+ // add pending request to queue for cache parallell request
338
+ this.cacheService.addToQueue(req, shared);
339
+ return shared;
340
+ }
341
+ /**
342
+ * Send http request (next handler)
343
+ */
344
+ sendRequest(req, next) {
345
+ let cloned = req.clone();
346
+ // trim custom headers before send request
347
+ Object.values(NgHttpCachingHeaders).forEach(ngHttpCachingHeaders => {
348
+ if (cloned.headers.has(ngHttpCachingHeaders)) {
349
+ cloned = cloned.clone({ headers: cloned.headers.delete(ngHttpCachingHeaders) });
350
+ }
351
+ });
352
+ return next.handle(cloned);
353
+ }
354
+ }
355
+ NgHttpCachingInterceptorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingInterceptorService, deps: [{ token: NgHttpCachingService }], target: i0.ɵɵFactoryTarget.Injectable });
356
+ NgHttpCachingInterceptorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingInterceptorService });
357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingInterceptorService, decorators: [{
358
+ type: Injectable
359
+ }], ctorParameters: function () { return [{ type: NgHttpCachingService }]; } });
360
+
361
+ class NgHttpCachingModule {
362
+ static forRoot(ngHttpCachingConfig) {
363
+ return {
364
+ ngModule: NgHttpCachingModule,
365
+ providers: [
366
+ {
367
+ provide: NG_HTTP_CACHING_CONFIG,
368
+ useValue: ngHttpCachingConfig,
369
+ },
370
+ ],
371
+ };
372
+ }
373
+ }
374
+ NgHttpCachingModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
375
+ NgHttpCachingModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingModule });
376
+ NgHttpCachingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingModule, providers: [
377
+ NgHttpCachingService,
378
+ {
379
+ provide: HTTP_INTERCEPTORS,
380
+ useClass: NgHttpCachingInterceptorService,
381
+ multi: true,
382
+ },
383
+ ], imports: [[]] });
384
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: NgHttpCachingModule, decorators: [{
385
+ type: NgModule,
386
+ args: [{
387
+ declarations: [],
388
+ imports: [],
389
+ providers: [
390
+ NgHttpCachingService,
391
+ {
392
+ provide: HTTP_INTERCEPTORS,
393
+ useClass: NgHttpCachingInterceptorService,
394
+ multi: true,
395
+ },
396
+ ],
397
+ exports: [],
398
+ }]
399
+ }] });
400
+
401
+ const KEY_PREFIX = 'NgHttpCaching::';
402
+ function serializeRequest(req) {
403
+ const request = req.clone(); // Make a clone, useful for doing destructive things
404
+ return JSON.stringify({
405
+ headers: Object.fromEntries(// Just a helper to make this into an object, not really required but makes the output nicer
406
+ request.headers.keys().map(// Get all of the headers
407
+ (key) => [key, request.headers.getAll(key)] // Get all of the corresponding values for the headers
408
+ )),
409
+ method: request.method,
410
+ url: request.url,
411
+ params: Object.fromEntries(// Just a helper to make this into an object, not really required but makes the output nicer
412
+ request.headers.keys().map(// Get all of the headers
413
+ (key) => [key, request.headers.getAll(key)] // Get all of the corresponding values for the headers
414
+ )),
415
+ withCredentials: request.withCredentials,
416
+ respnseType: request.responseType,
417
+ body: request.serializeBody() // Serialize the body, all well and good since we are working on a clone
418
+ });
419
+ }
420
+ function serializeResponse(res) {
421
+ const response = res.clone();
422
+ return JSON.stringify({
423
+ headers: Object.fromEntries(// Just a helper to make this into an object, not really required but makes the output nicer
424
+ response.headers.keys().map(// Get all of the headers
425
+ (key) => [key, response.headers.getAll(key)] // Get all of the corresponding values for the headers
426
+ )),
427
+ status: response.status,
428
+ statusText: response.statusText,
429
+ url: response.url,
430
+ body: response // Serialize the body, all well and good since we are working on a clone
431
+ });
432
+ }
433
+ function deserializeRequest(req) {
434
+ const request = JSON.parse(req);
435
+ const headers = new HttpHeaders(request.headers);
436
+ const params = new HttpParams(); // Probably some way to make this a one-liner, but alas, there are no good docs
437
+ // tslint:disable-next-line: forin
438
+ for (const parameter in request.params) {
439
+ request.params[parameter].forEach((paramValue) => params.append(parameter, paramValue));
440
+ }
441
+ return new HttpRequest(request.method, request.url, request.body, {
442
+ headers,
443
+ params,
444
+ responseType: request.responseType,
445
+ withCredentials: request.withCredentials
446
+ });
447
+ }
448
+ function deserializeResponse(res) {
449
+ const response = JSON.parse(res);
450
+ return new HttpResponse({
451
+ url: response.url,
452
+ headers: new HttpHeaders(response.headers),
453
+ body: response.body,
454
+ status: response.status,
455
+ statusText: response.statusText,
456
+ });
457
+ }
458
+ class NgHttpCachingLocalStorage {
459
+ get size() {
460
+ let count = 0;
461
+ for (let i = 0, e = localStorage.length; i < e; i++) {
462
+ const key = localStorage.key(i);
463
+ if (key && key.startsWith(KEY_PREFIX)) {
464
+ count++;
465
+ }
466
+ }
467
+ return count;
468
+ }
469
+ clear() {
470
+ for (let i = 0, e = localStorage.length; i < e; i++) {
471
+ const key = localStorage.key(i);
472
+ if (key && key.startsWith(KEY_PREFIX)) {
473
+ localStorage.removeItem(key);
474
+ }
475
+ }
476
+ }
477
+ delete(key) {
478
+ localStorage.removeItem(KEY_PREFIX + key);
479
+ return true;
480
+ }
481
+ // eslint-disable-next-line no-unused-vars
482
+ forEach(callbackfn) {
483
+ // iterate localStorage
484
+ const lenPrefix = KEY_PREFIX.length;
485
+ for (let i = 0, e = localStorage.length; i < e; i++) {
486
+ const key = localStorage.key(i);
487
+ if (key && key.startsWith(KEY_PREFIX)) {
488
+ const value = this.get(key.substring(lenPrefix));
489
+ if (value) {
490
+ callbackfn(value, key);
491
+ }
492
+ }
493
+ }
494
+ }
495
+ get(key) {
496
+ const item = localStorage.getItem(KEY_PREFIX + key);
497
+ if (item) {
498
+ const parsedItem = JSON.parse(item);
499
+ return {
500
+ url: parsedItem.url,
501
+ response: deserializeResponse(parsedItem.response),
502
+ request: deserializeRequest(parsedItem.request),
503
+ addedTime: parsedItem.addedTime
504
+ };
505
+ }
506
+ return undefined;
507
+ }
508
+ has(key) {
509
+ return localStorage.getItem(KEY_PREFIX + key) !== undefined;
510
+ }
511
+ set(key, value) {
512
+ localStorage.setItem(KEY_PREFIX + key, JSON.stringify({
513
+ url: value.url,
514
+ response: serializeResponse(value.response),
515
+ request: serializeRequest(value.request),
516
+ addedTime: value.addedTime
517
+ }));
518
+ }
519
+ }
520
+
521
+ /*
522
+ * Public API Surface of ng-http-caching
523
+ */
524
+
525
+ /**
526
+ * Generated bundle index. Do not edit.
527
+ */
528
+
529
+ export { NG_HTTP_CACHING_CONFIG, NgHttpCachingConfigDefault, NgHttpCachingHeaders, NgHttpCachingInterceptorService, NgHttpCachingLocalStorage, NgHttpCachingMemoryStorage, NgHttpCachingModule, NgHttpCachingService, NgHttpCachingStrategy };
530
+ //# sourceMappingURL=ng-http-caching.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ng-http-caching.mjs","sources":["../../../projects/ng-http-caching/src/lib/storage/ng-http-caching-memory-storage.ts","../../../projects/ng-http-caching/src/lib/ng-http-caching.service.ts","../../../projects/ng-http-caching/src/lib/ng-http-caching-interceptor.service.ts","../../../projects/ng-http-caching/src/lib/ng-http-caching.module.ts","../../../projects/ng-http-caching/src/lib/storage/ng-http-caching-local-storage.ts","../../../projects/ng-http-caching/src/public-api.ts","../../../projects/ng-http-caching/src/ng-http-caching.ts"],"sourcesContent":["import { NgHttpCachingStorageInterface } from './ng-http-caching-storage.interface';\r\nimport { NgHttpCachingEntry } from '../ng-http-caching.service';\r\n\r\nexport class NgHttpCachingMemoryStorage implements NgHttpCachingStorageInterface {\r\n\r\n get size(): number {\r\n return this.store.size;\r\n }\r\n\r\n private store = new Map<string, NgHttpCachingEntry>();\r\n\r\n clear(): void {\r\n this.store.clear();\r\n }\r\n\r\n delete(key: string): boolean {\r\n return this.store.delete(key);\r\n }\r\n\r\n // eslint-disable-next-line no-unused-vars\r\n forEach(callbackfn: (value: NgHttpCachingEntry, key: string) => void): void {\r\n return this.store.forEach(callbackfn);\r\n }\r\n\r\n get(key: string): NgHttpCachingEntry | undefined {\r\n return this.store.get(key);\r\n }\r\n\r\n has(key: string): boolean {\r\n return this.store.has(key);\r\n }\r\n\r\n set(key: string, value: NgHttpCachingEntry): void {\r\n this.store.set(key, value);\r\n }\r\n}\r\n","import { Injectable, InjectionToken, Inject, Optional } from '@angular/core';\r\nimport { HttpRequest, HttpResponse, HttpEvent } from '@angular/common/http';\r\nimport { Observable } from 'rxjs/internal/Observable';\r\nimport { NgHttpCachingStorageInterface } from './storage/ng-http-caching-storage.interface';\r\nimport { NgHttpCachingMemoryStorage } from './storage/ng-http-caching-memory-storage';\r\n\r\nexport interface NgHttpCachingEntry {\r\n url: string;\r\n response: HttpResponse<any>;\r\n request: HttpRequest<any>;\r\n addedTime: number;\r\n}\r\n\r\nexport const NG_HTTP_CACHING_CONFIG = new InjectionToken<NgHttpCachingConfig>(\r\n 'ng-http-caching.config'\r\n);\r\n\r\nexport enum NgHttpCachingStrategy {\r\n // eslint-disable-next-line no-unused-vars\r\n ALLOW_ALL = 'ALLOW_ALL',\r\n // eslint-disable-next-line no-unused-vars\r\n DISALLOW_ALL = 'DISALLOW_ALL',\r\n}\r\n\r\nexport enum NgHttpCachingHeaders {\r\n // eslint-disable-next-line no-unused-vars\r\n ALLOW_CACHE = 'X-NG-HTTP-CACHING-ALLOW-CACHE',\r\n // eslint-disable-next-line no-unused-vars\r\n DISALLOW_CACHE = 'X-NG-HTTP-CACHING-DISALLOW-CACHE',\r\n // eslint-disable-next-line no-unused-vars\r\n LIFETIME = 'X-NG-HTTP-CACHING-LIFETIME',\r\n // eslint-disable-next-line no-unused-vars\r\n TAG = 'X-NG-HTTP-CACHING-TAG',\r\n}\r\nexport interface NgHttpCachingConfig {\r\n store?: NgHttpCachingStorageInterface;\r\n lifetime?: number;\r\n allowedMethod?: string[];\r\n cacheStrategy?: NgHttpCachingStrategy;\r\n // eslint-disable-next-line no-unused-vars\r\n isExpired?: (entry: NgHttpCachingEntry) => boolean | undefined;\r\n // eslint-disable-next-line no-unused-vars\r\n isCacheable?: (req: HttpRequest<any>) => boolean | undefined;\r\n // eslint-disable-next-line no-unused-vars\r\n getKey?: (req: HttpRequest<any>) => string | undefined;\r\n // eslint-disable-next-line no-unused-vars\r\n isValid?: (entry: NgHttpCachingEntry) => boolean | undefined;\r\n}\r\n\r\nexport const NgHttpCachingConfigDefault: NgHttpCachingConfig = {\r\n store: new NgHttpCachingMemoryStorage(),\r\n lifetime: 60 * 60 * 100,\r\n allowedMethod: ['GET'],\r\n cacheStrategy: NgHttpCachingStrategy.ALLOW_ALL,\r\n};\r\n\r\n@Injectable()\r\nexport class NgHttpCachingService {\r\n\r\n private queue = new Map<string, Observable<HttpEvent<any>>>();\r\n\r\n private config: NgHttpCachingConfig = NgHttpCachingConfigDefault;\r\n\r\n constructor(\r\n @Inject(NG_HTTP_CACHING_CONFIG) @Optional() config: NgHttpCachingConfig\r\n ) {\r\n if (config) {\r\n this.config = { ...NgHttpCachingConfigDefault, ...config };\r\n }\r\n }\r\n\r\n /**\r\n * Return the config\r\n */\r\n getConfig(): NgHttpCachingConfig {\r\n return this.config;\r\n }\r\n\r\n /**\r\n * Return the queue map\r\n */\r\n getQueue(): Map<string, Observable<HttpEvent<any>>> {\r\n return this.queue;\r\n }\r\n\r\n /**\r\n * Return the cache store\r\n */\r\n getStore(): NgHttpCachingStorageInterface {\r\n return this.config.store as NgHttpCachingStorageInterface;\r\n }\r\n\r\n /**\r\n * Return response from cache\r\n */\r\n getFromCache(req: HttpRequest<any>): HttpResponse<any> | undefined {\r\n const key: string = this.getKey(req);\r\n const cached: NgHttpCachingEntry | undefined = this.config.store?.get(key);\r\n\r\n if (!cached) {\r\n return undefined;\r\n }\r\n\r\n if (this.isExpired(cached)) {\r\n this.clearCacheByKey(key);\r\n return undefined;\r\n }\r\n\r\n return cached.response;\r\n }\r\n\r\n /**\r\n * Add response to cache\r\n */\r\n addToCache(req: HttpRequest<any>, res: HttpResponse<any>): boolean {\r\n const key: string = this.getKey(req);\r\n const entry: NgHttpCachingEntry = {\r\n url: req.urlWithParams,\r\n response: res,\r\n request: req,\r\n addedTime: Date.now(),\r\n };\r\n if (this.isValid(entry)) {\r\n this.config.store?.set(key, entry);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Delete response from cache\r\n */\r\n deleteFromCache(req: HttpRequest<any>): boolean {\r\n const key: string = this.getKey(req);\r\n return this.clearCacheByKey(key);\r\n }\r\n\r\n /**\r\n * Clear the cache\r\n */\r\n clearCache(): void {\r\n this.config.store?.clear();\r\n }\r\n\r\n /**\r\n * Clear the cache by key\r\n */\r\n clearCacheByKey(key: string): boolean {\r\n return (this.config.store as NgHttpCachingStorageInterface).delete(key);\r\n }\r\n\r\n /**\r\n * Clear the cache by regex\r\n */\r\n clearCacheByRegex(regex: RegExp): void {\r\n (this.config.store as NgHttpCachingStorageInterface).forEach((entry: NgHttpCachingEntry, key: string) => {\r\n if (regex.test(key)) {\r\n this.clearCacheByKey(key);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Clear the cache by TAG\r\n */\r\n clearCacheByTag(tag: string): void {\r\n (this.config.store as NgHttpCachingStorageInterface).forEach((entry: NgHttpCachingEntry, key: string) => {\r\n const tagHeader = entry.request.headers.get(NgHttpCachingHeaders.TAG);\r\n if (tagHeader && tagHeader.split(',').includes(tag)) {\r\n this.clearCacheByKey(key);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Run garbage collector (delete expired cache entry)\r\n */\r\n runGc(): void {\r\n (this.config.store as NgHttpCachingStorageInterface).forEach((entry: NgHttpCachingEntry, key: string) => {\r\n if (this.isExpired(entry)) {\r\n this.clearCacheByKey(key);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Return true if cache entry is expired\r\n */\r\n isExpired(entry: NgHttpCachingEntry): boolean {\r\n // if user provide custom method, use it\r\n if (typeof this.config.isExpired === 'function') {\r\n const result = this.config.isExpired(entry);\r\n // if result is undefined, normal behaviour is provided\r\n if (typeof result !== 'undefined') {\r\n return result;\r\n }\r\n }\r\n // config/default lifetime\r\n let lifetime = this.config.lifetime;\r\n // request has own lifetime\r\n if (entry.request.headers.has(NgHttpCachingHeaders.LIFETIME)) {\r\n lifetime = +(entry.request.headers.get(NgHttpCachingHeaders.LIFETIME) || '');\r\n }\r\n // never expire if 0\r\n if (lifetime === 0) {\r\n return false;\r\n }\r\n // wrong lifetime\r\n if ((lifetime as number) < 0) {\r\n throw new Error('lifetime must be greater than or equal 0');\r\n }\r\n return entry.addedTime + (lifetime as number) < Date.now();\r\n }\r\n\r\n /**\r\n * Return true if cache entry is valid for store in the cache\r\n */\r\n isValid(entry: NgHttpCachingEntry): boolean {\r\n // if user provide custom method, use it\r\n if (typeof this.config.isValid === 'function') {\r\n const result = this.config.isValid(entry);\r\n // if result is undefined, normal behaviour is provided\r\n if (typeof result !== 'undefined') {\r\n return result;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * Return true if the request is cacheable\r\n */\r\n isCacheable(req: HttpRequest<any>): boolean {\r\n // if user provide custom method, use it\r\n if (typeof this.config.isCacheable === 'function') {\r\n const result = this.config.isCacheable(req);\r\n // if result is undefined, normal behaviour is provided\r\n if (typeof result !== 'undefined') {\r\n return result;\r\n }\r\n }\r\n // request has disallow cache header\r\n if (req.headers.has(NgHttpCachingHeaders.DISALLOW_CACHE)) {\r\n return false;\r\n }\r\n // strategy is disallow all...\r\n if (this.config.cacheStrategy === NgHttpCachingStrategy.DISALLOW_ALL) {\r\n // request isn't allowed if come without allow header\r\n if (!req.headers.has(NgHttpCachingHeaders.ALLOW_CACHE)) {\r\n return false;\r\n }\r\n }\r\n // if allowed method is only ALL, allow all http methos\r\n if (this.config.allowedMethod) {\r\n if (this.config.allowedMethod.length === 1) {\r\n if (this.config.allowedMethod[0] === 'ALL') {\r\n return true;\r\n }\r\n }\r\n // request is allowed if method is in allowedMethod\r\n return this.config.allowedMethod.indexOf(req.method) !== -1;\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * Return the cache key\r\n */\r\n getKey(req: HttpRequest<any>): string {\r\n // if user provide custom method, use it\r\n if (typeof this.config.getKey === 'function') {\r\n const result = this.config.getKey(req);\r\n // if result is undefined, normal behaviour is provided\r\n if (typeof result !== 'undefined') {\r\n return result;\r\n }\r\n }\r\n // default key id is url with query parameters\r\n return req.urlWithParams;\r\n }\r\n\r\n /**\r\n * Return observable from cache\r\n */\r\n getFromQueue(req: HttpRequest<any>): Observable<HttpEvent<any>> | undefined {\r\n const key: string = this.getKey(req);\r\n const cached: Observable<HttpEvent<any>> | undefined = this.queue.get(key);\r\n\r\n if (!cached) {\r\n return undefined;\r\n }\r\n\r\n return cached;\r\n }\r\n\r\n /**\r\n * Add observable to cache\r\n */\r\n addToQueue(req: HttpRequest<any>, obs: Observable<HttpEvent<any>>): void {\r\n const key: string = this.getKey(req);\r\n this.queue.set(key, obs);\r\n }\r\n\r\n /**\r\n * Delete observable from cache\r\n */\r\n deleteFromQueue(req: HttpRequest<any>): boolean {\r\n const key: string = this.getKey(req);\r\n return this.queue.delete(key);\r\n }\r\n}\r\n","import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Observable, of } from 'rxjs';\nimport { tap, finalize, share } from 'rxjs/operators';\nimport { NgHttpCachingService, NgHttpCachingHeaders } from './ng-http-caching.service';\n\n\n@Injectable()\nexport class NgHttpCachingInterceptorService implements HttpInterceptor {\n\n // eslint-disable-next-line no-unused-vars\n constructor(private readonly cacheService: NgHttpCachingService) {}\n\n intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\n // run garbage collector\n this.cacheService.runGc();\n\n // Don't cache if it's not cacheable\n if ( !this.cacheService.isCacheable(req) ) {\n return this.sendRequest(req, next);\n }\n\n // Checked if there is pending response for this request\n const cachedObservable: Observable<HttpEvent<any>> | undefined = this.cacheService.getFromQueue(req);\n if ( cachedObservable ) {\n // console.log('cachedObservable', req);\n return cachedObservable;\n }\n\n // Checked if there is cached response for this request\n const cachedResponse: HttpResponse<any> | undefined = this.cacheService.getFromCache(req);\n if (cachedResponse) {\n // console.log('cachedResponse', req);\n return of(cachedResponse.clone());\n }\n\n // If the request of going through for first time\n // then let the request proceed and cache the response\n // console.log('sendRequest', req);\n const shared = this.sendRequest(req, next).pipe(\n tap(event => {\n if (event instanceof HttpResponse) {\n this.cacheService.addToCache(req, event.clone());\n }\n }),\n finalize(() => {\n // delete pending request\n this.cacheService.deleteFromQueue(req);\n }),\n share()\n );\n\n // add pending request to queue for cache parallell request\n this.cacheService.addToQueue(req, shared);\n\n return shared;\n }\n\n /**\n * Send http request (next handler)\n */\n sendRequest(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\n let cloned: HttpRequest<any> = req.clone();\n // trim custom headers before send request\n Object.values(NgHttpCachingHeaders).forEach(ngHttpCachingHeaders => {\n if ( cloned.headers.has(ngHttpCachingHeaders) ) {\n cloned = cloned.clone({ headers: cloned.headers.delete(ngHttpCachingHeaders) });\n }\n });\n return next.handle(cloned);\n }\n}\n","import { NgModule, ModuleWithProviders } from '@angular/core';\r\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport {\r\n NG_HTTP_CACHING_CONFIG,\r\n NgHttpCachingConfig,\r\n NgHttpCachingService,\r\n} from './ng-http-caching.service';\r\nimport { NgHttpCachingInterceptorService } from './ng-http-caching-interceptor.service';\r\n\r\n@NgModule({\r\n declarations: [],\r\n imports: [],\r\n providers: [\r\n NgHttpCachingService,\r\n {\r\n provide: HTTP_INTERCEPTORS,\r\n useClass: NgHttpCachingInterceptorService,\r\n multi: true,\r\n },\r\n ],\r\n exports: [],\r\n})\r\nexport class NgHttpCachingModule {\r\n static forRoot(\r\n ngHttpCachingConfig?: NgHttpCachingConfig\r\n ): ModuleWithProviders<NgHttpCachingModule> {\r\n return {\r\n ngModule: NgHttpCachingModule,\r\n providers: [\r\n {\r\n provide: NG_HTTP_CACHING_CONFIG,\r\n useValue: ngHttpCachingConfig,\r\n },\r\n ],\r\n };\r\n }\r\n}\r\n","import { NgHttpCachingStorageInterface } from './ng-http-caching-storage.interface';\r\nimport { NgHttpCachingEntry } from '../ng-http-caching.service';\r\nimport { HttpHeaders, HttpParams, HttpRequest, HttpResponse } from '@angular/common/http';\r\n\r\nconst KEY_PREFIX = 'NgHttpCaching::';\r\n\r\nfunction serializeRequest(req: HttpRequest<any>): string {\r\n const request = req.clone(); // Make a clone, useful for doing destructive things\r\n return JSON.stringify({\r\n headers: Object.fromEntries( // Just a helper to make this into an object, not really required but makes the output nicer\r\n request.headers.keys().map( // Get all of the headers\r\n (key: string) => [key, request.headers.getAll(key)] // Get all of the corresponding values for the headers\r\n )\r\n ),\r\n method: request.method, // The Request Method, e.g. GET, POST, DELETE\r\n url: request.url, // The URL\r\n params: Object.fromEntries( // Just a helper to make this into an object, not really required but makes the output nicer\r\n request.headers.keys().map( // Get all of the headers\r\n (key: string) => [key, request.headers.getAll(key)] // Get all of the corresponding values for the headers\r\n )\r\n ), // The request parameters\r\n withCredentials: request.withCredentials, // Whether credentials are being sent\r\n respnseType: request.responseType, // The response type\r\n body: request.serializeBody() // Serialize the body, all well and good since we are working on a clone\r\n });\r\n}\r\n\r\nfunction serializeResponse(res: HttpResponse<any>): string {\r\n const response = res.clone();\r\n return JSON.stringify({\r\n headers: Object.fromEntries( // Just a helper to make this into an object, not really required but makes the output nicer\r\n response.headers.keys().map( // Get all of the headers\r\n (key: string) => [key, response.headers.getAll(key)] // Get all of the corresponding values for the headers\r\n )\r\n ),\r\n status: response.status,\r\n statusText: response.statusText,\r\n url: response.url,\r\n body: response // Serialize the body, all well and good since we are working on a clone\r\n });\r\n}\r\n\r\nfunction deserializeRequest<T = any>(req: string): HttpRequest<T> {\r\n const request = JSON.parse(req);\r\n const headers = new HttpHeaders(request.headers);\r\n const params = new HttpParams(); // Probably some way to make this a one-liner, but alas, there are no good docs\r\n // tslint:disable-next-line: forin\r\n for (const parameter in request.params) {\r\n request.params[parameter].forEach((paramValue: string) => params.append(parameter, paramValue));\r\n }\r\n return new HttpRequest(request.method, request.url, request.body, {\r\n headers,\r\n params,\r\n responseType: request.responseType,\r\n withCredentials: request.withCredentials\r\n });\r\n}\r\n\r\nfunction deserializeResponse<T = any>(res: string): HttpResponse<T> {\r\n const response = JSON.parse(res);\r\n return new HttpResponse<T>({\r\n url: response.url,\r\n headers: new HttpHeaders(response.headers),\r\n body: response.body,\r\n status: response.status,\r\n statusText: response.statusText,\r\n });\r\n}\r\n\r\nexport class NgHttpCachingLocalStorage implements NgHttpCachingStorageInterface {\r\n\r\n get size(): number {\r\n let count = 0;\r\n for (let i = 0, e = localStorage.length; i < e; i++) {\r\n const key = localStorage.key(i);\r\n if (key && key.startsWith(KEY_PREFIX)) {\r\n count++;\r\n }\r\n }\r\n return count;\r\n }\r\n\r\n clear(): void {\r\n for (let i = 0, e = localStorage.length; i < e; i++) {\r\n const key = localStorage.key(i);\r\n if (key && key.startsWith(KEY_PREFIX)) {\r\n localStorage.removeItem(key);\r\n }\r\n }\r\n }\r\n\r\n delete(key: string): boolean {\r\n localStorage.removeItem(KEY_PREFIX + key);\r\n return true;\r\n }\r\n\r\n // eslint-disable-next-line no-unused-vars\r\n forEach(callbackfn: (value: NgHttpCachingEntry, key: string) => void): void {\r\n // iterate localStorage\r\n const lenPrefix = KEY_PREFIX.length;\r\n for (let i = 0, e = localStorage.length; i < e; i++) {\r\n const key = localStorage.key(i);\r\n if (key && key.startsWith(KEY_PREFIX)) {\r\n const value = this.get(key.substring(lenPrefix));\r\n if (value) {\r\n callbackfn(value, key);\r\n }\r\n }\r\n }\r\n }\r\n\r\n get(key: string): NgHttpCachingEntry | undefined {\r\n const item = localStorage.getItem(KEY_PREFIX + key);\r\n if (item) {\r\n const parsedItem: NgHttpCachingEntry = JSON.parse(item);\r\n return {\r\n url: parsedItem.url,\r\n response: deserializeResponse(parsedItem.response as unknown as string),\r\n request: deserializeRequest(parsedItem.request as unknown as string),\r\n addedTime: parsedItem.addedTime\r\n };\r\n }\r\n return undefined;\r\n }\r\n\r\n has(key: string): boolean {\r\n return localStorage.getItem(KEY_PREFIX + key) !== undefined;\r\n }\r\n\r\n set(key: string, value: NgHttpCachingEntry): void {\r\n localStorage.setItem(KEY_PREFIX + key, JSON.stringify({\r\n url: value.url,\r\n response: serializeResponse(value.response),\r\n request: serializeRequest(value.request),\r\n addedTime: value.addedTime\r\n }));\r\n }\r\n}\r\n","/*\r\n * Public API Surface of ng-http-caching\r\n */\r\n\r\nexport * from './lib/ng-http-caching-interceptor.service';\r\nexport * from './lib/ng-http-caching.service';\r\nexport * from './lib/ng-http-caching.module';\r\nexport * from './lib/storage/ng-http-caching-storage.interface';\r\nexport * from './lib/storage/ng-http-caching-memory-storage';\r\nexport * from './lib/storage/ng-http-caching-local-storage';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;MAGa,0BAA0B;IAAvC;QAMY,UAAK,GAAG,IAAI,GAAG,EAA8B,CAAC;KA0BzD;IA9BG,IAAI,IAAI;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;KAC1B;IAID,KAAK;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;KACtB;IAED,MAAM,CAAC,GAAW;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KACjC;;IAGD,OAAO,CAAC,UAA4D;QAChE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;KACzC;IAED,GAAG,CAAC,GAAW;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;KAC9B;IAED,GAAG,CAAC,GAAW;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;KAC9B;IAED,GAAG,CAAC,GAAW,EAAE,KAAyB;QACtC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;KAC9B;;;MCrBQ,sBAAsB,GAAG,IAAI,cAAc,CACtD,wBAAwB,EACxB;IAEU;AAAZ,WAAY,qBAAqB;;IAE/B,gDAAuB,CAAA;;IAEvB,sDAA6B,CAAA;AAC/B,CAAC,EALW,qBAAqB,KAArB,qBAAqB,QAKhC;IAEW;AAAZ,WAAY,oBAAoB;;IAE9B,qEAA6C,CAAA;;IAE7C,2EAAmD,CAAA;;IAEnD,+DAAuC,CAAA;;IAEvC,qDAA6B,CAAA;AAC/B,CAAC,EATW,oBAAoB,KAApB,oBAAoB,QAS/B;MAgBY,0BAA0B,GAAwB;IAC7D,KAAK,EAAE,IAAI,0BAA0B,EAAE;IACvC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG;IACvB,aAAa,EAAE,CAAC,KAAK,CAAC;IACtB,aAAa,EAAE,qBAAqB,CAAC,SAAS;EAC9C;MAGW,oBAAoB;IAM/B,YAC8C,MAA2B;QALjE,UAAK,GAAG,IAAI,GAAG,EAAsC,CAAC;QAEtD,WAAM,GAAwB,0BAA0B,CAAC;QAK/D,IAAI,MAAM,EAAE;YACV,IAAI,CAAC,MAAM,mCAAQ,0BAA0B,GAAK,MAAM,CAAE,CAAC;SAC5D;KACF;;;;IAKD,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;KACpB;;;;IAKD,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;KACnB;;;;IAKD,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,KAAsC,CAAC;KAC3D;;;;IAKD,YAAY,CAAC,GAAqB;;QAChC,MAAM,GAAG,GAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,GAAmC,MAAA,IAAI,CAAC,MAAM,CAAC,KAAK,0CAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAE3E,IAAI,CAAC,MAAM,EAAE;YACX,OAAO,SAAS,CAAC;SAClB;QAED,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;YAC1B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO,SAAS,CAAC;SAClB;QAED,OAAO,MAAM,CAAC,QAAQ,CAAC;KACxB;;;;IAKD,UAAU,CAAC,GAAqB,EAAE,GAAsB;;QACtD,MAAM,GAAG,GAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,KAAK,GAAuB;YAChC,GAAG,EAAE,GAAG,CAAC,aAAa;YACtB,QAAQ,EAAE,GAAG;YACb,OAAO,EAAE,GAAG;YACZ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QACF,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACvB,MAAA,IAAI,CAAC,MAAM,CAAC,KAAK,0CAAE,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnC,OAAO,IAAI,CAAC;SACb;QACD,OAAO,KAAK,CAAC;KACd;;;;IAKD,eAAe,CAAC,GAAqB;QACnC,MAAM,GAAG,GAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;KAClC;;;;IAKD,UAAU;;QACR,MAAA,IAAI,CAAC,MAAM,CAAC,KAAK,0CAAE,KAAK,EAAE,CAAC;KAC5B;;;;IAKD,eAAe,CAAC,GAAW;QACzB,OAAQ,IAAI,CAAC,MAAM,CAAC,KAAuC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KACzE;;;;IAKD,iBAAiB,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAuC,CAAC,OAAO,CAAC,CAAC,KAAyB,EAAE,GAAW;YAClG,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;gBACnB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;aAC3B;SACF,CAAC,CAAC;KACJ;;;;IAKD,eAAe,CAAC,GAAW;QACxB,IAAI,CAAC,MAAM,CAAC,KAAuC,CAAC,OAAO,CAAC,CAAC,KAAyB,EAAE,GAAW;YAClG,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;YACtE,IAAI,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;gBACnD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;aAC3B;SACF,CAAC,CAAC;KACJ;;;;IAKD,KAAK;QACF,IAAI,CAAC,MAAM,CAAC,KAAuC,CAAC,OAAO,CAAC,CAAC,KAAyB,EAAE,GAAW;YAClG,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;gBACzB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;aAC3B;SACF,CAAC,CAAC;KACJ;;;;IAKD,SAAS,CAAC,KAAyB;;QAEjC,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,UAAU,EAAE;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;;YAE5C,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;gBACjC,OAAO,MAAM,CAAC;aACf;SACF;;QAED,IAAI,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;;QAEpC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE;YAC5D,QAAQ,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;SAC9E;;QAED,IAAI,QAAQ,KAAK,CAAC,EAAE;YAClB,OAAO,KAAK,CAAC;SACd;;QAED,IAAK,QAAmB,GAAG,CAAC,EAAE;YAC5B,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;SAC7D;QACD,OAAO,KAAK,CAAC,SAAS,GAAI,QAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;KAC5D;;;;IAKD,OAAO,CAAC,KAAyB;;QAE/B,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE;YAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;;YAE1C,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;gBACjC,OAAO,MAAM,CAAC;aACf;SACF;QACD,OAAO,IAAI,CAAC;KACb;;;;IAKD,WAAW,CAAC,GAAqB;;QAE/B,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,UAAU,EAAE;YACjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;;YAE5C,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;gBACjC,OAAO,MAAM,CAAC;aACf;SACF;;QAED,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,cAAc,CAAC,EAAE;YACxD,OAAO,KAAK,CAAC;SACd;;QAED,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,KAAK,qBAAqB,CAAC,YAAY,EAAE;;YAEpE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,WAAW,CAAC,EAAE;gBACtD,OAAO,KAAK,CAAC;aACd;SACF;;QAED,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE;YAC7B,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;gBAC1C,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE;oBAC1C,OAAO,IAAI,CAAC;iBACb;aACF;;YAED,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;SAC7D;QACD,OAAO,IAAI,CAAC;KACb;;;;IAKD,MAAM,CAAC,GAAqB;;QAE1B,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE;YAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;;YAEvC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;gBACjC,OAAO,MAAM,CAAC;aACf;SACF;;QAED,OAAO,GAAG,CAAC,aAAa,CAAC;KAC1B;;;;IAKD,YAAY,CAAC,GAAqB;QAChC,MAAM,GAAG,GAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,GAA2C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE3E,IAAI,CAAC,MAAM,EAAE;YACX,OAAO,SAAS,CAAC;SAClB;QAED,OAAO,MAAM,CAAC;KACf;;;;IAKD,UAAU,CAAC,GAAqB,EAAE,GAA+B;QAC/D,MAAM,GAAG,GAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;KAC1B;;;;IAKD,eAAe,CAAC,GAAqB;QACnC,MAAM,GAAG,GAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KAC/B;;iHA5PU,oBAAoB,kBAOrB,sBAAsB;qHAPrB,oBAAoB;2FAApB,oBAAoB;kBADhC,UAAU;;;8BAQN,MAAM;+BAAC,sBAAsB;;8BAAG,QAAQ;;;;MCxDhC,+BAA+B;;IAG1C,YAA6B,YAAkC;QAAlC,iBAAY,GAAZ,YAAY,CAAsB;KAAI;IAEnE,SAAS,CAAC,GAAqB,EAAE,IAAiB;;QAEhD,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;;QAG1B,IAAK,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,EAAG;YACzC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;SACpC;;QAGD,MAAM,gBAAgB,GAA2C,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACrG,IAAK,gBAAgB,EAAG;;YAEtB,OAAO,gBAAgB,CAAC;SACzB;;QAGD,MAAM,cAAc,GAAkC,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAC1F,IAAI,cAAc,EAAE;;YAElB,OAAO,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;SACnC;;;;QAKD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAC7C,GAAG,CAAC,KAAK;YACP,IAAI,KAAK,YAAY,YAAY,EAAE;gBACjC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;aAClD;SACF,CAAC,EACF,QAAQ,CAAC;;YAEP,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;SACxC,CAAC,EACF,KAAK,EAAE,CACR,CAAC;;QAGF,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAE1C,OAAO,MAAM,CAAC;KACf;;;;IAKD,WAAW,CAAC,GAAqB,EAAE,IAAiB;QAClD,IAAI,MAAM,GAAqB,GAAG,CAAC,KAAK,EAAE,CAAC;;QAE3C,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,oBAAoB;YAC9D,IAAK,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAG;gBAC9C,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;aACjF;SACF,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;KAC5B;;4HA9DU,+BAA+B;gIAA/B,+BAA+B;2FAA/B,+BAA+B;kBAD3C,UAAU;;;MCeE,mBAAmB;IAC9B,OAAO,OAAO,CACZ,mBAAyC;QAEzC,OAAO;YACL,QAAQ,EAAE,mBAAmB;YAC7B,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,sBAAsB;oBAC/B,QAAQ,EAAE,mBAAmB;iBAC9B;aACF;SACF,CAAC;KACH;;gHAbU,mBAAmB;iHAAnB,mBAAmB;iHAAnB,mBAAmB,aAVnB;QACT,oBAAoB;QACpB;YACE,OAAO,EAAE,iBAAiB;YAC1B,QAAQ,EAAE,+BAA+B;YACzC,KAAK,EAAE,IAAI;SACZ;KACF,YARQ,EAAE;2FAWA,mBAAmB;kBAb/B,QAAQ;mBAAC;oBACR,YAAY,EAAE,EAAE;oBAChB,OAAO,EAAE,EAAE;oBACX,SAAS,EAAE;wBACT,oBAAoB;wBACpB;4BACE,OAAO,EAAE,iBAAiB;4BAC1B,QAAQ,EAAE,+BAA+B;4BACzC,KAAK,EAAE,IAAI;yBACZ;qBACF;oBACD,OAAO,EAAE,EAAE;iBACZ;;;ACjBD,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC,SAAS,gBAAgB,CAAC,GAAqB;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IAC5B,OAAO,IAAI,CAAC,SAAS,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC,WAAW;QACvB,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG;QACtB,CAAC,GAAW,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;SACtD,CACJ;QACD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,MAAM,EAAE,MAAM,CAAC,WAAW;QACtB,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG;QACtB,CAAC,GAAW,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;SACtD,CACJ;QACD,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,WAAW,EAAE,OAAO,CAAC,YAAY;QACjC,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE;KAChC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAsB;IAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IAC7B,OAAO,IAAI,CAAC,SAAS,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC,WAAW;QACvB,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG;QACvB,CAAC,GAAW,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;SACvD,CACJ;QACD,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,IAAI,EAAE,QAAQ;KACjB,CAAC,CAAC;AACP,CAAC;AAED,SAAS,kBAAkB,CAAU,GAAW;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;;IAEhC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE;QACpC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,UAAkB,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;KACnG;IACD,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE;QAC9D,OAAO;QACP,MAAM;QACN,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,eAAe,EAAE,OAAO,CAAC,eAAe;KAC3C,CAAC,CAAC;AACP,CAAC;AAED,SAAS,mBAAmB,CAAU,GAAW;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,IAAI,YAAY,CAAI;QACvB,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,OAAO,EAAE,IAAI,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC1C,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;KAClC,CAAC,CAAC;AACP,CAAC;MAEY,yBAAyB;IAElC,IAAI,IAAI;QACJ,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YACjD,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;gBACnC,KAAK,EAAE,CAAC;aACX;SACJ;QACD,OAAO,KAAK,CAAC;KAChB;IAED,KAAK;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YACjD,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;gBACnC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;aAChC;SACJ;KACJ;IAED,MAAM,CAAC,GAAW;QACd,YAAY,CAAC,UAAU,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;KACf;;IAGD,OAAO,CAAC,UAA4D;;QAEhE,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YACjD,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;gBACnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;gBACjD,IAAI,KAAK,EAAE;oBACP,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;iBAC1B;aACJ;SACJ;KACJ;IAED,GAAG,CAAC,GAAW;QACX,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;QACpD,IAAI,IAAI,EAAE;YACN,MAAM,UAAU,GAAuB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxD,OAAO;gBACH,GAAG,EAAE,UAAU,CAAC,GAAG;gBACnB,QAAQ,EAAE,mBAAmB,CAAC,UAAU,CAAC,QAA6B,CAAC;gBACvE,OAAO,EAAE,kBAAkB,CAAC,UAAU,CAAC,OAA4B,CAAC;gBACpE,SAAS,EAAE,UAAU,CAAC,SAAS;aAClC,CAAC;SACL;QACD,OAAO,SAAS,CAAC;KACpB;IAED,GAAG,CAAC,GAAW;QACX,OAAO,YAAY,CAAC,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC,KAAK,SAAS,CAAC;KAC/D;IAED,GAAG,CAAC,GAAW,EAAE,KAAyB;QACtC,YAAY,CAAC,OAAO,CAAC,UAAU,GAAG,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC;YAClD,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,QAAQ,EAAE,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC3C,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC;YACxC,SAAS,EAAE,KAAK,CAAC,SAAS;SAC7B,CAAC,CAAC,CAAC;KACP;;;ACxIL;;;;ACAA;;;;;;"}