ng-simple-state 17.0.2 → 17.0.4

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/README.md CHANGED
@@ -11,17 +11,15 @@ See the demos:
11
11
  - [Tour of heroes](https://stackblitz.com/edit/ng-simple-state-tour-of-heroes?file=src%2Fapp%2Fhero.service.ts)
12
12
  - [To Do List](https://stackblitz.com/edit/ng-simple-state-todo?file=src%2Fapp%2Fapp.component.ts)
13
13
 
14
- ## RxJS Store
15
-
16
- ### Get Started
14
+ ## Get Started
17
15
 
18
- #### Step 1: install `ng-simple-state`
16
+ ### Step 1: install `ng-simple-state`
19
17
 
20
18
  ```bash
21
19
  npm i ng-simple-state
22
20
  ```
23
21
 
24
- #### Step 2: Import `NgSimpleStateModule` into your `AppModule`
22
+ ### Step 2: Import `NgSimpleStateModule` into your `AppModule`
25
23
 
26
24
  `NgSimpleStateModule` has some global optional config defined by `NgSimpleStateConfig` interface:
27
25
 
@@ -57,7 +55,14 @@ import { environment } from '../environments/environment';
57
55
  export class AppModule {}
58
56
  ```
59
57
 
60
- #### Step 3: Create your store
58
+ ### Step 3: Chose your store
59
+
60
+ There are two type of store `NgSimpleStateBaseRxjsStore` based on RxJS `BehaviorSubject` and `NgSimpleStateBaseSignalStore` based on Angular `Signal`:
61
+
62
+ - [RxJS Store](#rxjs-store)
63
+ - [Signal Store](#signal-store)
64
+
65
+ ## RxJS Store
61
66
 
62
67
  This is an example for a counter store in a `src/app/counter-store.ts` file.
63
68
  Obviously, you can create every store you want with every complexity you need.
@@ -70,18 +75,18 @@ export interface CounterState {
70
75
  }
71
76
  ```
72
77
 
73
- 2) Define your store service by extending `NgSimpleStateBaseStore`, eg.:
78
+ 2) Define your store service by extending `NgSimpleStateBaseRxjsStore`, eg.:
74
79
 
75
80
  ```ts
76
81
  import { Injectable } from '@angular/core';
77
- import { NgSimpleStateBaseStore } from 'ng-simple-state';
82
+ import { NgSimpleStateBaseRxjsStore } from 'ng-simple-state';
78
83
 
79
84
  export interface CounterState {
80
85
  count: number;
81
86
  }
82
87
 
83
88
  @Injectable()
84
- export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
89
+ export class CounterStore extends NgSimpleStateBaseRxjsStore<CounterState> {
85
90
 
86
91
  }
87
92
  ```
@@ -90,14 +95,14 @@ export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
90
95
 
91
96
  ```ts
92
97
  import { Injectable } from '@angular/core';
93
- import { NgSimpleStateBaseStore, NgSimpleStateStoreConfig } from 'ng-simple-state';
98
+ import { NgSimpleStateBaseRxjsStore, NgSimpleStateStoreConfig } from 'ng-simple-state';
94
99
 
95
100
  export interface CounterState {
96
101
  count: number;
97
102
  }
98
103
 
99
104
  @Injectable()
100
- export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
105
+ export class CounterStore extends NgSimpleStateBaseRxjsStore<CounterState> {
101
106
 
102
107
  storeConfig(): NgSimpleStateStoreConfig {
103
108
  return {
@@ -118,7 +123,7 @@ export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
118
123
 
119
124
  ```ts
120
125
  import { Injectable } from '@angular/core';
121
- import { NgSimpleStateBaseStore, NgSimpleStateStoreConfig } from 'ng-simple-state';
126
+ import { NgSimpleStateBaseRxjsStore, NgSimpleStateStoreConfig } from 'ng-simple-state';
122
127
  import { Observable } from 'rxjs';
123
128
 
124
129
  export interface CounterState {
@@ -126,7 +131,7 @@ export interface CounterState {
126
131
  }
127
132
 
128
133
  @Injectable()
129
- export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
134
+ export class CounterStore extends NgSimpleStateBaseRxjsStore<CounterState> {
130
135
 
131
136
  storeConfig(): NgSimpleStateStoreConfig {
132
137
  return {
@@ -150,7 +155,7 @@ export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
150
155
 
151
156
  ```ts
152
157
  import { Injectable } from '@angular/core';
153
- import { NgSimpleStateBaseStore, NgSimpleStateStoreConfig } from 'ng-simple-state';
158
+ import { NgSimpleStateBaseRxjsStore, NgSimpleStateStoreConfig } from 'ng-simple-state';
154
159
  import { Observable } from 'rxjs';
155
160
 
156
161
  export interface CounterState {
@@ -158,7 +163,7 @@ export interface CounterState {
158
163
  }
159
164
 
160
165
  @Injectable()
161
- export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
166
+ export class CounterStore extends NgSimpleStateBaseRxjsStore<CounterState> {
162
167
 
163
168
  storeConfig(): NgSimpleStateStoreConfig {
164
169
  return {
@@ -244,12 +249,12 @@ export class AppComponent {
244
249
 
245
250
  ### Manage component state without service
246
251
 
247
- If you want manage just a component state without make a new service, your component can extend directly `NgSimpleStateBaseStore`:
252
+ If you want manage just a component state without make a new service, your component can extend directly `NgSimpleStateBaseRxjsStore`:
248
253
 
249
254
  ```ts
250
255
  import { Component, Injector } from '@angular/core';
251
256
  import { CommonModule } from '@angular/common';
252
- import { NgSimpleStateBaseStore } from 'ng-simple-state';
257
+ import { NgSimpleStateBaseRxjsStore } from 'ng-simple-state';
253
258
  import { Observable } from 'rxjs';
254
259
 
255
260
  export interface CounterState {
@@ -264,7 +269,7 @@ export interface CounterState {
264
269
  <button (click)="decrement()">-</button>
265
270
  `
266
271
  })
267
- export class CounterComponent extends NgSimpleStateBaseStore<CounterState> {
272
+ export class CounterComponent extends NgSimpleStateBaseRxjsStore<CounterState> {
268
273
 
269
274
  public counter$: Observable<number> = this.selectState(state => state.count);
270
275
 
@@ -301,10 +306,10 @@ If you need to inject something into your store (eg. `HttpClient`), you need to
301
306
  ```ts
302
307
  import { Injectable, Injector } from '@angular/core';
303
308
  import { HttpClient } from '@angular/common/http';
304
- import { NgSimpleStateBaseStore } from 'ng-simple-state';
309
+ import { NgSimpleStateBaseRxjsStore } from 'ng-simple-state';
305
310
 
306
311
  @Injectable()
307
- export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
312
+ export class CounterStore extends NgSimpleStateBaseRxjsStore<CounterState> {
308
313
 
309
314
  constructor(injector: Injector, private http: HttpClient) {
310
315
  super(injector);
@@ -331,7 +336,7 @@ import { NgSimpleStateStoreConfig } from 'ng-simple-state';
331
336
 
332
337
 
333
338
  @Injectable()
334
- export class CounterStore extends NgSimpleStateBaseStore<CounterState> {
339
+ export class CounterStore extends NgSimpleStateBaseRxjsStore<CounterState> {
335
340
 
336
341
  override storeConfig(): NgSimpleStateStoreConfig {
337
342
  return {
@@ -410,7 +415,7 @@ This is an example for a todo list store in a `src/app/todo-store.ts` file.
410
415
 
411
416
  ```ts
412
417
  import { Injectable } from '@angular/core';
413
- import { NgSimpleStateBaseStore } from 'ng-simple-state';
418
+ import { NgSimpleStateBaseRxjsStore } from 'ng-simple-state';
414
419
  import { Observable } from 'rxjs';
415
420
 
416
421
  export interface Todo {
@@ -422,7 +427,7 @@ export interface Todo {
422
427
  export type TodoState = Array<Todo>;
423
428
 
424
429
  @Injectable()
425
- export class TodoStore extends NgSimpleStateBaseStore<TodoState> {
430
+ export class TodoStore extends NgSimpleStateBaseRxjsStore<TodoState> {
426
431
 
427
432
  storeConfig(): NgSimpleStateStoreConfig {
428
433
  return {
@@ -480,12 +485,12 @@ export class AppComponent {
480
485
  ```
481
486
 
482
487
 
483
- ### NgSimpleStateBaseStore API
488
+ ### NgSimpleStateBaseRxjsStore API
484
489
 
485
490
  ```ts
486
491
  @Injectable()
487
492
  @Directive()
488
- export abstract class NgSimpleStateBaseStore<S extends object | Array<any>> implements OnDestroy {
493
+ export abstract class NgSimpleStateBaseRxjsStore<S extends object | Array<any>> implements OnDestroy {
489
494
 
490
495
  /**
491
496
  * Return the observable of the state
@@ -558,51 +563,6 @@ export abstract class NgSimpleStateBaseStore<S extends object | Array<any>> impl
558
563
  ```
559
564
  ## Signal Store
560
565
 
561
- ### Get Started
562
-
563
- #### Step 1: install `ng-simple-state`
564
-
565
- ```bash
566
- npm i ng-simple-state
567
- ```
568
-
569
- #### Step 2: Import `NgSimpleStateModule` into your `AppModule`
570
-
571
- `NgSimpleStateModule` has some global optional config defined by `NgSimpleStateConfig` interface:
572
-
573
- | Option | Description | Default |
574
- | -------------------- | ----------------------------------------------------------------------------------------------- | ---------- |
575
- | *enableDevTool* | if `true` enable `Redux DevTools` browser extension for inspect the state of the store. | `false` |
576
- | *enableLocalStorage* | if `true` latest state of store is saved in local storage and reloaded on store initialization. | `false` |
577
- | *persistentStorage* | Set the persistent storage `local` or `session`. | `local` |
578
-
579
- _Side note: each store can be override the global configuration implementing `storeConfig()` method (see "Override global config")._
580
-
581
- ```ts
582
- import { BrowserModule } from '@angular/platform-browser';
583
- import { NgModule } from '@angular/core';
584
- import { AppComponent } from './app.component';
585
- import { CommonModule } from '@angular/common';
586
- import { NgSimpleStateModule } from 'ng-simple-state';
587
- import { environment } from '../environments/environment';
588
-
589
- @NgModule({
590
- declarations: [AppComponent],
591
- imports: [
592
- BrowserModule,
593
- CommonModule,
594
- NgSimpleStateModule.forRoot({
595
- enableDevTool: !environment.production, // Enable Redux DevTools only in development mode
596
- enableLocalStorage: false // Local storage state persistence is globally disabled
597
- })
598
- ],
599
- bootstrap: [AppComponent],
600
- })
601
- export class AppModule {}
602
- ```
603
-
604
- #### Step 3: Create your store
605
-
606
566
  This is an example for a counter store in a `src/app/counter-store.ts` file.
607
567
  Obviously, you can create every store you want with every complexity you need.
608
568
 
@@ -891,6 +851,7 @@ The options are defined by `NgSimpleStateStoreConfig` interface:
891
851
  | *enableLocalStorage* | if `true` latest state of store is saved in local storage and reloaded on store initialization. | `false` |
892
852
  | *storeName* | The name used into `Redux DevTools` and local storage key. | Class name |
893
853
  | *persistentStorage* | Set the persistent storage `local` or `session` | `local` |
854
+ | *comparator* | A function used to compare the previous and current state for equality. | `a === b` |
894
855
 
895
856
  ### Testing
896
857
 
@@ -1062,9 +1023,10 @@ export abstract class NgSimpleStateBaseSignalStore<S extends object | Array<any>
1062
1023
  /**
1063
1024
  * Select a store state
1064
1025
  * @param selectFn State selector (if not provided return full state)
1026
+ * @param comparator A function used to compare the previous and current state for equality. Defaults to a `===` check.
1065
1027
  * @returns Signal of the selected state
1066
1028
  */
1067
- selectState<K>(selectFn?: (state: Readonly<S>) => K): Signal<K>;
1029
+ selectState<K>(selectFn?: (state: Readonly<S>) => K, comparator?: (previous: K, current: K) => boolean): Signal<K>;
1068
1030
 
1069
1031
  /**
1070
1032
  * Return the current store state (snapshot)
@@ -0,0 +1,141 @@
1
+ import { Inject, Injectable, Injector, Directive, isDevMode } from '@angular/core';
2
+ import { NgSimpleStateDevTool } from './tool/ng-simple-state-dev-tool';
3
+ import { NgSimpleStateLocalStorage } from './storage/ng-simple-state-local-storage';
4
+ import { NG_SIMPLE_STORE_CONFIG } from './ng-simple-state-models';
5
+ import { NgSimpleStateSessionStorage } from './storage/ng-simple-state-session-storage';
6
+ import * as i0 from "@angular/core";
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ export class NgSimpleStateBaseCommonStore {
9
+ constructor(injector) {
10
+ this.devMode = isDevMode();
11
+ const globalConfig = injector.get(NG_SIMPLE_STORE_CONFIG, {});
12
+ const storeConfig = this.storeConfig() || {};
13
+ this.localStoreConfig = { ...globalConfig, ...storeConfig };
14
+ this.localStorageIsEnabled = typeof this.localStoreConfig.enableLocalStorage === 'boolean' ? this.localStoreConfig.enableLocalStorage : false;
15
+ if (this.localStorageIsEnabled) {
16
+ if (this.localStoreConfig.persistentStorage === 'local') {
17
+ this.persistentStorage = injector.get(NgSimpleStateLocalStorage);
18
+ }
19
+ else if (this.localStoreConfig.persistentStorage === 'session') {
20
+ this.persistentStorage = injector.get(NgSimpleStateSessionStorage);
21
+ }
22
+ }
23
+ this.devToolIsEnabled = typeof this.localStoreConfig.enableDevTool === 'boolean' ? this.localStoreConfig.enableDevTool : false;
24
+ if (this.devToolIsEnabled) {
25
+ this.devTool = injector.get(NgSimpleStateDevTool);
26
+ }
27
+ this.storeName = typeof this.localStoreConfig.storeName === 'string' ? this.localStoreConfig.storeName : this.constructor.name;
28
+ if (typeof this.localStoreConfig.comparator === 'function') {
29
+ this.comparator = this.localStoreConfig.comparator;
30
+ }
31
+ if (this.localStorageIsEnabled && this.persistentStorage) {
32
+ const firstState = this.persistentStorage.getItem(this.storeName);
33
+ if (firstState) {
34
+ this.firstState = firstState;
35
+ }
36
+ }
37
+ if (!this.firstState) {
38
+ this.firstState = this.initialState(injector);
39
+ }
40
+ this.devToolSend(this.firstState, `initialState`);
41
+ this.isArray = Array.isArray(this.firstState);
42
+ }
43
+ /**
44
+ * When you override this method, you have to call the `super.ngOnDestroy()` method in your `ngOnDestroy()` method.
45
+ */
46
+ ngOnDestroy() {
47
+ this.devToolSend(undefined, 'ngOnDestroy');
48
+ }
49
+ /**
50
+ * Return the first loaded store state:
51
+ * the last saved state, if `enableLocalStorage` config is `true`;
52
+ * otherwise the initial state provided from `initialState()` method.
53
+ * @returns The first state
54
+ */
55
+ getFirstState() {
56
+ return this.deepFreeze(this.firstState);
57
+ }
58
+ /**
59
+ * Reset store to first loaded store state:
60
+ * - the last saved state, if `enableLocalStorage` config is `true`
61
+ * - otherwise the initial state provided from `initialState()` method.
62
+ */
63
+ resetState() {
64
+ return this.setState(() => this.firstState, 'resetState');
65
+ }
66
+ /**
67
+ * Restart the store to initial state provided from `initialState()` method
68
+ */
69
+ restartState() {
70
+ return this.setState(() => this.initialState(), 'restartState');
71
+ }
72
+ /**
73
+ * Send to dev tool a new state
74
+ * @param newState new state
75
+ * @param actionName The action name
76
+ * @returns True if dev tools are enabled
77
+ */
78
+ devToolSend(newState, actionName) {
79
+ if (!this.devToolIsEnabled || !this.devTool) {
80
+ return false;
81
+ }
82
+ if (!actionName) {
83
+ // retrieve the parent (of parent) method into the stack trace
84
+ actionName = new Error().stack
85
+ ?.split('\n')[this.stackPoint]
86
+ .trim()
87
+ .split(' ')[1]
88
+ .split('.')[1] || 'unknown';
89
+ }
90
+ if (!this.devTool.send(this.storeName, actionName, newState)) {
91
+ console.log(this.storeName + '.' + actionName, newState);
92
+ }
93
+ return true;
94
+ }
95
+ /**
96
+ * Recursively Object.freeze simple Javascript structures consisting of plain objects, arrays, and primitives.
97
+ * Make the data immutable.
98
+ * @returns immutable object
99
+ */
100
+ deepFreeze(object) {
101
+ // No freezing in production (for better performance).
102
+ if (!this.devMode || !object) {
103
+ return object;
104
+ }
105
+ // When already frozen, we assume its children are frozen (for better performance).
106
+ // This should be true if you always use `deepFreeze` to freeze objects.
107
+ //
108
+ // Note that Object.isFrozen will also return `true` for primitives (numbers,
109
+ // strings, booleans, undefined, null), so there is no need to check for
110
+ // those explicitly.
111
+ if (Object.isFrozen(object)) {
112
+ return object;
113
+ }
114
+ // At this point we know that we're dealing with either an array or plain object, so
115
+ // just freeze it and recurse on its values.
116
+ Object.freeze(object);
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
+ Object.keys(object).forEach(key => this.deepFreeze(object[key]));
119
+ return object;
120
+ }
121
+ /**
122
+ * Persist state to storage
123
+ */
124
+ statePersist(state) {
125
+ if (this.localStorageIsEnabled && this.persistentStorage) {
126
+ this.persistentStorage.setItem(this.storeName, state);
127
+ }
128
+ }
129
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: NgSimpleStateBaseCommonStore, deps: [{ token: Injector }], target: i0.ɵɵFactoryTarget.Directive }); }
130
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.8", type: NgSimpleStateBaseCommonStore, ngImport: i0 }); }
131
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: NgSimpleStateBaseCommonStore }); }
132
+ }
133
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: NgSimpleStateBaseCommonStore, decorators: [{
134
+ type: Injectable
135
+ }, {
136
+ type: Directive
137
+ }], ctorParameters: () => [{ type: i0.Injector, decorators: [{
138
+ type: Inject,
139
+ args: [Injector]
140
+ }] }] });
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctc2ltcGxlLXN0YXRlLWNvbW1vbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25nLXNpbXBsZS1zdGF0ZS9zcmMvbGliL25nLXNpbXBsZS1zdGF0ZS1jb21tb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFhLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFOUYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdkUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDcEYsT0FBTyxFQUE0QixzQkFBc0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzVGLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDJDQUEyQyxDQUFDOztBQUl4Riw4REFBOEQ7QUFDOUQsTUFBTSxPQUFnQiw0QkFBNEI7SUFjOUMsWUFBOEIsUUFBa0I7UUFIdEMsWUFBTyxHQUFZLFNBQVMsRUFBRSxDQUFDO1FBS3JDLE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsc0JBQXNCLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDOUQsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUM3QyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxHQUFHLFlBQVksRUFBRSxHQUFHLFdBQVcsRUFBRSxDQUFDO1FBRTVELElBQUksQ0FBQyxxQkFBcUIsR0FBRyxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxrQkFBa0IsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBRTlJLElBQUksSUFBSSxDQUFDLHFCQUFxQixFQUFFO1lBQzVCLElBQUksSUFB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LENBQUM7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ08sWUFBWSxDQUFDLEtBQVE7UUFDM0IsSUFBSSxJQUFJLENBQUMscUJBQXFCLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQ3RELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztTQUM1RDtJQUNMLENBQUM7OEdBekxpQiw0QkFBNEIsa0JBYzFCLFFBQVE7a0dBZFYsNEJBQTRCO2tIQUE1Qiw0QkFBNEI7OzJGQUE1Qiw0QkFBNEI7a0JBSGpELFVBQVU7O2tCQUNWLFNBQVM7OzBCQWdCTyxNQUFNOzJCQUFDLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIEluamVjdG9yLCBPbkRlc3Ryb3ksIERpcmVjdGl2ZSwgaXNEZXZNb2RlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IE5nU2ltcGxlU3RhdGVCcm93c2VyU3RvcmFnZSB9IGZyb20gJy4vc3RvcmFnZS9uZy1zaW1wbGUtc3RhdGUtYnJvd3Nlci1zdG9yYWdlJztcclxuaW1wb3J0IHsgTmdTaW1wbGVTdGF0ZURldlRvb2wgfSBmcm9tICcuL3Rvb2wvbmctc2ltcGxlLXN0YXRlLWRldi10b29sJztcclxuaW1wb3J0IHsgTmdTaW1wbGVTdGF0ZUxvY2FsU3RvcmFnZSB9IGZyb20gJy4vc3RvcmFnZS9uZy1zaW1wbGUtc3RhdGUtbG9jYWwtc3RvcmFnZSc7XHJcbmltcG9ydCB7IE5nU2ltcGxlU3RhdGVTdG9yZUNvbmZpZywgTkdfU0lNUExFX1NUT1JFX0NPTkZJRyB9IGZyb20gJy4vbmctc2ltcGxlLXN0YXRlLW1vZGVscyc7XHJcbmltcG9ydCB7IE5nU2ltcGxlU3RhdGVTZXNzaW9uU3RvcmFnZSB9IGZyb20gJy4vc3RvcmFnZS9uZy1zaW1wbGUtc3RhdGUtc2Vzc2lvbi1zdG9yYWdlJztcclxuXHJcbkBJbmplY3RhYmxlKClcclxuQERpcmVjdGl2ZSgpXHJcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBOZ1NpbXBsZVN0YXRlQmFzZUNvbW1vblN0b3JlPFMgZXh0ZW5kcyBvYmplY3QgfCBBcnJheTxhbnk+PiBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XHJcblxyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHN0YWNrUG9pbnQ6IG51bWJlcjtcclxuICAgIHByb3RlY3RlZCBsb2NhbFN0b3JhZ2VJc0VuYWJsZWQ6IGJvb2xlYW47XHJcbiAgICBwcm90ZWN0ZWQgZGV2VG9vbElzRW5hYmxlZDogYm9vbGVhbjtcclxuICAgIHByb3RlY3RlZCBkZXZUb29sITogTmdTaW1wbGVTdGF0ZURldlRvb2w7XHJcbiAgICBwcm90ZWN0ZWQgcGVyc2lzdGVudFN0b3JhZ2UhOiBOZ1NpbXBsZVN0YXRlQnJvd3NlclN0b3JhZ2U7XHJcbiAgICBwcm90ZWN0ZWQgbG9jYWxTdG9yZUNvbmZpZzogTmdTaW1wbGVTdGF0ZVN0b3JlQ29uZmlnO1xyXG4gICAgcHJvdGVjdGVkIHN0b3JlTmFtZTogc3RyaW5nO1xyXG4gICAgcHJvdGVjdGVkIGZpcnN0U3RhdGUhOiBTO1xyXG4gICAgcHJvdGVjdGVkIGlzQXJyYXk6IGJvb2xlYW47XHJcbiAgICBwcm90ZWN0ZWQgZGV2TW9kZTogYm9vbGVhbiA9IGlzRGV2TW9kZSgpO1xyXG4gICAgcHJvdGVjdGVkIGNvbXBhcmF0b3IhOiA8Sz4ocHJldmlvdXM6IEssIGN1cnJlbnQ6IEspID0+IGJvb2xlYW47XHJcblxyXG4gICAgY29uc3RydWN0b3IoQEluamVjdChJbmplY3RvcikgaW5qZWN0b3I6IEluamVjdG9yKSB7XHJcblxyXG4gICAgICAgIGNvbnN0IGdsb2JhbENvbmZpZyA9IGluamVjdG9yLmdldChOR19TSU1QTEVfU1RPUkVfQ09ORklHLCB7fSk7XHJcbiAgICAgICAgY29uc3Qgc3RvcmVDb25maWcgPSB0aGlzLnN0b3JlQ29uZmlnKCkgfHwge307XHJcbiAgICAgICAgdGhpcy5sb2NhbFN0b3JlQ29uZmlnID0geyAuLi5nbG9iYWxDb25maWcsIC4uLnN0b3JlQ29uZmlnIH07XHJcblxyXG4gICAgICAgIHRoaXMubG9jYWxTdG9yYWdlSXNFbmFibGVkID0gdHlwZW9mIHRoaXMubG9jYWxTdG9yZUNvbmZpZy5lbmFibGVMb2NhbFN0b3JhZ2UgPT09ICdib29sZWFuJyA/IHRoaXMubG9jYWxTdG9yZUNvbmZpZy5lbmFibGVMb2NhbFN0b3JhZ2UgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMubG9jYWxTdG9yYWdlSXNFbmFibGVkKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmxvY2FsU3RvcmVDb25maWcucGVyc2lzdGVudFN0b3JhZ2UgPT09ICdsb2NhbCcpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMucGVyc2lzdGVudFN0b3JhZ2UgPSBpbmplY3Rvci5nZXQoTmdTaW1wbGVTdGF0ZUxvY2FsU3RvcmFnZSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5sb2NhbFN0b3JlQ29uZmlnLnBlcnNpc3RlbnRTdG9yYWdlID09PSAnc2Vzc2lvbicpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMucGVyc2lzdGVudFN0b3JhZ2UgPSBpbmplY3Rvci5nZXQoTmdTaW1wbGVTdGF0ZVNlc3Npb25TdG9yYWdlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5kZXZUb29sSXNFbmFibGVkID0gdHlwZW9mIHRoaXMubG9jYWxTdG9yZUNvbmZpZy5lbmFibGVEZXZUb29sID09PSAnYm9vbGVhbicgPyB0aGlzLmxvY2FsU3RvcmVDb25maWcuZW5hYmxlRGV2VG9vbCA6IGZhbHNlO1xyXG4gICAgICAgIGlmICh0aGlzLmRldlRvb2xJc0VuYWJsZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5kZXZUb29sID0gaW5qZWN0b3IuZ2V0KE5nU2ltcGxlU3RhdGVEZXZUb29sKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuc3RvcmVOYW1lID0gdHlwZW9mIHRoaXMubG9jYWxTdG9yZUNvbmZpZy5zdG9yZU5hbWUgPT09ICdzdHJpbmcnID8gdGhpcy5sb2NhbFN0b3JlQ29uZmlnLnN0b3JlTmFtZSA6IHRoaXMuY29uc3RydWN0b3IubmFtZTtcclxuICAgICAgICBpZiAodHlwZW9mIHRoaXMubG9jYWxTdG9yZUNvbmZpZy5jb21wYXJhdG9yID09PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29tcGFyYXRvciA9IHRoaXMubG9jYWxTdG9yZUNvbmZpZy5jb21wYXJhdG9yO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMubG9jYWxTdG9yYWdlSXNFbmFibGVkICYmIHRoaXMucGVyc2lzdGVudFN0b3JhZ2UpIHtcclxuICAgICAgICAgICAgY29uc3QgZmlyc3RTdGF0ZSA9IHRoaXMucGVyc2lzdGVudFN0b3JhZ2UuZ2V0SXRlbTxTPih0aGlzLnN0b3JlTmFtZSk7XHJcbiAgICAgICAgICAgIGlmIChmaXJzdFN0YXRlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmZpcnN0U3RhdGUgPSBmaXJzdFN0YXRlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICghdGhpcy5maXJzdFN0YXRlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuZmlyc3RTdGF0ZSA9IHRoaXMuaW5pdGlhbFN0YXRlKGluamVjdG9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuZGV2VG9vbFNlbmQodGhpcy5maXJzdFN0YXRlLCBgaW5pdGlhbFN0YXRlYCk7XHJcblxyXG4gICAgICAgIHRoaXMuaXNBcnJheSA9IEFycmF5LmlzQXJyYXkodGhpcy5maXJzdFN0YXRlKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFdoZW4geW91IG92ZXJyaWRlIHRoaXMgbWV0aG9kLCB5b3UgaGF2ZSB0byBjYWxsIHRoZSBgc3VwZXIubmdPbkRlc3Ryb3koKWAgbWV0aG9kIGluIHlvdXIgYG5nT25EZXN0cm95KClgIG1ldGhvZC5cclxuICAgICAqL1xyXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5kZXZUb29sU2VuZCh1bmRlZmluZWQsICduZ09uRGVzdHJveScpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogT3ZlcnJpZGUgdGhpcyBtZXRob2QgZm9yIHNldCBhIHNwZWNpZmljIGNvbmZpZyBmb3IgdGhlIHN0b3JlXHJcbiAgICAgKiBAcmV0dXJucyBOZ1NpbXBsZVN0YXRlU3RvcmVDb25maWdcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHN0b3JlQ29uZmlnKCk6IE5nU2ltcGxlU3RhdGVTdG9yZUNvbmZpZztcclxuXHJcbiAgICAvKipcclxuICAgICAqIFNldCBpbnRvIHRoZSBzdG9yZSB0aGUgaW5pdGlhbCBzdGF0ZVxyXG4gICAgICogQHBhcmFtIGluamVjdG9yIGN1cnJlbnQgSW5qZWN0b3JcclxuICAgICAqIEByZXR1cm5zIFRoZSBzdGF0ZSBvYmplY3RcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGluaXRpYWxTdGF0ZShpbmplY3Rvcj86IEluamVjdG9yKTogUztcclxuXHJcbiAgICAvKipcclxuICAgICAqIFNlbGVjdCBhIHN0b3JlIHN0YXRlXHJcbiAgICAgKiBAcGFyYW0gc2VsZWN0Rm4gU3RhdGUgc2VsZWN0b3IgKGlmIG5vdCBwcm92aWRlZCByZXR1cm4gZnVsbCBzdGF0ZSlcclxuICAgICAqIEBwYXJhbSBjb21wYXJhdG9yIEEgZnVuY3Rpb24gdXNlZCB0byBjb21wYXJlIHRoZSBwcmV2aW91cyBhbmQgY3VycmVudCBzdGF0ZSBmb3IgZXF1YWxpdHkuIERlZmF1bHRzIHRvIGEgYD09PWAgY2hlY2suXHJcbiAgICAgKiBAcmV0dXJucyBPYnNlcnZhYmxlIG9mIHRoZSBzZWxlY3RlZCBzdGF0ZVxyXG4gICAgICovXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxyXG4gICAgYWJzdHJhY3Qgc2VsZWN0U3RhdGU8Sz4oc2VsZWN0Rm4/OiAoc3RhdGU6IFJlYWRvbmx5PFM+KSA9PiBLLCBjb21wYXJhdG9yPzogKHByZXZpb3VzOiBLLCBjdXJyZW50OiBLKSA9PiBib29sZWFuKTogYW55O1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2V0IGEgbmV3IHN0YXRlXHJcbiAgICAgKiBAcGFyYW0gc2VsZWN0Rm4gU3RhdGUgcmVkdWNlclxyXG4gICAgICogQHBhcmFtIGFjdGlvbk5hbWUgVGhlIGFjdGlvbiBsYWJlbCBpbnRvIFJlZHV4IERldlRvb2xzIChkZWZhdWx0IGlzIHBhcmVudCBmdW5jdGlvbiBuYW1lKVxyXG4gICAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgc3RhdGUgaXMgY2hhbmdlZFxyXG4gICAgICovXHJcbiAgICBhYnN0cmFjdCBzZXRTdGF0ZShzdGF0ZUZuOiAoY3VycmVudFN0YXRlOiBSZWFkb25seTxTPikgPT4gUGFydGlhbDxTPiwgYWN0aW9uTmFtZT86IHN0cmluZyk6IGJvb2xlYW47XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm4gdGhlIGN1cnJlbnQgc3RvcmUgc3RhdGUgKHNuYXBzaG90KVxyXG4gICAgICogQHJldHVybnMgVGhlIGN1cnJlbnQgc3RhdGVcclxuICAgICAqL1xyXG4gICAgYWJzdHJhY3QgZ2V0Q3VycmVudFN0YXRlKCk6IFJlYWRvbmx5PFM+O1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJuIHRoZSBmaXJzdCBsb2FkZWQgc3RvcmUgc3RhdGU6XHJcbiAgICAgKiB0aGUgbGFzdCBzYXZlZCBzdGF0ZSwgaWYgYGVuYWJsZUxvY2FsU3RvcmFnZWAgY29uZmlnIGlzIGB0cnVlYDtcclxuICAgICAqIG90aGVyd2lzZSB0aGUgaW5pdGlhbCBzdGF0ZSBwcm92aWRlZCBmcm9tIGBpbml0aWFsU3RhdGUoKWAgbWV0aG9kLlxyXG4gICAgICogQHJldHVybnMgVGhlIGZpcnN0IHN0YXRlXHJcbiAgICAgKi9cclxuICAgIGdldEZpcnN0U3RhdGUoKTogUmVhZG9ubHk8Uz4gfCBudWxsIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5kZWVwRnJlZXplKHRoaXMuZmlyc3RTdGF0ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXNldCBzdG9yZSB0byBmaXJzdCBsb2FkZWQgc3RvcmUgc3RhdGU6XHJcbiAgICAgKiAgLSB0aGUgbGFzdCBzYXZlZCBzdGF0ZSwgaWYgYGVuYWJsZUxvY2FsU3RvcmFnZWAgY29uZmlnIGlzIGB0cnVlYFxyXG4gICAgICogIC0gb3RoZXJ3aXNlIHRoZSBpbml0aWFsIHN0YXRlIHByb3ZpZGVkIGZyb20gYGluaXRpYWxTdGF0ZSgpYCBtZXRob2QuXHJcbiAgICAgKi9cclxuICAgIHJlc2V0U3RhdGUoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc2V0U3RhdGUoKCkgPT4gdGhpcy5maXJzdFN0YXRlLCAncmVzZXRTdGF0ZScpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmVzdGFydCB0aGUgc3RvcmUgdG8gaW5pdGlhbCBzdGF0ZSBwcm92aWRlZCBmcm9tIGBpbml0aWFsU3RhdGUoKWAgbWV0aG9kXHJcbiAgICAgKi9cclxuICAgIHJlc3RhcnRTdGF0ZSgpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zZXRTdGF0ZSgoKSA9PiB0aGlzLmluaXRpYWxTdGF0ZSgpLCAncmVzdGFydFN0YXRlJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTZW5kIHRvIGRldiB0b29sIGEgbmV3IHN0YXRlXHJcbiAgICAgKiBAcGFyYW0gbmV3U3RhdGUgbmV3IHN0YXRlXHJcbiAgICAgKiBAcGFyYW0gYWN0aW9uTmFtZSBUaGUgYWN0aW9uIG5hbWVcclxuICAgICAqIEByZXR1cm5zIFRydWUgaWYgZGV2IHRvb2xzIGFyZSBlbmFibGVkXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBkZXZUb29sU2VuZChuZXdTdGF0ZTogUyB8IHVuZGVmaW5lZCwgYWN0aW9uTmFtZT86IHN0cmluZyk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmICghdGhpcy5kZXZUb29sSXNFbmFibGVkIHx8ICF0aGlzLmRldlRvb2wpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoIWFjdGlvbk5hbWUpIHtcclxuICAgICAgICAgICAgLy8gcmV0cmlldmUgdGhlIHBhcmVudCAob2YgcGFyZW50KSBtZXRob2QgaW50byB0aGUgc3RhY2sgdHJhY2VcclxuICAgICAgICAgICAgYWN0aW9uTmFtZSA9IG5ldyBFcnJvcigpLnN0YWNrXHJcbiAgICAgICAgICAgICAgICA/LnNwbGl0KCdcXG4nKVt0aGlzLnN0YWNrUG9pbnRdXHJcbiAgICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgICAuc3BsaXQoJyAnKVsxXVxyXG4gICAgICAgICAgICAgICAgLnNwbGl0KCcuJylbMV0gfHwgJ3Vua25vd24nO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoIXRoaXMuZGV2VG9vbC5zZW5kKHRoaXMuc3RvcmVOYW1lLCBhY3Rpb25OYW1lLCBuZXdTdGF0ZSkpIHtcclxuICAgICAgICAgICAgY29uc29sZS5sb2codGhpcy5zdG9yZU5hbWUgKyAnLicgKyBhY3Rpb25OYW1lLCBuZXdTdGF0ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmVjdXJzaXZlbHkgT2JqZWN0LmZyZWV6ZSBzaW1wbGUgSmF2YXNjcmlwdCBzdHJ1Y3R1cmVzIGNvbnNpc3Rpbmcgb2YgcGxhaW4gb2JqZWN0cywgYXJyYXlzLCBhbmQgcHJpbWl0aXZlcy5cclxuICAgICAqIE1ha2UgdGhlIGRhdGEgaW1tdXRhYmxlLlxyXG4gICAgICogQHJldHVybnMgaW1tdXRhYmxlIG9iamVjdFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZGVlcEZyZWV6ZShvYmplY3Q6IFMpOiBSZWFkb25seTxTPiB7XHJcbiAgICAgICAgLy8gTm8gZnJlZXppbmcgaW4gcHJvZHVjdGlvbiAoZm9yIGJldHRlciBwZXJmb3JtYW5jZSkuXHJcbiAgICAgICAgaWYgKCF0aGlzLmRldk1vZGUgfHwgIW9iamVjdCkge1xyXG4gICAgICAgICAgICByZXR1cm4gb2JqZWN0IGFzIFJlYWRvbmx5PFM+O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gV2hlbiBhbHJlYWR5IGZyb3plbiwgd2UgYXNzdW1lIGl0cyBjaGlsZHJlbiBhcmUgZnJvemVuIChmb3IgYmV0dGVyIHBlcmZvcm1hbmNlKS5cclxuICAgICAgICAvLyBUaGlzIHNob3VsZCBiZSB0cnVlIGlmIHlvdSBhbHdheXMgdXNlIGBkZWVwRnJlZXplYCB0byBmcmVlemUgb2JqZWN0cy5cclxuICAgICAgICAvL1xyXG4gICAgICAgIC8vIE5vdGUgdGhhdCBPYmplY3QuaXNGcm96ZW4gd2lsbCBhbHNvIHJldHVybiBgdHJ1ZWAgZm9yIHByaW1pdGl2ZXMgKG51bWJlcnMsXHJcbiAgICAgICAgLy8gc3RyaW5ncywgYm9vbGVhbnMsIHVuZGVmaW5lZCwgbnVsbCksIHNvIHRoZXJlIGlzIG5vIG5lZWQgdG8gY2hlY2sgZm9yXHJcbiAgICAgICAgLy8gdGhvc2UgZXhwbGljaXRseS5cclxuICAgICAgICBpZiAoT2JqZWN0LmlzRnJvemVuKG9iamVjdCkpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG9iamVjdCBhcyBSZWFkb25seTxTPjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEF0IHRoaXMgcG9pbnQgd2Uga25vdyB0aGF0IHdlJ3JlIGRlYWxpbmcgd2l0aCBlaXRoZXIgYW4gYXJyYXkgb3IgcGxhaW4gb2JqZWN0LCBzb1xyXG4gICAgICAgIC8vIGp1c3QgZnJlZXplIGl0IGFuZCByZWN1cnNlIG9uIGl0cyB2YWx1ZXMuXHJcbiAgICAgICAgT2JqZWN0LmZyZWV6ZShvYmplY3QpO1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XHJcbiAgICAgICAgT2JqZWN0LmtleXMob2JqZWN0KS5mb3JFYWNoKGtleSA9PiB0aGlzLmRlZXBGcmVlemUoKG9iamVjdCBhcyBhbnkpW2tleV0pKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIG9iamVjdCBhcyBSZWFkb25seTxTPjtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFBlcnNpc3Qgc3RhdGUgdG8gc3RvcmFnZVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGVQZXJzaXN0KHN0YXRlOiBTKSB7XHJcbiAgICAgICAgaWYgKHRoaXMubG9jYWxTdG9yYWdlSXNFbmFibGVkICYmIHRoaXMucGVyc2lzdGVudFN0b3JhZ2UpIHtcclxuICAgICAgICAgICAgdGhpcy5wZXJzaXN0ZW50U3RvcmFnZS5zZXRJdGVtPFM+KHRoaXMuc3RvcmVOYW1lLCBzdGF0ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiJdfQ==