@angular/material 16.1.2 → 16.2.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/button/index.d.ts +11 -35
  2. package/card/_card-theme.scss +4 -7
  3. package/checkbox/_checkbox-theme.scss +1 -4
  4. package/core/index.d.ts +37 -0
  5. package/core/style/_sass-utils.scss +12 -0
  6. package/core/tokens/_token-utils.scss +11 -2
  7. package/core/tokens/m2/mat/_slide-toggle.scss +52 -0
  8. package/core/tokens/m2/mat/_table.scss +97 -0
  9. package/core/tokens/m2/mdc/_switch.scss +182 -0
  10. package/esm2022/button/button-base.mjs +32 -17
  11. package/esm2022/button/button.mjs +3 -3
  12. package/esm2022/button/fab.mjs +5 -5
  13. package/esm2022/button/icon-button.mjs +4 -15
  14. package/esm2022/core/private/index.mjs +9 -0
  15. package/esm2022/core/private/ripple-loader.mjs +133 -0
  16. package/esm2022/core/public-api.mjs +2 -1
  17. package/esm2022/core/version.mjs +1 -1
  18. package/esm2022/legacy-autocomplete/autocomplete-trigger.mjs +2 -2
  19. package/esm2022/slide-toggle/slide-toggle-config.mjs +2 -2
  20. package/esm2022/slide-toggle/slide-toggle.mjs +16 -4
  21. package/esm2022/table/table.mjs +2 -2
  22. package/fesm2022/button.mjs +57 -156
  23. package/fesm2022/button.mjs.map +1 -1
  24. package/fesm2022/core.mjs +124 -3
  25. package/fesm2022/core.mjs.map +1 -1
  26. package/fesm2022/legacy-autocomplete.mjs.map +1 -1
  27. package/fesm2022/slide-toggle.mjs +16 -4
  28. package/fesm2022/slide-toggle.mjs.map +1 -1
  29. package/fesm2022/table.mjs +2 -2
  30. package/fesm2022/table.mjs.map +1 -1
  31. package/package.json +7 -7
  32. package/prebuilt-themes/deeppurple-amber.css +1 -1
  33. package/prebuilt-themes/indigo-pink.css +1 -1
  34. package/prebuilt-themes/pink-bluegrey.css +1 -1
  35. package/prebuilt-themes/purple-green.css +1 -1
  36. package/schematics/ng-add/index.js +2 -2
  37. package/schematics/ng-add/index.mjs +2 -2
  38. package/slide-toggle/_slide-toggle-theme.scss +26 -75
  39. package/slide-toggle/index.d.ts +7 -1
  40. package/table/_table-theme.scss +24 -40
  41. package/esm2022/button/button-lazy-loader.mjs +0 -113
@@ -1,73 +1,12 @@
1
1
  @use 'sass:map';
2
- @use 'sass:color';
3
2
  @use '@material/switch/switch-theme' as mdc-switch-theme;
4
- @use '@material/theme/color-palette' as mdc-color-palette;
5
3
  @use '@material/form-field' as mdc-form-field;
6
4
  @use '../core/theming/theming';
7
5
  @use '../core/mdc-helpers/mdc-helpers';
8
6
  @use '../core/typography/typography';
9
-
10
-
11
- // Generates all color mapping for the properties that only change based on the theme.
12
- @function _get-theme-base-map($is-dark) {
13
- $on-surface: if($is-dark, mdc-color-palette.$grey-100, mdc-color-palette.$grey-800);
14
- $hairline: if($is-dark, mdc-color-palette.$grey-700, mdc-color-palette.$grey-300);
15
- $on-surface-variant: if($is-dark, mdc-color-palette.$grey-500, mdc-color-palette.$grey-700);
16
- $on-surface-state-content: if($is-dark, mdc-color-palette.$grey-50, mdc-color-palette.$grey-900);
17
- $disabled-handle-color: if($is-dark, #000, mdc-color-palette.$grey-800);
18
- $icon-color: if($is-dark, mdc-color-palette.$grey-900, #fff);
19
-
20
- @return (
21
- disabled-selected-handle-color: $disabled-handle-color,
22
- disabled-unselected-handle-color: $disabled-handle-color,
23
-
24
- disabled-selected-track-color: $on-surface,
25
- disabled-unselected-track-color: $on-surface,
26
- unselected-focus-state-layer-color: $on-surface,
27
- unselected-pressed-state-layer-color: $on-surface,
28
- unselected-hover-state-layer-color: $on-surface,
29
-
30
- unselected-focus-track-color: $hairline,
31
- unselected-hover-track-color: $hairline,
32
- unselected-pressed-track-color: $hairline,
33
- unselected-track-color: $hairline,
34
-
35
- unselected-focus-handle-color: $on-surface-state-content,
36
- unselected-hover-handle-color: $on-surface-state-content,
37
- unselected-pressed-handle-color: $on-surface-state-content,
38
-
39
- handle-surface-color: surface,
40
- unselected-handle-color: $on-surface-variant,
41
-
42
- selected-icon-color: $icon-color,
43
- disabled-selected-icon-color: $icon-color,
44
- disabled-unselected-icon-color: $icon-color,
45
- unselected-icon-color: $icon-color,
46
- );
47
- }
48
-
49
- // Generates the mapping for the properties that change based on the slide toggle color.
50
- @function _get-theme-color-map($color-palette, $is-dark) {
51
- $primary: theming.get-color-from-palette($color-palette, if($is-dark, 300, 600));
52
- $state-content: theming.get-color-from-palette($color-palette, if($is-dark, 200, 900));
53
- $inverse: theming.get-color-from-palette($color-palette, if($is-dark, 600, 300));
54
-
55
- @return (
56
- selected-focus-state-layer-color: $primary,
57
- selected-handle-color: $primary,
58
- selected-hover-state-layer-color: $primary,
59
- selected-pressed-state-layer-color: $primary,
60
-
61
- selected-focus-handle-color: $state-content,
62
- selected-hover-handle-color: $state-content,
63
- selected-pressed-handle-color: $state-content,
64
-
65
- selected-focus-track-color: $inverse,
66
- selected-hover-track-color: $inverse,
67
- selected-pressed-track-color: $inverse,
68
- selected-track-color: $inverse,
69
- );
70
- }
7
+ @use '../core/tokens/m2/mdc/switch' as m2-mdc-switch;
8
+ @use '../core/tokens/m2/mat/slide-toggle' as m2-mat-slide-toggle;
9
+ @use '../core/tokens/token-utils';
71
10
 
72
11
  @mixin color($config-or-theme) {
73
12
  $config: theming.get-color-config($config-or-theme);
@@ -77,28 +16,32 @@
77
16
  $is-dark: map.get($config, is-dark);
78
17
  $foreground: map.get($config, foreground);
79
18
 
19
+ $mdc-switch-color-tokens: m2-mdc-switch.get-color-tokens($config);
20
+
80
21
  @include mdc-helpers.using-mdc-theme($config) {
81
- // MDC's switch doesn't support a `color` property. We add support
82
- // for it by adding a CSS class for accent and warn style.
22
+ // Add values for MDC slide toggles tokens
83
23
  .mat-mdc-slide-toggle {
84
24
  @include mdc-form-field.core-styles($query: mdc-helpers.$mdc-theme-styles-query);
85
- @include mdc-switch-theme.theme(_get-theme-base-map($is-dark));
25
+ @include mdc-switch-theme.theme($mdc-switch-color-tokens);
86
26
 
87
27
  // MDC should set the disabled color on the label, but doesn't, so we do it here instead.
88
28
  .mdc-switch--disabled + label {
89
29
  color: theming.get-color-from-palette($foreground, disabled-text);
90
30
  }
91
31
 
92
- &.mat-primary {
93
- @include mdc-switch-theme.theme(_get-theme-color-map($primary, $is-dark));
94
- }
95
-
32
+ // Change the color palette related tokens to accent or warn if applicable
96
33
  &.mat-accent {
97
- @include mdc-switch-theme.theme(_get-theme-color-map($accent, $is-dark));
34
+ @include mdc-switch-theme.theme(m2-mdc-switch.private-get-color-palette-color-tokens(
35
+ map.get($config, accent),
36
+ map.get($config, is-dark)
37
+ ));
98
38
  }
99
39
 
100
40
  &.mat-warn {
101
- @include mdc-switch-theme.theme(_get-theme-color-map($warn, $is-dark));
41
+ @include mdc-switch-theme.theme(m2-mdc-switch.private-get-color-palette-color-tokens(
42
+ map.get($config, warn),
43
+ map.get($config, is-dark)
44
+ ));
102
45
  }
103
46
  }
104
47
  }
@@ -107,8 +50,17 @@
107
50
  @mixin typography($config-or-theme) {
108
51
  $config: typography.private-typography-to-2018-config(
109
52
  theming.get-typography-config($config-or-theme));
110
- @include mdc-helpers.using-mdc-typography($config) {
53
+ $mdc-switch-typography-tokens: m2-mdc-switch.get-typography-tokens($config);
54
+ $mat-slide-toggle-typography-tokens: m2-mat-slide-toggle.get-typography-tokens($config);
55
+
56
+ //Add values for MDC slide toggle tokens
57
+ .mat-mdc-slide-toggle {
111
58
  @include mdc-form-field.core-styles($query: mdc-helpers.$mdc-typography-styles-query);
59
+ @include mdc-switch-theme.theme($mdc-switch-typography-tokens);
60
+ @include token-utils.create-token-values(
61
+ m2-mat-slide-toggle.$prefix,
62
+ $mat-slide-toggle-typography-tokens
63
+ );
112
64
  }
113
65
  }
114
66
 
@@ -138,4 +90,3 @@
138
90
  }
139
91
  }
140
92
  }
141
-
@@ -101,6 +101,10 @@ export declare abstract class _MatSlideToggleBase<T> extends _MatSlideToggleMixi
101
101
  /** Whether the slide-toggle element is checked or not. */
102
102
  get checked(): boolean;
103
103
  set checked(value: BooleanInput);
104
+ /** Whether to hide the icon inside of the slide toggle. */
105
+ get hideIcon(): boolean;
106
+ set hideIcon(value: BooleanInput);
107
+ private _hideIcon;
104
108
  /** An event will be dispatched each time the slide-toggle changes its value. */
105
109
  readonly change: EventEmitter<T>;
106
110
  /**
@@ -129,7 +133,7 @@ export declare abstract class _MatSlideToggleBase<T> extends _MatSlideToggleMixi
129
133
  */
130
134
  protected _emitChangeEvent(): void;
131
135
  static ɵfac: i0.ɵɵFactoryDeclaration<_MatSlideToggleBase<any>, never>;
132
- static ɵdir: i0.ɵɵDirectiveDeclaration<_MatSlideToggleBase<any>, never, never, { "name": { "alias": "name"; "required": false; }; "id": { "alias": "id"; "required": false; }; "labelPosition": { "alias": "labelPosition"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; }; "required": { "alias": "required"; "required": false; }; "checked": { "alias": "checked"; "required": false; }; }, { "change": "change"; "toggleChange": "toggleChange"; }, never, never, false, never>;
136
+ static ɵdir: i0.ɵɵDirectiveDeclaration<_MatSlideToggleBase<any>, never, never, { "name": { "alias": "name"; "required": false; }; "id": { "alias": "id"; "required": false; }; "labelPosition": { "alias": "labelPosition"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; }; "required": { "alias": "required"; "required": false; }; "checked": { "alias": "checked"; "required": false; }; "hideIcon": { "alias": "hideIcon"; "required": false; }; }, { "change": "change"; "toggleChange": "toggleChange"; }, never, never, false, never>;
133
137
  }
134
138
 
135
139
  /** Change event object emitted by a slide toggle. */
@@ -151,6 +155,8 @@ export declare interface MatSlideToggleDefaultOptions {
151
155
  disableToggleValue?: boolean;
152
156
  /** Default color for slide toggles. */
153
157
  color?: ThemePalette;
158
+ /** Whether to hide the icon inside the slide toggle. */
159
+ hideIcon?: boolean;
154
160
  }
155
161
 
156
162
  /** @docs-private */
@@ -1,60 +1,44 @@
1
- @use 'sass:map';
2
- @use '@material/theme/theme-color' as mdc-theme-color;
3
- @use '@material/data-table/data-table' as mdc-data-table;
4
- @use '@material/data-table' as mdc-data-table-theme;
1
+ @use '../core/tokens/m2/mat/table' as tokens-mat-table;
5
2
  @use '../core/theming/theming';
6
- @use '../core/mdc-helpers/mdc-helpers';
7
3
  @use '../core/typography/typography';
4
+ @use '../core/tokens/token-utils';
8
5
 
9
- @mixin color($config-or-theme) {
10
- $config: theming.get-color-config($config-or-theme);
11
- // Save original values of MDC global variables. We need to save these so we can restore the
12
- // variables to their original values and prevent unintended side effects from using this mixin.
13
- $orig-selected-row-fill-color: mdc-data-table-theme.$selected-row-fill-color;
14
- $orig-divider-color: mdc-data-table-theme.$divider-color;
15
- $orig-row-hover-fill-color: mdc-data-table-theme.$row-hover-fill-color;
16
- $orig-header-row-text-color: mdc-data-table-theme.$header-row-text-color;
17
- $orig-row-text-color: mdc-data-table-theme.$row-text-color;
18
- $orig-stroke-color: mdc-data-table-theme.$stroke-color;
19
-
20
- @include mdc-helpers.using-mdc-theme($config) {
21
- mdc-data-table-theme.$selected-row-fill-color: rgba(mdc-theme-color.prop-value(primary), 0.04);
22
- mdc-data-table-theme.$divider-color: rgba(mdc-theme-color.prop-value(on-surface), 0.12);
23
- mdc-data-table-theme.$row-hover-fill-color: rgba(mdc-theme-color.prop-value(on-surface), 0.04);
24
- mdc-data-table-theme.$header-row-text-color: rgba(mdc-theme-color.prop-value(on-surface), 0.87);
25
- mdc-data-table-theme.$row-text-color: rgba(mdc-theme-color.prop-value(on-surface), 0.87);
26
- mdc-data-table-theme.$stroke-color: rgba(mdc-theme-color.prop-value(on-surface), 0.12);
27
-
28
- @include mdc-data-table.table-styles($query: mdc-helpers.$mdc-theme-styles-query);
6
+ @mixin _output-tokens {
7
+ @if (&) {
8
+ @content;
9
+ }
10
+ @else {
11
+ html {
12
+ @content;
13
+ }
29
14
  }
15
+ }
30
16
 
31
- // Restore original values of MDC global variables.
32
- mdc-data-table-theme.$selected-row-fill-color: $orig-selected-row-fill-color;
33
- mdc-data-table-theme.$divider-color: $orig-divider-color;
34
- mdc-data-table-theme.$row-hover-fill-color: $orig-row-hover-fill-color;
35
- mdc-data-table-theme.$header-row-text-color: $orig-header-row-text-color;
36
- mdc-data-table-theme.$row-text-color: $orig-row-text-color;
37
- mdc-data-table-theme.$stroke-color: $orig-stroke-color;
17
+ @mixin color($config-or-theme) {
18
+ $config: theming.get-color-config($config-or-theme);
38
19
 
39
- .mat-mdc-table {
40
- $background: map.get($config, background);
41
- background: theming.get-color-from-palette($background, 'card');
20
+ @include _output-tokens {
21
+ @include token-utils.create-token-values(tokens-mat-table.$prefix,
22
+ tokens-mat-table.get-color-tokens($config));
42
23
  }
43
24
  }
44
25
 
45
26
  @mixin typography($config-or-theme) {
46
27
  $config: typography.private-typography-to-2018-config(
47
28
  theming.get-typography-config($config-or-theme));
48
- @include mdc-helpers.using-mdc-typography($config) {
49
- @include mdc-data-table.table-styles($query: mdc-helpers.$mdc-typography-styles-query);
29
+
30
+ @include _output-tokens {
31
+ @include token-utils.create-token-values(tokens-mat-table.$prefix,
32
+ tokens-mat-table.get-typography-tokens($config));
50
33
  }
51
34
  }
52
35
 
53
36
  @mixin density($config-or-theme) {
54
37
  $density-scale: theming.get-density-config($config-or-theme);
55
- .mat-mdc-table {
56
- @include mdc-data-table-theme.density($density-scale,
57
- $query: mdc-helpers.$mdc-base-styles-query);
38
+
39
+ @include _output-tokens {
40
+ @include token-utils.create-token-values(tokens-mat-table.$prefix,
41
+ tokens-mat-table.get-density-tokens($density-scale));
58
42
  }
59
43
  }
60
44
 
@@ -1,113 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright Google LLC All Rights Reserved.
4
- *
5
- * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.io/license
7
- */
8
- import { DOCUMENT } from '@angular/common';
9
- import { ANIMATION_MODULE_TYPE, ElementRef, Injectable, NgZone, inject, } from '@angular/core';
10
- import { MAT_RIPPLE_GLOBAL_OPTIONS, MatRipple, RippleRenderer, } from '@angular/material/core';
11
- import { Platform } from '@angular/cdk/platform';
12
- import * as i0 from "@angular/core";
13
- /** The options for the MatButtonRippleLoader's event listeners. */
14
- const eventListenerOptions = { capture: true };
15
- /** The events that should trigger the initialization of the ripple. */
16
- const rippleInteractionEvents = ['focus', 'click', 'mouseenter', 'touchstart'];
17
- /** The attribute attached to a mat-button whose ripple has not yet been initialized. */
18
- export const MAT_BUTTON_RIPPLE_UNINITIALIZED = 'mat-button-ripple-uninitialized';
19
- /**
20
- * Handles attaching the MatButton's ripple on demand.
21
- *
22
- * This service allows us to avoid eagerly creating & attaching the MatButton's ripple.
23
- * It works by creating & attaching the ripple only when a MatButton is first interacted with.
24
- */
25
- export class MatButtonLazyLoader {
26
- constructor() {
27
- this._document = inject(DOCUMENT, { optional: true });
28
- this._animationMode = inject(ANIMATION_MODULE_TYPE, { optional: true });
29
- this._globalRippleOptions = inject(MAT_RIPPLE_GLOBAL_OPTIONS, { optional: true });
30
- this._platform = inject(Platform);
31
- this._ngZone = inject(NgZone);
32
- /** Handles creating and attaching button internals when a button is initially interacted with. */
33
- this._onInteraction = (event) => {
34
- if (event.target === this._document) {
35
- return;
36
- }
37
- const eventTarget = event.target;
38
- // TODO(wagnermaciel): Consider batching these events to improve runtime performance.
39
- const button = eventTarget.closest(`[${MAT_BUTTON_RIPPLE_UNINITIALIZED}]`);
40
- if (button) {
41
- button.removeAttribute(MAT_BUTTON_RIPPLE_UNINITIALIZED);
42
- this._appendRipple(button);
43
- }
44
- };
45
- this._ngZone.runOutsideAngular(() => {
46
- for (const event of rippleInteractionEvents) {
47
- this._document?.addEventListener(event, this._onInteraction, eventListenerOptions);
48
- }
49
- });
50
- }
51
- ngOnDestroy() {
52
- for (const event of rippleInteractionEvents) {
53
- this._document?.removeEventListener(event, this._onInteraction, eventListenerOptions);
54
- }
55
- }
56
- /** Creates a MatButtonRipple and appends it to the given button element. */
57
- _appendRipple(button) {
58
- if (!this._document) {
59
- return;
60
- }
61
- const ripple = this._document.createElement('span');
62
- ripple.classList.add('mat-mdc-button-ripple');
63
- const target = new MatButtonRippleTarget(button, this._globalRippleOptions ? this._globalRippleOptions : undefined, this._animationMode ? this._animationMode : undefined);
64
- target.rippleConfig.centered = button.hasAttribute('mat-icon-button');
65
- const rippleRenderer = new RippleRenderer(target, this._ngZone, ripple, this._platform);
66
- rippleRenderer.setupTriggerEvents(button);
67
- button.append(ripple);
68
- }
69
- _createMatRipple(button) {
70
- if (!this._document) {
71
- return;
72
- }
73
- button.querySelector('.mat-mdc-button-ripple')?.remove();
74
- button.removeAttribute(MAT_BUTTON_RIPPLE_UNINITIALIZED);
75
- const rippleEl = this._document.createElement('span');
76
- rippleEl.classList.add('mat-mdc-button-ripple');
77
- const ripple = new MatRipple(new ElementRef(rippleEl), this._ngZone, this._platform, this._globalRippleOptions ? this._globalRippleOptions : undefined, this._animationMode ? this._animationMode : undefined);
78
- ripple._isInitialized = true;
79
- ripple.trigger = button;
80
- button.append(rippleEl);
81
- return ripple;
82
- }
83
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: MatButtonLazyLoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
84
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: MatButtonLazyLoader, providedIn: 'root' }); }
85
- }
86
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: MatButtonLazyLoader, decorators: [{
87
- type: Injectable,
88
- args: [{ providedIn: 'root' }]
89
- }], ctorParameters: function () { return []; } });
90
- /**
91
- * The RippleTarget for the lazily rendered MatButton ripple.
92
- * It handles ripple configuration and disabled state for ripples interactions.
93
- *
94
- * Note that this configuration is usually handled by the MatRipple, but the MatButtonLazyLoader does not use the
95
- * MatRipple Directive. In order to create & attach a ripple on demand, it uses the "lower level" RippleRenderer.
96
- */
97
- class MatButtonRippleTarget {
98
- constructor(_button, _globalRippleOptions, animationMode) {
99
- this._button = _button;
100
- this._globalRippleOptions = _globalRippleOptions;
101
- this._setRippleConfig(_globalRippleOptions, animationMode);
102
- }
103
- _setRippleConfig(globalRippleOptions, animationMode) {
104
- this.rippleConfig = globalRippleOptions || {};
105
- if (animationMode === 'NoopAnimations') {
106
- this.rippleConfig.animation = { enterDuration: 0, exitDuration: 0 };
107
- }
108
- }
109
- get rippleDisabled() {
110
- return this._button.hasAttribute('disabled') || !!this._globalRippleOptions?.disabled;
111
- }
112
- }
113
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnV0dG9uLWxhenktbG9hZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21hdGVyaWFsL2J1dHRvbi9idXR0b24tbGF6eS1sb2FkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQ3pDLE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsVUFBVSxFQUNWLFVBQVUsRUFDVixNQUFNLEVBRU4sTUFBTSxHQUNQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsU0FBUyxFQUdULGNBQWMsR0FFZixNQUFNLHdCQUF3QixDQUFDO0FBQ2hDLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQzs7QUFFL0MsbUVBQW1FO0FBQ25FLE1BQU0sb0JBQW9CLEdBQUcsRUFBQyxPQUFPLEVBQUUsSUFBSSxFQUFDLENBQUM7QUFFN0MsdUVBQXVFO0FBQ3ZFLE1BQU0sdUJBQXVCLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQztBQUUvRSx3RkFBd0Y7QUFDeEYsTUFBTSxDQUFDLE1BQU0sK0JBQStCLEdBQUcsaUNBQWlDLENBQUM7QUFFakY7Ozs7O0dBS0c7QUFFSCxNQUFNLE9BQU8sbUJBQW1CO0lBTzlCO1FBTlEsY0FBUyxHQUFHLE1BQU0sQ0FBQyxRQUFRLEVBQUUsRUFBQyxRQUFRLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQztRQUMvQyxtQkFBYyxHQUFHLE1BQU0sQ0FBQyxxQkFBcUIsRUFBRSxFQUFDLFFBQVEsRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUFDO1FBQ2pFLHlCQUFvQixHQUFHLE1BQU0sQ0FBQyx5QkFBeUIsRUFBRSxFQUFDLFFBQVEsRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUFDO1FBQzNFLGNBQVMsR0FBRyxNQUFN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SSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxRQUFRLENBQUM7SUFDeEYsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7RE9DVU1FTlR9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBBTklNQVRJT05fTU9EVUxFX1RZUEUsXG4gIEVsZW1lbnRSZWYsXG4gIEluamVjdGFibGUsXG4gIE5nWm9uZSxcbiAgT25EZXN0cm95LFxuICBpbmplY3QsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgTUFUX1JJUFBMRV9HTE9CQUxfT1BUSU9OUyxcbiAgTWF0UmlwcGxlLFxuICBSaXBwbGVDb25maWcsXG4gIFJpcHBsZUdsb2JhbE9wdGlvbnMsXG4gIFJpcHBsZVJlbmRlcmVyLFxuICBSaXBwbGVUYXJnZXQsXG59IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NvcmUnO1xuaW1wb3J0IHtQbGF0Zm9ybX0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BsYXRmb3JtJztcblxuLyoqIFRoZSBvcHRpb25zIGZvciB0aGUgTWF0QnV0dG9uUmlwcGxlTG9hZGVyJ3MgZXZlbnQgbGlzdGVuZXJzLiAqL1xuY29uc3QgZXZlbnRMaXN0ZW5lck9wdGlvbnMgPSB7Y2FwdHVyZTogdHJ1ZX07XG5cbi8qKiBUaGUgZXZlbnRzIHRoYXQgc2hvdWxkIHRyaWdnZXIgdGhlIGluaXRpYWxpemF0aW9uIG9mIHRoZSByaXBwbGUuICovXG5jb25zdCByaXBwbGVJbnRlcmFjdGlvbkV2ZW50cyA9IFsnZm9jdXMnLCAnY2xpY2snLCAnbW91c2VlbnRlcicsICd0b3VjaHN0YXJ0J107XG5cbi8qKiBUaGUgYXR0cmlidXRlIGF0dGFjaGVkIHRvIGEgbWF0LWJ1dHRvbiB3aG9zZSByaXBwbGUgaGFzIG5vdCB5ZXQgYmVlbiBpbml0aWFsaXplZC4gKi9cbmV4cG9ydCBjb25zdCBNQVRfQlVUVE9OX1JJUFBMRV9VTklOSVRJQUxJWkVEID0gJ21hdC1idXR0b24tcmlwcGxlLXVuaW5pdGlhbGl6ZWQnO1xuXG4vKipcbiAqIEhhbmRsZXMgYXR0YWNoaW5nIHRoZSBNYXRCdXR0b24ncyByaXBwbGUgb24gZGVtYW5kLlxuICpcbiAqIFRoaXMgc2VydmljZSBhbGxvd3MgdXMgdG8gYXZvaWQgZWFnZXJseSBjcmVhdGluZyAmIGF0dGFjaGluZyB0aGUgTWF0QnV0dG9uJ3MgcmlwcGxlLlxuICogSXQgd29ya3MgYnkgY3JlYXRpbmcgJiBhdHRhY2hpbmcgdGhlIHJpcHBsZSBvbmx5IHdoZW4gYSBNYXRCdXR0b24gaXMgZmlyc3QgaW50ZXJhY3RlZCB3aXRoLlxuICovXG5ASW5qZWN0YWJsZSh7cHJvdmlkZWRJbjogJ3Jvb3QnfSlcbmV4cG9ydCBjbGFzcyBNYXRCdXR0b25MYXp5TG9hZGVyIGltcGxlbWVudHMgT25EZXN0cm95IHtcbiAgcHJpdmF0ZSBfZG9jdW1lbnQgPSBpbmplY3QoRE9DVU1FTlQsIHtvcHRpb25hbDogdHJ1ZX0pO1xuICBwcml2YXRlIF9hbmltYXRpb25Nb2RlID0gaW5qZWN0KEFOSU1BVElPTl9NT0RVTEVfVFlQRSwge29wdGlvbmFsOiB0cnVlfSk7XG4gIHByaXZhdGUgX2dsb2JhbFJpcHBsZU9wdGlvbnMgPSBpbmplY3QoTUFUX1JJUFBMRV9HTE9CQUxfT1BUSU9OUywge29wdGlvbmFsOiB0cnVlfSk7XG4gIHByaXZhdGUgX3BsYXRmb3JtID0gaW5qZWN0KFBsYXRmb3JtKTtcbiAgcHJpdmF0ZSBfbmdab25lID0gaW5qZWN0KE5nWm9uZSk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5fbmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgIGZvciAoY29uc3QgZXZlbnQgb2YgcmlwcGxlSW50ZXJhY3Rpb25FdmVudHMpIHtcbiAgICAgICAgdGhpcy5fZG9jdW1lbnQ/LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIHRoaXMuX29uSW50ZXJhY3Rpb24sIGV2ZW50TGlzdGVuZXJPcHRpb25zKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIGZvciAoY29uc3QgZXZlbnQgb2YgcmlwcGxlSW50ZXJhY3Rpb25FdmVudHMpIHtcbiAgICAgIHRoaXMuX2RvY3VtZW50Py5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50LCB0aGlzLl9vbkludGVyYWN0aW9uLCBldmVudExpc3RlbmVyT3B0aW9ucyk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEhhbmRsZXMgY3JlYXRpbmcgYW5kIGF0dGFjaGluZyBidXR0b24gaW50ZXJuYWxzIHdoZW4gYSBidXR0b24gaXMgaW5pdGlhbGx5IGludGVyYWN0ZWQgd2l0aC4gKi9cbiAgcHJpdmF0ZSBfb25JbnRlcmFjdGlvbiA9IChldmVudDogRXZlbnQpID0+IHtcbiAgICBpZiAoZXZlbnQudGFyZ2V0ID09PSB0aGlzLl9kb2N1bWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBldmVudFRhcmdldCA9IGV2ZW50LnRhcmdldCBhcyBFbGVtZW50O1xuXG4gICAgLy8gVE9ETyh3YWduZXJtYWNpZWwpOiBDb25zaWRlciBiYXRjaGluZyB0aGVzZSBldmVudHMgdG8gaW1wcm92ZSBydW50aW1lIHBlcmZvcm1hbmNlLlxuXG4gICAgY29uc3QgYnV0dG9uID0gZXZlbnRUYXJnZXQuY2xvc2VzdChgWyR7TUFUX0JVVFRPTl9SSVBQTEVfVU5JTklUSUFMSVpFRH1dYCk7XG4gICAgaWYgKGJ1dHRvbikge1xuICAgICAgYnV0dG9uLnJlbW92ZUF0dHJpYnV0ZShNQVRfQlVUVE9OX1JJUFBMRV9VTklOSVRJQUxJWkVEKTtcbiAgICAgIHRoaXMuX2FwcGVuZFJpcHBsZShidXR0b24gYXMgSFRNTEVsZW1lbnQpO1xuICAgIH1cbiAgfTtcblxuICAvKiogQ3JlYXRlcyBhIE1hdEJ1dHRvblJpcHBsZSBhbmQgYXBwZW5kcyBpdCB0byB0aGUgZ2l2ZW4gYnV0dG9uIGVsZW1lbnQuICovXG4gIHByaXZhdGUgX2FwcGVuZFJpcHBsZShidXR0b246IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLl9kb2N1bWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByaXBwbGUgPSB0aGlzLl9kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgcmlwcGxlLmNsYXNzTGlzdC5hZGQoJ21hdC1tZGMtYnV0dG9uLXJpcHBsZScpO1xuXG4gICAgY29uc3QgdGFyZ2V0ID0gbmV3IE1hdEJ1dHRvblJpcHBsZVRhcmdldChcbiAgICAgIGJ1dHRvbixcbiAgICAgIHRoaXMuX2dsb2JhbFJpcHBsZU9wdGlvbnMgPyB0aGlzLl9nbG9iYWxSaXBwbGVPcHRpb25zIDogdW5kZWZpbmVkLFxuICAgICAgdGhpcy5fYW5pbWF0aW9uTW9kZSA/IHRoaXMuX2FuaW1hdGlvbk1vZGUgOiB1bmRlZmluZWQsXG4gICAgKTtcbiAgICB0YXJnZXQucmlwcGxlQ29uZmlnLmNlbnRlcmVkID0gYnV0dG9uLmhhc0F0dHJpYnV0ZSgnbWF0LWljb24tYnV0dG9uJyk7XG5cbiAgICBjb25zdCByaXBwbGVSZW5kZXJlciA9IG5ldyBSaXBwbGVSZW5kZXJlcih0YXJnZXQsIHRoaXMuX25nWm9uZSwgcmlwcGxlLCB0aGlzLl9wbGF0Zm9ybSk7XG4gICAgcmlwcGxlUmVuZGVyZXIuc2V0dXBUcmlnZ2VyRXZlbnRzKGJ1dHRvbik7XG4gICAgYnV0dG9uLmFwcGVuZChyaXBwbGUpO1xuICB9XG5cbiAgX2NyZWF0ZU1hdFJpcHBsZShidXR0b246IEhUTUxFbGVtZW50KTogTWF0UmlwcGxlIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXRoaXMuX2RvY3VtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGJ1dHRvbi5xdWVyeVNlbGVjdG9yKCcubWF0LW1kYy1idXR0b24tcmlwcGxlJyk/LnJlbW92ZSgpO1xuICAgIGJ1dHRvbi5yZW1vdmVBdHRyaWJ1dGUoTUFUX0JVVFRPTl9SSVBQTEVfVU5JTklUSUFMSVpFRCk7XG4gICAgY29uc3QgcmlwcGxlRWwgPSB0aGlzLl9kb2N1bWVudCEuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgIHJpcHBsZUVsLmNsYXNzTGlzdC5hZGQoJ21hdC1tZGMtYnV0dG9uLXJpcHBsZScpO1xuICAgIGNvbnN0IHJpcHBsZSA9IG5ldyBNYXRSaXBwbGUoXG4gICAgICBuZXcgRWxlbWVudFJlZihyaXBwbGVFbCksXG4gICAgICB0aGlzLl9uZ1pvbmUsXG4gICAgICB0aGlzLl9wbGF0Zm9ybSxcbiAgICAgIHRoaXMuX2dsb2JhbFJpcHBsZU9wdGlvbnMgPyB0aGlzLl9nbG9iYWxSaXBwbGVPcHRpb25zIDogdW5kZWZpbmVkLFxuICAgICAgdGhpcy5fYW5pbWF0aW9uTW9kZSA/IHRoaXMuX2FuaW1hdGlvbk1vZGUgOiB1bmRlZmluZWQsXG4gICAgKTtcbiAgICByaXBwbGUuX2lzSW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgIHJpcHBsZS50cmlnZ2VyID0gYnV0dG9uO1xuICAgIGJ1dHRvbi5hcHBlbmQocmlwcGxlRWwpO1xuICAgIHJldHVybiByaXBwbGU7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgUmlwcGxlVGFyZ2V0IGZvciB0aGUgbGF6aWx5IHJlbmRlcmVkIE1hdEJ1dHRvbiByaXBwbGUuXG4gKiBJdCBoYW5kbGVzIHJpcHBsZSBjb25maWd1cmF0aW9uIGFuZCBkaXNhYmxlZCBzdGF0ZSBmb3IgcmlwcGxlcyBpbnRlcmFjdGlvbnMuXG4gKlxuICogTm90ZSB0aGF0IHRoaXMgY29uZmlndXJhdGlvbiBpcyB1c3VhbGx5IGhhbmRsZWQgYnkgdGhlIE1hdFJpcHBsZSwgYnV0IHRoZSBNYXRCdXR0b25MYXp5TG9hZGVyIGRvZXMgbm90IHVzZSB0aGVcbiAqIE1hdFJpcHBsZSBEaXJlY3RpdmUuIEluIG9yZGVyIHRvIGNyZWF0ZSAmIGF0dGFjaCBhIHJpcHBsZSBvbiBkZW1hbmQsIGl0IHVzZXMgdGhlIFwibG93ZXIgbGV2ZWxcIiBSaXBwbGVSZW5kZXJlci5cbiAqL1xuY2xhc3MgTWF0QnV0dG9uUmlwcGxlVGFyZ2V0IGltcGxlbWVudHMgUmlwcGxlVGFyZ2V0IHtcbiAgcmlwcGxlQ29uZmlnOiBSaXBwbGVDb25maWcgJiBSaXBwbGVHbG9iYWxPcHRpb25zO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgX2J1dHRvbjogSFRNTEVsZW1lbnQsXG4gICAgcHJpdmF0ZSBfZ2xvYmFsUmlwcGxlT3B0aW9ucz86IFJpcHBsZUdsb2JhbE9wdGlvbnMsXG4gICAgYW5pbWF0aW9uTW9kZT86IHN0cmluZyxcbiAgKSB7XG4gICAgdGhpcy5fc2V0UmlwcGxlQ29uZmlnKF9nbG9iYWxSaXBwbGVPcHRpb25zLCBhbmltYXRpb25Nb2RlKTtcbiAgfVxuXG4gIHByaXZhdGUgX3NldFJpcHBsZUNvbmZpZyhnbG9iYWxSaXBwbGVPcHRpb25zPzogUmlwcGxlR2xvYmFsT3B0aW9ucywgYW5pbWF0aW9uTW9kZT86IHN0cmluZykge1xuICAgIHRoaXMucmlwcGxlQ29uZmlnID0gZ2xvYmFsUmlwcGxlT3B0aW9ucyB8fCB7fTtcbiAgICBpZiAoYW5pbWF0aW9uTW9kZSA9PT0gJ05vb3BBbmltYXRpb25zJykge1xuICAgICAgdGhpcy5yaXBwbGVDb25maWcuYW5pbWF0aW9uID0ge2VudGVyRHVyYXRpb246IDAsIGV4aXREdXJhdGlvbjogMH07XG4gICAgfVxuICB9XG5cbiAgZ2V0IHJpcHBsZURpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9idXR0b24uaGFzQXR0cmlidXRlKCdkaXNhYmxlZCcpIHx8ICEhdGhpcy5fZ2xvYmFsUmlwcGxlT3B0aW9ucz8uZGlzYWJsZWQ7XG4gIH1cbn1cbiJdfQ==