@covalent/guided-tour 4.0.0 → 4.1.0-develop.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +32 -15
  2. package/_guided-tour-theme.scss +6 -6
  3. package/covalent-guided-tour.d.ts +2 -1
  4. package/esm2020/covalent-guided-tour.mjs +5 -0
  5. package/esm2020/lib/guided-tour.module.mjs +19 -0
  6. package/esm2020/lib/guided-tour.service.mjs +163 -0
  7. package/esm2020/lib/guided.tour.mjs +438 -0
  8. package/esm2020/public_api.mjs +4 -0
  9. package/fesm2015/{covalent-guided-tour.js → covalent-guided-tour.mjs} +180 -615
  10. package/fesm2015/covalent-guided-tour.mjs.map +1 -0
  11. package/fesm2020/covalent-guided-tour.mjs +619 -0
  12. package/fesm2020/covalent-guided-tour.mjs.map +1 -0
  13. package/lib/guided-tour.module.d.ts +7 -0
  14. package/{guided-tour.service.d.ts → lib/guided-tour.service.d.ts} +4 -1
  15. package/{guided.tour.d.ts → lib/guided.tour.d.ts} +3 -7
  16. package/package.json +25 -21
  17. package/public_api.d.ts +3 -0
  18. package/{_guided-tour.scss → styles/guided-tour.scss} +17 -2
  19. package/bundles/covalent-guided-tour.umd.js +0 -1369
  20. package/bundles/covalent-guided-tour.umd.js.map +0 -1
  21. package/bundles/covalent-guided-tour.umd.min.js +0 -16
  22. package/bundles/covalent-guided-tour.umd.min.js.map +0 -1
  23. package/covalent-guided-tour.metadata.json +0 -1
  24. package/esm2015/covalent-guided-tour.js +0 -10
  25. package/esm2015/guided-tour.module.js +0 -19
  26. package/esm2015/guided-tour.service.js +0 -312
  27. package/esm2015/guided.tour.js +0 -722
  28. package/esm2015/index.js +0 -7
  29. package/esm2015/public-api.js +0 -9
  30. package/fesm2015/covalent-guided-tour.js.map +0 -1
  31. package/guided-tour.module.d.ts +0 -2
  32. package/index.d.ts +0 -1
  33. package/public-api.d.ts +0 -3
package/README.md CHANGED
@@ -6,15 +6,15 @@ A wrapper around [Shepherd](https://shepherdjs.dev) with extra functionality. Ma
6
6
 
7
7
  #### Methods
8
8
 
9
- + registerTour(tourName: string, tour: IGuidedTour | string): Promise<void>
10
- + Create a tour
11
- + startTour(tourName: string): Shepherd.Tour
12
- + Start a certain tour
13
- + initializeOnQueryParams(queryParam: string = 'tour'): Observable<ParamMap>
14
- + Listen to query params to launch a tour
15
- + tourEvent$(str: TourEvents): Observable<IGuidedTourEvent>
16
- + Observable of tour events
17
-
9
+ - registerTour(tourName: string, tour: IGuidedTour | string): Promise<void>
10
+ - Create a tour
11
+ - startTour(tourName: string): Shepherd.Tour
12
+ - Start a certain tour
13
+ - initializeOnQueryParams(queryParam: string = 'tour'): Observable<ParamMap>
14
+ - Listen to query params to launch a tour
15
+ - tourEvent$(str: TourEvents): Observable<IGuidedTourEvent>
16
+ - Observable of tour events
17
+
18
18
  ```ts
19
19
  // for reference
20
20
  export type TourStep = Shepherd.Step.StepOptions;
@@ -105,6 +105,7 @@ import { CovalentGuidedTourModule } from '@covalent/guided-tour';
105
105
  ```
106
106
 
107
107
  ## Usage
108
+
108
109
  ```ts
109
110
  import { CovalentGuidedTourService } from '@covalent/guided-tour';
110
111
 
@@ -139,16 +140,32 @@ const basicDemoTour: IGuidedTour = {
139
140
  };
140
141
  this._guidedTourService.registerTour('basicDemoTour', basicDemoTour);
141
142
  this._guidedTourService.startTour('basicDemoTour');
142
- this._guidedTourService.tourEvent$(TourEvents.show)
143
- .subscribe((event: IGuidedTourEvent) => { /* event object contains current step, previous step and tour objects */});
143
+ this._guidedTourService
144
+ .tourEvent$(TourEvents.show)
145
+ .subscribe((event: IGuidedTourEvent) => {
146
+ /* event object contains current step, previous step and tour objects */
147
+ });
144
148
  ```
145
149
 
146
150
  ```html
147
151
  <div id="basic-demo">
148
- <button mat-raised-button color="accent" (click)="startTour()">Start tour</button>
149
- <meter id="fuel" min="0" max="100" low="33" high="66" optimum="50" value="50"></meter>
150
- <progress id="oxygen" max="100" value="70"> 70% </progress>
152
+ <button mat-raised-button color="accent" (click)="startTour()">
153
+ Start tour
154
+ </button>
155
+ <meter
156
+ id="fuel"
157
+ min="0"
158
+ max="100"
159
+ low="33"
160
+ high="66"
161
+ optimum="50"
162
+ value="50"
163
+ ></meter>
164
+ <progress id="oxygen" max="100" value="70">70%</progress>
151
165
  <marquee id="status">All systems are running smoothly</marquee>
152
166
  </div>
153
-
154
167
  ```
168
+
169
+ ## Running unit tests
170
+
171
+ Run `nx test angular-guided-tour` to execute the unit tests.
@@ -1,6 +1,3 @@
1
- @import './guided-tour.scss';
2
- @import '~@angular/material/button/button-base';
3
-
4
1
  @mixin covalent-guided-tour-theme($theme, $config: null) {
5
2
  @include td-guided-tour-typography($config);
6
3
  @include td-guided-tour-theme($theme);
@@ -14,9 +11,11 @@
14
11
  .shepherd-title {
15
12
  @include mat-typography-level-to-styles($config, subheading-2);
16
13
  }
14
+
17
15
  .shepherd-text {
18
16
  @include mat-typography-level-to-styles($config, body-1);
19
17
  }
18
+
20
19
  .shepherd-progress {
21
20
  @include mat-typography-level-to-styles($config, body-1);
22
21
  }
@@ -41,6 +40,7 @@
41
40
  .shepherd-cancel-icon span::after {
42
41
  color: mat-color($accent, darker-contrast);
43
42
  }
43
+
44
44
  .shepherd-button:not(:disabled),
45
45
  .shepherd-button.shepherd-button-secondary:not(:disabled),
46
46
  .shepherd-cancel-icon {
@@ -54,15 +54,14 @@
54
54
  .shepherd-arrow::before,
55
55
  .shepherd-arrow::after,
56
56
  .shepherd-content,
57
- .shepherd-element.shepherd-has-title[data-popper-placement^='bottom'] > .shepherd-arrow::before {
57
+ .shepherd-element.shepherd-has-title[data-popper-placement^='bottom']
58
+ > .shepherd-arrow::before {
58
59
  background: mat-color($accent, darker);
59
60
  }
60
61
 
61
62
  // Bringing in mat-icon button styles
62
63
  // Class can't be passed so we must include mat button styles here
63
64
  .shepherd-cancel-icon {
64
- @include mat-button-base;
65
-
66
65
  min-width: 0;
67
66
  margin: 0;
68
67
  padding: 0;
@@ -72,6 +71,7 @@
72
71
  line-height: $mat-icon-button-size;
73
72
  border-radius: $mat-icon-button-border-radius;
74
73
  }
74
+
75
75
  .shepherd-void-button {
76
76
  display: none;
77
77
  }
@@ -1,4 +1,5 @@
1
1
  /**
2
2
  * Generated bundle index. Do not edit.
3
3
  */
4
- export * from './index';
4
+ /// <amd-module name="@covalent/guided-tour" />
5
+ export * from './public_api';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './public_api';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY292YWxlbnQtZ3VpZGVkLXRvdXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWJzL2FuZ3VsYXItZ3VpZGVkLXRvdXIvc3JjL2NvdmFsZW50LWd1aWRlZC10b3VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vcHVibGljX2FwaSc7XG4iXX0=
@@ -0,0 +1,19 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { CovalentGuidedTourService } from './guided-tour.service';
4
+ import * as i0 from "@angular/core";
5
+ export class CovalentGuidedTourModule {
6
+ }
7
+ CovalentGuidedTourModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: CovalentGuidedTourModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
8
+ CovalentGuidedTourModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: CovalentGuidedTourModule, imports: [CommonModule] });
9
+ CovalentGuidedTourModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: CovalentGuidedTourModule, providers: [CovalentGuidedTourService], imports: [[CommonModule]] });
10
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: CovalentGuidedTourModule, decorators: [{
11
+ type: NgModule,
12
+ args: [{
13
+ imports: [CommonModule],
14
+ providers: [CovalentGuidedTourService],
15
+ declarations: [],
16
+ exports: [],
17
+ }]
18
+ }] });
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3VpZGVkLXRvdXIubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGlicy9hbmd1bGFyLWd1aWRlZC10b3VyL3NyYy9saWIvZ3VpZGVkLXRvdXIubW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDOztBQVFsRSxNQUFNLE9BQU8sd0JBQXdCOztxSEFBeEIsd0JBQXdCO3NIQUF4Qix3QkFBd0IsWUFMekIsWUFBWTtzSEFLWCx3QkFBd0IsYUFKeEIsQ0FBQyx5QkFBeUIsQ0FBQyxZQUQ3QixDQUFDLFlBQVksQ0FBQzsyRkFLWix3QkFBd0I7a0JBTnBDLFFBQVE7bUJBQUM7b0JBQ1IsT0FBTyxFQUFFLENBQUMsWUFBWSxDQUFDO29CQUN2QixTQUFTLEVBQUUsQ0FBQyx5QkFBeUIsQ0FBQztvQkFDdEMsWUFBWSxFQUFFLEVBQUU7b0JBQ2hCLE9BQU8sRUFBRSxFQUFFO2lCQUNaIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBDb3ZhbGVudEd1aWRlZFRvdXJTZXJ2aWNlIH0gZnJvbSAnLi9ndWlkZWQtdG91ci5zZXJ2aWNlJztcblxuQE5nTW9kdWxlKHtcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV0sXG4gIHByb3ZpZGVyczogW0NvdmFsZW50R3VpZGVkVG91clNlcnZpY2VdLFxuICBkZWNsYXJhdGlvbnM6IFtdLFxuICBleHBvcnRzOiBbXSxcbn0pXG5leHBvcnQgY2xhc3MgQ292YWxlbnRHdWlkZWRUb3VyTW9kdWxlIHt9XG4iXX0=
@@ -0,0 +1,163 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { HttpClient } from '@angular/common/http';
3
+ import { Router, ActivatedRoute, NavigationStart, } from '@angular/router';
4
+ import { tap, map, filter } from 'rxjs/operators';
5
+ import { fromEvent } from 'rxjs';
6
+ import { debounceTime } from 'rxjs/operators';
7
+ import { CovalentGuidedTour, } from './guided.tour';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/router";
10
+ import * as i2 from "@angular/common/http";
11
+ /**
12
+ * Router enabled Shepherd tour
13
+ */
14
+ export var TourEvents;
15
+ (function (TourEvents) {
16
+ TourEvents["complete"] = "complete";
17
+ TourEvents["cancel"] = "cancel";
18
+ TourEvents["hide"] = "hide";
19
+ TourEvents["show"] = "show";
20
+ TourEvents["start"] = "start";
21
+ TourEvents["active"] = "active";
22
+ TourEvents["inactive"] = "inactive";
23
+ })(TourEvents || (TourEvents = {}));
24
+ export class CovalentGuidedTourService extends CovalentGuidedTour {
25
+ constructor(_router, _route, _httpClient) {
26
+ super();
27
+ this._router = _router;
28
+ this._route = _route;
29
+ this._httpClient = _httpClient;
30
+ this._toursMap = new Map();
31
+ this._tourStepURLs = new Map();
32
+ _router.events
33
+ .pipe(filter((event) => event instanceof NavigationStart &&
34
+ event.navigationTrigger === 'popstate'))
35
+ .subscribe(() => {
36
+ if (this.shepherdTour.isActive()) {
37
+ this.shepherdTour.cancel();
38
+ }
39
+ });
40
+ }
41
+ tourEvent$(str) {
42
+ return fromEvent(this.shepherdTour, str);
43
+ }
44
+ async registerTour(tourName, tour) {
45
+ const guidedTour = typeof tour === 'string' ? await this._loadTour(tour) : tour;
46
+ this._toursMap.set(tourName, guidedTour);
47
+ }
48
+ startTour(tourName) {
49
+ const guidedTour = this._getTour(tourName);
50
+ this.finish();
51
+ if (guidedTour && guidedTour.steps && guidedTour.steps.length) {
52
+ // remove steps from tour since we need to preprocess them first
53
+ this.newTour(Object.assign({}, guidedTour, { steps: undefined }));
54
+ const tourInstance = this.shepherdTour.addSteps(this._configureRoutesForSteps(this._prepareTour(guidedTour.steps, guidedTour.finishButtonText)));
55
+ // init route transition if step URL is different then the current location.
56
+ this.tourEvent$(TourEvents.show).subscribe((tourEvent) => {
57
+ const currentURL = this._router.url.split(/[?#]/)[0];
58
+ const { step: { id, options }, } = tourEvent;
59
+ if (this._tourStepURLs.has(id)) {
60
+ const stepRoute = this._tourStepURLs.get(id);
61
+ if (stepRoute !== currentURL) {
62
+ this._router.navigate([stepRoute]);
63
+ }
64
+ }
65
+ else {
66
+ if (options && options.routing) {
67
+ this._tourStepURLs.set(id, options.routing.route);
68
+ }
69
+ else {
70
+ this._tourStepURLs.set(id, currentURL);
71
+ }
72
+ }
73
+ });
74
+ this.start();
75
+ return tourInstance;
76
+ }
77
+ else {
78
+ // tslint:disable-next-line:no-console
79
+ console.warn(`Tour ${tourName} does not exist. Please try another tour.`);
80
+ return undefined;
81
+ }
82
+ }
83
+ // Finds the right registered tour by using queryParams
84
+ // finishes any other tour and starts the new one.
85
+ initializeOnQueryParams(queryParam = 'tour') {
86
+ return this._route.queryParamMap.pipe(debounceTime(100), tap((params) => {
87
+ const tourParam = params.get(queryParam);
88
+ if (tourParam) {
89
+ this.startTour(tourParam);
90
+ // get current search parameters
91
+ const searchParams = new URLSearchParams(window.location.search);
92
+ // delete tour queryParam
93
+ searchParams.delete(queryParam);
94
+ // build new URL string without it
95
+ let url = window.location.protocol +
96
+ '//' +
97
+ window.location.host +
98
+ window.location.pathname;
99
+ if (searchParams.toString()) {
100
+ url += '?' + searchParams.toString();
101
+ }
102
+ // replace state in history without triggering a navigation
103
+ window.history.replaceState({ path: url }, '', url);
104
+ }
105
+ }));
106
+ }
107
+ setNextBtnDisability(stepId, isDisabled) {
108
+ if (this.shepherdTour.getById(stepId)) {
109
+ const stepOptions = this.shepherdTour.getById(stepId)
110
+ .options;
111
+ stepOptions.buttons?.forEach((button) => {
112
+ if (button.text === 'chevron_right') {
113
+ button.disabled = isDisabled;
114
+ }
115
+ });
116
+ this.shepherdTour.getById(stepId)?.updateStepOptions(stepOptions);
117
+ }
118
+ }
119
+ async _loadTour(tourUrl) {
120
+ const request = this._httpClient.get(tourUrl);
121
+ try {
122
+ return await request
123
+ .pipe(map((resultSet) => {
124
+ return JSON.parse(JSON.stringify(resultSet));
125
+ }))
126
+ .toPromise();
127
+ }
128
+ catch {
129
+ return undefined;
130
+ }
131
+ }
132
+ _getTour(key) {
133
+ return this._toursMap.get(key);
134
+ }
135
+ _configureRoutesForSteps(routedSteps) {
136
+ routedSteps.forEach((step) => {
137
+ if (step.routing) {
138
+ const route = step.routing.route;
139
+ // if there is a beforeShowPromise, then we save it and call it after the navigation
140
+ if (step.beforeShowPromise) {
141
+ const beforeShowPromise = step.beforeShowPromise;
142
+ step.beforeShowPromise = () => {
143
+ return this._router
144
+ .navigate([route], step.routing?.extras)
145
+ .then(() => {
146
+ return beforeShowPromise();
147
+ });
148
+ };
149
+ }
150
+ else {
151
+ step.beforeShowPromise = () => this._router.navigate([route]);
152
+ }
153
+ }
154
+ });
155
+ return routedSteps;
156
+ }
157
+ }
158
+ CovalentGuidedTourService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: CovalentGuidedTourService, deps: [{ token: i1.Router }, { token: i1.ActivatedRoute }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
159
+ CovalentGuidedTourService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: CovalentGuidedTourService });
160
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: CovalentGuidedTourService, decorators: [{
161
+ type: Injectable
162
+ }], ctorParameters: function () { return [{ type: i1.Router }, { type: i1.ActivatedRoute }, { type: i2.HttpClient }]; } });
163
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3VpZGVkLXRvdXIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci1ndWlkZWQtdG91ci9zcmMvbGliL2d1aWRlZC10b3VyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUNMLE1BQU0sRUFDTixjQUFjLEVBR2QsZUFBZSxHQUVoQixNQUFNLGlCQUFpQixDQUFDO0FBRXpCLE9BQU8sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2xELE9BQU8sRUFBYyxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFDTCxrQkFBa0IsR0FJbkIsTUFBTSxlQUFlLENBQUM7Ozs7QUFjdkI7O0dBRUc7QUFDSCxNQUFNLENBQU4sSUFBWSxVQVFYO0FBUkQsV0FBWSxVQUFVO0lBQ3BCLG1DQUFxQixDQUFBO0lBQ3JCLCtCQUFpQixDQUFBO0lBQ2pCLDJCQUFhLENBQUE7SUFDYiwyQkFBYSxDQUFBO0lBQ2IsNkJBQWUsQ0FBQTtJQUNmLCtCQUFpQixDQUFBO0lBQ2pCLG1DQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFSVyxVQUFVLEtBQVYsVUFBVSxRQVFyQjtBQVNELE1BQU0sT0FBTyx5QkFBMEIsU0FBUSxrQkFBa0I7SUFHL0QsWUFDVSxPQUFlLEVBQ2YsTUFBc0IsRUFDdEIsV0FBdUI7UUFFL0IsS0FBSyxFQUFFLENBQUM7UUFKQSxZQUFPLEdBQVAsT0FBTyxDQUFRO1FBQ2YsV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFDdEIsZ0JBQVcsR0FBWCxXQUFXLENBQVk7UUFMekIsY0FB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QzFCLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVPLHdCQUF3QixDQUM5QixXQUE4QjtRQUU5QixXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBcUIsRUFBRSxFQUFFO1lBQzVDLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTtnQkFDaEIsTUFBTSxLQUFLLEdBQVcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7Z0JBQ3pDLG9GQUFvRjtnQkFDcEYsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEVBQUU7b0JBQzFCLE1BQU0saUJBQWlCLEdBQXdCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQztvQkFDdEUsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEdBQUcsRUFBRTt3QkFDNUIsT0FBTyxJQUFJLENBQUMsT0FBTzs2QkFDaEIsUUFBUSxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUM7NkJBQ3ZDLElBQUksQ0FBQyxHQUFHLEVBQUU7NEJBQ1QsT0FBTyxpQkFBaUIsRUFBRSxDQUFDO3dCQUM3QixDQUFDLENBQUMsQ0FBQztvQkFDUCxDQUFDLENBQUM7aUJBQ0g7cUJBQU07b0JBQ0wsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFDL0Q7YUFDRjtRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQzs7c0hBcEtVLHlCQUF5QjswSEFBekIseUJBQXlCOzJGQUF6Qix5QkFBeUI7a0JBRHJDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHtcbiAgUm91dGVyLFxuICBBY3RpdmF0ZWRSb3V0ZSxcbiAgUGFyYW1NYXAsXG4gIE5hdmlnYXRpb25FeHRyYXMsXG4gIE5hdmlnYXRpb25TdGFydCxcbiAgRXZlbnQgYXMgTmF2aWdhdGlvbkV2ZW50LFxufSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IFNoZXBoZXJkIGZyb20gJ3NoZXBoZXJkLmpzJztcbmltcG9ydCB7IHRhcCwgbWFwLCBmaWx0ZXIgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBmcm9tRXZlbnQgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7XG4gIENvdmFsZW50R3VpZGVkVG91cixcbiAgSVRvdXJTdGVwLFxuICBJVG91ck9wdGlvbnMsXG4gIFRvdXJTdGVwQnV0dG9uLFxufSBmcm9tICcuL2d1aWRlZC50b3VyJztcblxuZXhwb3J0IGludGVyZmFjZSBJR3VpZGVkVG91ciBleHRlbmRzIElUb3VyT3B0aW9ucyB7XG4gIHN0ZXBzOiBJR3VpZGVkVG91clN0ZXBbXTtcbiAgZmluaXNoQnV0dG9uVGV4dD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJR3VpZGVkVG91clN0ZXAgZXh0ZW5kcyBJVG91clN0ZXAge1xuICByb3V0aW5nPzoge1xuICAgIHJvdXRlOiBzdHJpbmc7XG4gICAgZXh0cmFzPzogTmF2aWdhdGlvbkV4dHJhcztcbiAgfTtcbn1cblxuLyoqXG4gKiAgUm91dGVyIGVuYWJsZWQgU2hlcGhlcmQgdG91clxuICovXG5leHBvcnQgZW51bSBUb3VyRXZlbnRzIHtcbiAgY29tcGxldGUgPSAnY29tcGxldGUnLFxuICBjYW5jZWwgPSAnY2FuY2VsJyxcbiAgaGlkZSA9ICdoaWRlJyxcbiAgc2hvdyA9ICdzaG93JyxcbiAgc3RhcnQgPSAnc3RhcnQnLFxuICBhY3RpdmUgPSAnYWN0aXZlJyxcbiAgaW5hY3RpdmUgPSAnaW5hY3RpdmUnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIElHdWlkZWRUb3VyRXZlbnQge1xuICBzdGVwOiBhbnk7XG4gIHByZXZpb3VzOiBhbnk7XG4gIHRvdXI6IGFueTtcbn1cblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIENvdmFsZW50R3VpZGVkVG91clNlcnZpY2UgZXh0ZW5kcyBDb3ZhbGVudEd1aWRlZFRvdXIge1xuICBwcml2YXRlIF90b3Vyc01hcDogTWFwPHN0cmluZywgSUd1aWRlZFRvdXI+ID0gbmV3IE1hcDxzdHJpbmcsIElHdWlkZWRUb3VyPigpO1xuICBwcml2YXRlIF90b3VyU3RlcFVSTHM6IE1hcDxzdHJpbmcsIHN0cmluZz4gPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIF9yb3V0ZXI6IFJvdXRlcixcbiAgICBwcml2YXRlIF9yb3V0ZTogQWN0aXZhdGVkUm91dGUsXG4gICAgcHJpdmF0ZSBfaHR0cENsaWVudDogSHR0cENsaWVudFxuICApIHtcbiAgICBzdXBlcigpO1xuICAgIF9yb3V0ZXIuZXZlbnRzXG4gICAgICAucGlwZShcbiAgICAgICAgZmlsdGVyKFxuICAgICAgICAgIChldmVudDogTmF2aWdhdGlvbkV2ZW50KSA9PlxuICAgICAgICAgICAgZXZlbnQgaW5zdGFuY2VvZiBOYXZpZ2F0aW9uU3RhcnQgJiZcbiAgICAgICAgICAgIGV2ZW50Lm5hdmlnYXRpb25UcmlnZ2VyID09PSAncG9wc3RhdGUnXG4gICAgICAgIClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICBpZiAodGhpcy5zaGVwaGVyZFRvdXIuaXNBY3RpdmUoKSkge1xuICAgICAgICAgIHRoaXMuc2hlcGhlcmRUb3VyLmNhbmNlbCgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgfVxuXG4gIHRvdXJFdmVudCQoc3RyOiBUb3VyRXZlbnRzKTogT2JzZXJ2YWJsZTxJR3VpZGVkVG91ckV2ZW50PiB7XG4gICAgcmV0dXJuIGZyb21FdmVudCh0aGlzLnNoZXBoZXJkVG91ciwgc3RyKTtcbiAgfVxuXG4gIGFzeW5jIHJlZ2lzdGVyVG91cihcbiAgICB0b3VyTmFtZTogc3RyaW5nLFxuICAgIHRvdXI6IElHdWlkZWRUb3VyIHwgc3RyaW5nXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGd1aWRlZFRvdXI6IElHdWlkZWRUb3VyID1cbiAgICAgIHR5cGVvZiB0b3VyID09PSAnc3RyaW5nJyA/IGF3YWl0IHRoaXMuX2xvYWRUb3VyKHRvdXIpIDogdG91cjtcbiAgICB0aGlzLl90b3Vyc01hcC5zZXQodG91ck5hbWUsIGd1aWRlZFRvdXIpO1xuICB9XG5cbiAgc3RhcnRUb3VyKHRvdXJOYW1lOiBzdHJpbmcpOiBTaGVwaGVyZC5Ub3VyIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBndWlkZWRUb3VyID0gdGhpcy5fZ2V0VG91cih0b3VyTmFtZSk7XG4gICAgdGhpcy5maW5pc2goKTtcbiAgICBpZiAoZ3VpZGVkVG91ciAmJiBndWlkZWRUb3VyLnN0ZXBzICYmIGd1aWRlZFRvdXIuc3RlcHMubGVuZ3RoKSB7XG4gICAgICAvLyByZW1vdmUgc3RlcHMgZnJvbSB0b3VyIHNpbmNlIHdlIG5lZWQgdG8gcHJlcHJvY2VzcyB0aGVtIGZpcnN0XG4gICAgICB0aGlzLm5ld1RvdXIoT2JqZWN0LmFzc2lnbih7fSwgZ3VpZGVkVG91ciwgeyBzdGVwczogdW5kZWZpbmVkIH0pKTtcbiAgICAgIGNvbnN0IHRvdXJJbnN0YW5jZTogU2hlcGhlcmQuVG91ciA9IHRoaXMuc2hlcGhlcmRUb3VyLmFkZFN0ZXBzKFxuICAgICAgICB0aGlzLl9jb25maWd1cmVSb3V0ZXNGb3JTdGVwcyhcbiAgICAgICAgICB0aGlzLl9wcmVwYXJlVG91cihndWlkZWRUb3VyLnN0ZXBzLCBndWlkZWRUb3VyLmZpbmlzaEJ1dHRvblRleHQpXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgICAvLyBpbml0IHJvdXRlIHRyYW5zaXRpb24gaWYgc3RlcCBVUkwgaXMgZGlmZmVyZW50IHRoZW4gdGhlIGN1cnJlbnQgbG9jYXRpb24uXG4gICAgICB0aGlzLnRvdXJFdmVudCQoVG91ckV2ZW50cy5zaG93KS5zdWJzY3JpYmUoXG4gICAgICAgICh0b3VyRXZlbnQ6IElHdWlkZWRUb3VyRXZlbnQpID0+IHtcbiAgICAgICAgICBjb25zdCBjdXJyZW50VVJMOiBzdHJpbmcgPSB0aGlzLl9yb3V0ZXIudXJsLnNwbGl0KC9bPyNdLylbMF07XG4gICAgICAgICAgY29uc3Qge1xuICAgICAgICAgICAgc3RlcDogeyBpZCwgb3B0aW9ucyB9LFxuICAgICAgICAgIH0gPSB0b3VyRXZlbnQ7XG4gICAgICAgICAgaWYgKHRoaXMuX3RvdXJTdGVwVVJMcy5oYXMoaWQpKSB7XG4gICAgICAgICAgICBjb25zdCBzdGVwUm91dGUgPSB0aGlzLl90b3VyU3RlcFVSTHMuZ2V0KGlkKTtcbiAgICAgICAgICAgIGlmIChzdGVwUm91dGUgIT09IGN1cnJlbnRVUkwpIHtcbiAgICAgICAgICAgICAgdGhpcy5fcm91dGVyLm5hdmlnYXRlKFtzdGVwUm91dGVdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5yb3V0aW5nKSB7XG4gICAgICAgICAgICAgIHRoaXMuX3RvdXJTdGVwVVJMcy5zZXQoaWQsIG9wdGlvbnMucm91dGluZy5yb3V0ZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aGlzLl90b3VyU3RlcFVSTHMuc2V0KGlkLCBjdXJyZW50VVJMKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgICB0aGlzLnN0YXJ0KCk7XG4gICAgICByZXR1cm4gdG91ckluc3RhbmNlO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tY29uc29sZVxuICAgICAgY29uc29sZS53YXJuKGBUb3VyICR7dG91ck5hbWV9IGRvZXMgbm90IGV4aXN0LiBQbGVhc2UgdHJ5IGFub3RoZXIgdG91ci5gKTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgLy8gRmluZHMgdGhlIHJpZ2h0IHJlZ2lzdGVyZWQgdG91ciBieSB1c2luZyBxdWVyeVBhcmFtc1xuICAvLyBmaW5pc2hlcyBhbnkgb3RoZXIgdG91ciBhbmQgc3RhcnRzIHRoZSBuZXcgb25lLlxuICBpbml0aWFsaXplT25RdWVyeVBhcmFtcyhxdWVyeVBhcmFtOiBzdHJpbmcgPSAndG91cicpOiBPYnNlcnZhYmxlPFBhcmFtTWFwPiB7XG4gICAgcmV0dXJuIHRoaXMuX3JvdXRlLnF1ZXJ5UGFyYW1NYXAucGlwZShcbiAgICAgIGRlYm91bmNlVGltZSgxMDApLFxuICAgICAgdGFwKChwYXJhbXM6IFBhcmFtTWFwKSA9PiB7XG4gICAgICAgIGNvbnN0IHRvdXJQYXJhbSA9IHBhcmFtcy5nZXQocXVlcnlQYXJhbSk7XG4gICAgICAgIGlmICh0b3VyUGFyYW0pIHtcbiAgICAgICAgICB0aGlzLnN0YXJ0VG91cih0b3VyUGFyYW0pO1xuICAgICAgICAgIC8vIGdldCBjdXJyZW50IHNlYXJjaCBwYXJhbWV0ZXJzXG4gICAgICAgICAgY29uc3Qgc2VhcmNoUGFyYW1zOiBVUkxTZWFyY2hQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKFxuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLnNlYXJjaFxuICAgICAgICAgICk7XG4gICAgICAgICAgLy8gZGVsZXRlIHRvdXIgcXVlcnlQYXJhbVxuICAgICAgICAgIHNlYXJjaFBhcmFtcy5kZWxldGUocXVlcnlQYXJhbSk7XG4gICAgICAgICAgLy8gYnVpbGQgbmV3IFVSTCBzdHJpbmcgd2l0aG91dCBpdFxuICAgICAgICAgIGxldCB1cmw6IHN0cmluZyA9XG4gICAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wgK1xuICAgICAgICAgICAgJy8vJyArXG4gICAgICAgICAgICB3aW5kb3cubG9jYXRpb24uaG9zdCArXG4gICAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWU7XG4gICAgICAgICAgaWYgKHNlYXJjaFBhcmFtcy50b1N0cmluZygpKSB7XG4gICAgICAgICAgICB1cmwgKz0gJz8nICsgc2VhcmNoUGFyYW1zLnRvU3RyaW5nKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIHJlcGxhY2Ugc3RhdGUgaW4gaGlzdG9yeSB3aXRob3V0IHRyaWdnZXJpbmcgYSBuYXZpZ2F0aW9uXG4gICAgICAgICAgd2luZG93Lmhpc3RvcnkucmVwbGFjZVN0YXRlKHsgcGF0aDogdXJsIH0sICcnLCB1cmwpO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBzZXROZXh0QnRuRGlzYWJpbGl0eShzdGVwSWQ6IHN0cmluZywgaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICh0aGlzLnNoZXBoZXJkVG91ci5nZXRCeUlkKHN0ZXBJZCkpIHtcbiAgICAgIGNvbnN0IHN0ZXBPcHRpb25zOiBJVG91clN0ZXAgPSAodGhpcy5zaGVwaGVyZFRvdXIuZ2V0QnlJZChzdGVwSWQpIGFzIGFueSlcbiAgICAgICAgLm9wdGlvbnM7XG4gICAgICBzdGVwT3B0aW9ucy5idXR0b25zPy5mb3JFYWNoKChidXR0b246IFRvdXJTdGVwQnV0dG9uKSA9PiB7XG4gICAgICAgIGlmIChidXR0b24udGV4dCA9PT0gJ2NoZXZyb25fcmlnaHQnKSB7XG4gICAgICAgICAgYnV0dG9uLmRpc2FibGVkID0gaXNEaXNhYmxlZDtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB0aGlzLnNoZXBoZXJkVG91ci5nZXRCeUlkKHN0ZXBJZCk/LnVwZGF0ZVN0ZXBPcHRpb25zKHN0ZXBPcHRpb25zKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIF9sb2FkVG91cih0b3VyVXJsOiBzdHJpbmcpOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHJlcXVlc3Q6IE9ic2VydmFibGU8b2JqZWN0PiA9IHRoaXMuX2h0dHBDbGllbnQuZ2V0KHRvdXJVcmwpO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgcmVxdWVzdFxuICAgICAgICAucGlwZShcbiAgICAgICAgICBtYXAoKHJlc3VsdFNldDogYW55KSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShyZXN1bHRTZXQpKTtcbiAgICAgICAgICB9KVxuICAgICAgICApXG4gICAgICAgIC50b1Byb21pc2UoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfZ2V0VG91cihrZXk6IHN0cmluZyk6IElHdWlkZWRUb3VyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fdG91cnNNYXAuZ2V0KGtleSk7XG4gIH1cblxuICBwcml2YXRlIF9jb25maWd1cmVSb3V0ZXNGb3JTdGVwcyhcbiAgICByb3V0ZWRTdGVwczogSUd1aWRlZFRvdXJTdGVwW11cbiAgKTogSUd1aWRlZFRvdXJTdGVwW10ge1xuICAgIHJvdXRlZFN0ZXBzLmZvckVhY2goKHN0ZXA6IElHdWlkZWRUb3VyU3RlcCkgPT4ge1xuICAgICAgaWYgKHN0ZXAucm91dGluZykge1xuICAgICAgICBjb25zdCByb3V0ZTogc3RyaW5nID0gc3RlcC5yb3V0aW5nLnJvdXRlO1xuICAgICAgICAvLyBpZiB0aGVyZSBpcyBhIGJlZm9yZVNob3dQcm9taXNlLCB0aGVuIHdlIHNhdmUgaXQgYW5kIGNhbGwgaXQgYWZ0ZXIgdGhlIG5hdmlnYXRpb25cbiAgICAgICAgaWYgKHN0ZXAuYmVmb3JlU2hvd1Byb21pc2UpIHtcbiAgICAgICAgICBjb25zdCBiZWZvcmVTaG93UHJvbWlzZTogKCkgPT4gUHJvbWlzZTx2b2lkPiA9IHN0ZXAuYmVmb3JlU2hvd1Byb21pc2U7XG4gICAgICAgICAgc3RlcC5iZWZvcmVTaG93UHJvbWlzZSA9ICgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9yb3V0ZXJcbiAgICAgICAgICAgICAgLm5hdmlnYXRlKFtyb3V0ZV0sIHN0ZXAucm91dGluZz8uZXh0cmFzKVxuICAgICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGJlZm9yZVNob3dQcm9taXNlKCk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3RlcC5iZWZvcmVTaG93UHJvbWlzZSA9ICgpID0+IHRoaXMuX3JvdXRlci5uYXZpZ2F0ZShbcm91dGVdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHJvdXRlZFN0ZXBzO1xuICB9XG59XG4iXX0=