valtech-components 2.0.302 → 2.0.305

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 (32) hide show
  1. package/esm2022/lib/components/atoms/button/button.component.mjs +103 -23
  2. package/esm2022/lib/components/types.mjs +1 -1
  3. package/esm2022/lib/services/lang-provider/content.mjs +1 -72
  4. package/esm2022/lib/services/lang-provider/lang-provider.service.mjs +4 -9
  5. package/esm2022/lib/shared/utils/content.mjs +2 -8
  6. package/esm2022/public-api.mjs +1 -12
  7. package/fesm2022/valtech-components.mjs +124 -2824
  8. package/fesm2022/valtech-components.mjs.map +1 -1
  9. package/lib/components/atoms/button/button.component.d.ts +33 -2
  10. package/lib/components/types.d.ts +19 -7
  11. package/package.json +1 -1
  12. package/public-api.d.ts +0 -10
  13. package/esm2022/lib/examples/comprehensive-link-test.component.mjs +0 -208
  14. package/esm2022/lib/examples/custom-content-demo.component.mjs +0 -291
  15. package/esm2022/lib/examples/display-demo.component.mjs +0 -518
  16. package/esm2022/lib/examples/display-simple-example.component.mjs +0 -202
  17. package/esm2022/lib/examples/link-processing-example.component.mjs +0 -233
  18. package/esm2022/lib/examples/multi-language-demo.component.mjs +0 -304
  19. package/esm2022/lib/examples/reactive-components-demo.component.mjs +0 -303
  20. package/esm2022/lib/examples/reactivity-test.component.mjs +0 -200
  21. package/esm2022/lib/examples/selector-examples.component.mjs +0 -234
  22. package/esm2022/lib/examples/user-issue-test.component.mjs +0 -267
  23. package/lib/examples/comprehensive-link-test.component.d.ts +0 -23
  24. package/lib/examples/custom-content-demo.component.d.ts +0 -26
  25. package/lib/examples/display-demo.component.d.ts +0 -62
  26. package/lib/examples/display-simple-example.component.d.ts +0 -23
  27. package/lib/examples/link-processing-example.component.d.ts +0 -26
  28. package/lib/examples/multi-language-demo.component.d.ts +0 -34
  29. package/lib/examples/reactive-components-demo.component.d.ts +0 -45
  30. package/lib/examples/reactivity-test.component.d.ts +0 -27
  31. package/lib/examples/selector-examples.component.d.ts +0 -21
  32. package/lib/examples/user-issue-test.component.d.ts +0 -31
@@ -4,7 +4,7 @@ import { ContentService } from '../../../services/content.service';
4
4
  import { DownloadService } from '../../../services/download.service';
5
5
  import { IconService } from '../../../services/icons.service';
6
6
  import { NavigationService } from '../../../services/navigation.service';
7
- import { ButtonMetadata } from '../../types';
7
+ import { ButtonContentConfig, ButtonMetadata } from '../../types';
8
8
  import * as i0 from "@angular/core";
9
9
  export declare class ButtonComponent implements OnInit, OnDestroy {
10
10
  private download;
@@ -16,6 +16,10 @@ export declare class ButtonComponent implements OnInit, OnDestroy {
16
16
  WORKING: "WORKING";
17
17
  ERROR: "ERROR";
18
18
  };
19
+ /**
20
+ * Observable that provides the text content to display.
21
+ * This will be either static text or reactive content from the language service.
22
+ */
19
23
  displayText$: Observable<string>;
20
24
  private subscriptions;
21
25
  props: ButtonMetadata;
@@ -26,8 +30,35 @@ export declare class ButtonComponent implements OnInit, OnDestroy {
26
30
  constructor(download: DownloadService, icon: IconService, navigation: NavigationService, contentService: ContentService);
27
31
  ngOnInit(): void;
28
32
  ngOnDestroy(): void;
29
- private initializeDisplayText;
33
+ /**
34
+ * Set up the text content observable based on the props configuration.
35
+ * Priority: static text > reactive content with interpolation > reactive content
36
+ * This follows the same pattern as val-text component.
37
+ */
38
+ private setupDisplayText;
30
39
  clickHandler(): void;
31
40
  static ɵfac: i0.ɵɵFactoryDeclaration<ButtonComponent, never>;
32
41
  static ɵcmp: i0.ɵɵComponentDeclaration<ButtonComponent, "val-button", never, { "props": { "alias": "props"; "required": false; }; }, { "onClick": "onClick"; }, never, never, true, never>;
33
42
  }
43
+ /**
44
+ * Helper function to create reactive button props from content configuration.
45
+ * This provides a convenient way to create val-button props with reactive content.
46
+ * Follows the same pattern as createTextProps for consistency.
47
+ *
48
+ * @param contentConfig - Content configuration
49
+ * @param styleConfig - Optional style and behavior configuration
50
+ * @returns ButtonMetadata with content properties set
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // In component
55
+ * saveButtonProps: ButtonMetadata = createButtonProps({
56
+ * contentKey: 'save',
57
+ * contentClass: 'MyComponent'
58
+ * }, {
59
+ * color: 'primary',
60
+ * icon: { name: 'save', slot: 'start' }
61
+ * });
62
+ * ```
63
+ */
64
+ export declare function createButtonProps(contentConfig: ButtonContentConfig, styleConfig?: Partial<Pick<ButtonMetadata, 'color' | 'type' | 'state' | 'size' | 'fill' | 'icon' | 'expand' | 'shape' | 'handler'>>): ButtonMetadata;
@@ -203,15 +203,16 @@ export interface ButtonMetadata {
203
203
  color: Color;
204
204
  /** Button state */
205
205
  state: ComponentState;
206
- /** Static display text (takes precedence over textConfig) */
206
+ /** Static display text (takes precedence over reactive content) */
207
207
  text?: string;
208
208
  /** Reactive content configuration for button text */
209
- textConfig?: {
210
- className?: string;
211
- key: string;
212
- fallback?: string;
213
- interpolation?: Record<string, any>;
214
- };
209
+ contentKey?: string;
210
+ /** Component class name for content lookup (required with contentKey) */
211
+ contentClass?: string;
212
+ /** Fallback text if contentKey is not found */
213
+ contentFallback?: string;
214
+ /** Values to interpolate into the content string */
215
+ contentInterpolation?: Record<string, string | number>;
215
216
  /** Associated icon */
216
217
  icon?: IconMetada;
217
218
  /** Button shape */
@@ -229,3 +230,14 @@ export interface ButtonMetadata {
229
230
  /** Action handler */
230
231
  handler?: (value: any) => any | Promise<any>;
231
232
  }
233
+ /**
234
+ * Configuration for reactive content in val-button component.
235
+ * Use this interface when you only need to specify content-related properties.
236
+ * This follows the same pattern as TextContentConfig for consistency.
237
+ */
238
+ export interface ButtonContentConfig {
239
+ contentKey: string;
240
+ contentClass: string;
241
+ contentFallback?: string;
242
+ contentInterpolation?: Record<string, string | number>;
243
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valtech-components",
3
- "version": "2.0.302",
3
+ "version": "2.0.305",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^18.0.0",
6
6
  "@angular/core": "^18.0.0",
package/public-api.d.ts CHANGED
@@ -83,16 +83,6 @@ export * from './lib/components/organisms/wizard/wizard.component';
83
83
  export * from './lib/components/templates/layout/layout.component';
84
84
  export * from './lib/components/templates/simple/simple.component';
85
85
  export * from './lib/components/templates/simple/types';
86
- export * from './lib/examples/comprehensive-link-test.component';
87
- export * from './lib/examples/custom-content-demo.component';
88
- export * from './lib/examples/display-demo.component';
89
- export * from './lib/examples/display-simple-example.component';
90
- export * from './lib/examples/link-processing-example.component';
91
- export * from './lib/examples/multi-language-demo.component';
92
- export * from './lib/examples/reactive-components-demo.component';
93
- export * from './lib/examples/reactivity-test.component';
94
- export * from './lib/examples/selector-examples.component';
95
- export * from './lib/examples/user-issue-test.component';
96
86
  export * from './lib/services/content.service';
97
87
  export * from './lib/services/download.service';
98
88
  export * from './lib/services/icons.service';
@@ -1,208 +0,0 @@
1
- import { Component } from '@angular/core';
2
- import { TextComponent } from '../components/atoms/text/text.component';
3
- import * as i0 from "@angular/core";
4
- /**
5
- * ComprehensiveLinkTestComponent - Componente de prueba exhaustiva para el procesamiento de enlaces.
6
- *
7
- * Este componente demuestra todos los casos edge y escenarios complejos de procesamiento de enlaces,
8
- * incluyendo puntuación, URLs complejas, y mezclas de formatos.
9
- *
10
- * @example Uso en template:
11
- * ```html
12
- * <val-comprehensive-link-test></val-comprehensive-link-test>
13
- * ```
14
- */
15
- export class ComprehensiveLinkTestComponent {
16
- constructor() {
17
- this.punctuationProps = {
18
- content: 'Diferentes puntuaciones: https://angular.io, también https://github.com! ¿Conoces https://typescript.org? Final: https://rxjs.dev. Entre paréntesis (https://zone.js) y con comillas "https://ionic.io".',
19
- size: 'medium',
20
- color: 'dark',
21
- bold: false,
22
- processLinks: true,
23
- linkConfig: {
24
- openExternalInNewTab: true,
25
- linkClass: 'test-punctuation',
26
- externalLinkClass: 'test-external',
27
- },
28
- };
29
- this.complexUrlProps = {
30
- content: 'URLs complejas: https://api.github.com/repos/angular/angular/issues?state=open&sort=updated&per_page=50, búsqueda https://google.com/search?q=angular+ionic+components#results, y documentación https://angular.io/guide/getting-started#development-environment.',
31
- size: 'medium',
32
- color: 'dark',
33
- bold: false,
34
- processLinks: true,
35
- linkConfig: {
36
- openExternalInNewTab: true,
37
- linkClass: 'test-complex',
38
- externalLinkClass: 'test-external',
39
- },
40
- };
41
- this.parenthesesProps = {
42
- content: 'Paréntesis de contexto (ver https://docs.angular.io) vs URLs con paréntesis https://example.com/api/method(param) en el contenido. También funciona (https://ionic.io/docs).',
43
- size: 'medium',
44
- color: 'dark',
45
- bold: false,
46
- processLinks: true,
47
- linkConfig: {
48
- openExternalInNewTab: true,
49
- linkClass: 'test-parentheses',
50
- externalLinkClass: 'test-external',
51
- },
52
- };
53
- this.mixedFormatsProps = {
54
- content: 'Formatos mezclados: [Documentación oficial](https://angular.io/docs), enlace directo https://github.com/angular/angular, ruta interna /dashboard/settings, [guía de inicio](/getting-started), y API https://api.example.com/v1/users?active=true.',
55
- size: 'medium',
56
- color: 'dark',
57
- bold: false,
58
- processLinks: true,
59
- linkConfig: {
60
- openExternalInNewTab: true,
61
- openInternalInNewTab: false,
62
- processMarkdownLinks: true,
63
- linkClass: 'test-mixed',
64
- externalLinkClass: 'test-external',
65
- internalLinkClass: 'test-internal',
66
- },
67
- };
68
- this.edgeCasesProps = {
69
- content: 'Casos extremos: "https://quoted-url.com", múltiple puntuación https://example.com?!!, URL al final de oración https://final-url.org. También consecutivos: https://first.com y https://second.com.',
70
- size: 'medium',
71
- color: 'dark',
72
- bold: false,
73
- processLinks: true,
74
- linkConfig: {
75
- openExternalInNewTab: true,
76
- linkClass: 'test-edge',
77
- externalLinkClass: 'test-external',
78
- },
79
- };
80
- this.devUrlsProps = {
81
- content: 'URLs de desarrollo: http://localhost:4200/dashboard, servidor local https://127.0.0.1:8080/api/status, desarrollo http://dev.example.com:3000/debug?verbose=true, y túnel https://abc123.ngrok.io/webhook.',
82
- size: 'medium',
83
- color: 'dark',
84
- bold: false,
85
- processLinks: true,
86
- linkConfig: {
87
- openExternalInNewTab: false, // Para desarrollo, puede ser útil no abrir en nueva pestaña
88
- linkClass: 'test-dev',
89
- externalLinkClass: 'test-dev-external',
90
- },
91
- };
92
- }
93
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComprehensiveLinkTestComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
94
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ComprehensiveLinkTestComponent, isStandalone: true, selector: "val-comprehensive-link-test", ngImport: i0, template: `
95
- <div class="comprehensive-test">
96
- <h2>Prueba Exhaustiva de Procesamiento de Enlaces</h2>
97
-
98
- <div class="test-section">
99
- <h3>✅ Puntuación Final - SOLUCIONADO</h3>
100
- <val-text [props]="punctuationProps"></val-text>
101
- <p class="note">
102
- <strong>Esperado:</strong> Los enlaces no incluyen puntuación final (.,;!?), pero la puntuación se preserva
103
- como texto después del enlace.
104
- </p>
105
- </div>
106
-
107
- <div class="test-section">
108
- <h3>✅ URLs Complejas con Parámetros - SOLUCIONADO</h3>
109
- <val-text [props]="complexUrlProps"></val-text>
110
- <p class="note">
111
- <strong>Esperado:</strong> URLs con query params, fragmentos y rutas complejas se preservan completamente.
112
- </p>
113
- </div>
114
-
115
- <div class="test-section">
116
- <h3>✅ Paréntesis Inteligentes - SOLUCIONADO</h3>
117
- <val-text [props]="parenthesesProps"></val-text>
118
- <p class="note">
119
- <strong>Esperado:</strong> Paréntesis de contexto (texto) vs paréntesis de URL se manejan correctamente.
120
- </p>
121
- </div>
122
-
123
- <div class="test-section">
124
- <h3>✅ Mezcla de Formatos - SOLUCIONADO</h3>
125
- <val-text [props]="mixedFormatsProps"></val-text>
126
- <p class="note">
127
- <strong>Esperado:</strong> Enlaces Markdown, URLs directas y rutas internas coexisten sin conflictos.
128
- </p>
129
- </div>
130
-
131
- <div class="test-section">
132
- <h3>✅ Casos Extremos - SOLUCIONADO</h3>
133
- <val-text [props]="edgeCasesProps"></val-text>
134
- <p class="note">
135
- <strong>Esperado:</strong> Comillas, múltiple puntuación, y URLs al final de oraciones se procesan
136
- correctamente.
137
- </p>
138
- </div>
139
-
140
- <div class="test-section">
141
- <h3>✅ URLs de Desarrollo - SOLUCIONADO</h3>
142
- <val-text [props]="devUrlsProps"></val-text>
143
- <p class="note">
144
- <strong>Esperado:</strong> URLs de localhost, puertos, y rutas de desarrollo se detectan correctamente.
145
- </p>
146
- </div>
147
- </div>
148
- `, isInline: true, styles: [".comprehensive-test{padding:20px;max-width:1000px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.test-section{margin-bottom:32px;padding:20px;border:2px solid var(--ion-color-success, #2dd36f);border-radius:12px;background:var(--ion-color-success-tint, #42d77d) 10}h2{color:var(--ion-color-primary, #3880ff);margin-bottom:24px;text-align:center}h3{color:var(--ion-color-success, #2dd36f);margin-bottom:16px;font-size:18px;display:flex;align-items:center;gap:8px}.note{margin-top:12px;padding:12px;background:var(--ion-color-light, #f4f5f8);border-radius:8px;font-size:14px;color:var(--ion-color-medium, #92949c);border-left:4px solid var(--ion-color-primary, #3880ff)}.note strong{color:var(--ion-color-dark, #222428)}\n"], dependencies: [{ kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
149
- }
150
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComprehensiveLinkTestComponent, decorators: [{
151
- type: Component,
152
- args: [{ selector: 'val-comprehensive-link-test', standalone: true, imports: [TextComponent], template: `
153
- <div class="comprehensive-test">
154
- <h2>Prueba Exhaustiva de Procesamiento de Enlaces</h2>
155
-
156
- <div class="test-section">
157
- <h3>✅ Puntuación Final - SOLUCIONADO</h3>
158
- <val-text [props]="punctuationProps"></val-text>
159
- <p class="note">
160
- <strong>Esperado:</strong> Los enlaces no incluyen puntuación final (.,;!?), pero la puntuación se preserva
161
- como texto después del enlace.
162
- </p>
163
- </div>
164
-
165
- <div class="test-section">
166
- <h3>✅ URLs Complejas con Parámetros - SOLUCIONADO</h3>
167
- <val-text [props]="complexUrlProps"></val-text>
168
- <p class="note">
169
- <strong>Esperado:</strong> URLs con query params, fragmentos y rutas complejas se preservan completamente.
170
- </p>
171
- </div>
172
-
173
- <div class="test-section">
174
- <h3>✅ Paréntesis Inteligentes - SOLUCIONADO</h3>
175
- <val-text [props]="parenthesesProps"></val-text>
176
- <p class="note">
177
- <strong>Esperado:</strong> Paréntesis de contexto (texto) vs paréntesis de URL se manejan correctamente.
178
- </p>
179
- </div>
180
-
181
- <div class="test-section">
182
- <h3>✅ Mezcla de Formatos - SOLUCIONADO</h3>
183
- <val-text [props]="mixedFormatsProps"></val-text>
184
- <p class="note">
185
- <strong>Esperado:</strong> Enlaces Markdown, URLs directas y rutas internas coexisten sin conflictos.
186
- </p>
187
- </div>
188
-
189
- <div class="test-section">
190
- <h3>✅ Casos Extremos - SOLUCIONADO</h3>
191
- <val-text [props]="edgeCasesProps"></val-text>
192
- <p class="note">
193
- <strong>Esperado:</strong> Comillas, múltiple puntuación, y URLs al final de oraciones se procesan
194
- correctamente.
195
- </p>
196
- </div>
197
-
198
- <div class="test-section">
199
- <h3>✅ URLs de Desarrollo - SOLUCIONADO</h3>
200
- <val-text [props]="devUrlsProps"></val-text>
201
- <p class="note">
202
- <strong>Esperado:</strong> URLs de localhost, puertos, y rutas de desarrollo se detectan correctamente.
203
- </p>
204
- </div>
205
- </div>
206
- `, styles: [".comprehensive-test{padding:20px;max-width:1000px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.test-section{margin-bottom:32px;padding:20px;border:2px solid var(--ion-color-success, #2dd36f);border-radius:12px;background:var(--ion-color-success-tint, #42d77d) 10}h2{color:var(--ion-color-primary, #3880ff);margin-bottom:24px;text-align:center}h3{color:var(--ion-color-success, #2dd36f);margin-bottom:16px;font-size:18px;display:flex;align-items:center;gap:8px}.note{margin-top:12px;padding:12px;background:var(--ion-color-light, #f4f5f8);border-radius:8px;font-size:14px;color:var(--ion-color-medium, #92949c);border-left:4px solid var(--ion-color-primary, #3880ff)}.note strong{color:var(--ion-color-dark, #222428)}\n"] }]
207
- }] });
208
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcHJlaGVuc2l2ZS1saW5rLXRlc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdmFsdGVjaC1jb21wb25lbnRzL3NyYy9saWIvZXhhbXBsZXMvY29tcHJlaGVuc2l2ZS1saW5rLXRlc3QuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHlDQUF5QyxDQUFDOztBQUd4RTs7Ozs7Ozs7OztHQVVHO0FBMkdILE1BQU0sT0FBTyw4QkFBOEI7SUExRzNDO1FBMkdFLHFCQUFnQixHQUFpQjtZQUMvQixPQUFPLEVBQ0wsME1BQTBNO1lBQzVNLElBQUksRUFBRSxRQUFRO1lBQ2QsS0FBSyxFQUFFLE1BQU07WUFDYixJQUFJLEVBQUUsS0FBSztZQUNYLFlBQVksRUFBRSxJQUFJO1lBQ2xCLFVBQVUsRUFBRTtnQkFDVixvQkFBb0IsRUFBRSxJQUFJO2dCQUMxQixTQUFTLEVBQUUsa0JBQWtCO2dCQUM3QixpQkFBaUIsRUFBRSxlQUFlO2FBQ25DO1NBQ0YsQ0FBQztRQUVGLG9CQUFlLEdBQWlCO1lBQzlCLE9BQU8sRUFDTCxtUUFBbVE7WUFDclEsSUFBSSxFQUFFLFFBQVE7WUFDZCxLQUFLLEVBQUUsTUFBTTtZQUNiLElBQUksRUFBRSxLQUFLO1lBQ1gsWUFBWSxFQUFFLElBQUk7WUFDbEIsVUFBVSxFQUFFO2dCQUNWLG9CQUFvQixFQUFFLElBQUk7Z0JBQzFCLFNBQVMsRUFBRSxjQUFjO2dCQUN6QixpQkFBaUIsRUFBRSxlQUFlO2FBQ25DO1NBQ0YsQ0FBQztRQUVGLHFCQUFnQixHQUFpQjtZQUMvQixPQUFPLEVBQ0wsOEtBQThLO1lBQ2hMLElBQUksRUFBRSxRQUFRO1lBQ2QsS0FBSyxFQUFFLE1BQU07WUFDYixJQUFJLEVBQUUsS0FBSztZQUNYLFlBQVksRUFBRSxJQUFJO1lBQ2xCLFVBQVUsRUFBRTtnQkFDVixvQkFBb0IsRUFBRSxJQUFJO2dCQUMxQixTQUFTLEVBQUUsa0JBQWtCO2dCQUM3QixpQkFBaUIsRUFBRSxlQUFlO2FBQ25DO1NBQ0YsQ0FBQztRQUVGLHNCQUFpQixHQUFpQjtZQUNoQyxPQUFPLEVBQ0wsb1BBQW9QO1lBQ3RQLElBQUksRUFBRSxRQUFRO1lBQ2QsS0FBSyxFQUFFLE1BQU07WUFDYixJQUFJLEVBQUUsS0FBSztZQUNYLFlBQVksRUFBRSxJQUFJO1lBQ2xCLFVBQVUsRUFBRTtnQkFDVixvQkFBb0IsRUFBRSxJQUFJO2dCQUMxQixvQkFBb0IsRUFBRSxLQUFLO2dCQUMzQixvQkFBb0IsRUFBRSxJQUFJO2dCQUMxQixTQUFTLEVBQUUsWUFBWTtnQkFDdkIsaUJBQWlCLEVBQUUsZUFBZTtnQkFDbEMsaUJBQWlCLEVBQUUsZUFBZTthQUNuQztTQUNGLENBQUM7UUFFRixtQkFBYyxHQUFpQjtZQUM3QixPQUFPLEVBQ0wsb01BQW9NO1lBQ3RNLElBQUksRUFBRSxRQUFRO1lBQ2QsS0FBSyxFQUFFLE1BQU07WUFDYixJQUFJLEVBQUUsS0FBSztZQUNYLFlBQVksRUFBRSxJQUFJO1lBQ2xCLFVBQVUsRUFBRTtnQkFDVixvQkFBb0IsRUFBRSxJQUFJO2dCQUMxQixTQUFTLEVBQUUsV0FBVztnQkFDdEIsaUJBQWlCLEVBQUUsZUFBZTthQUNuQztTQUNGLENBQUM7UUFFRixpQkFBWSxHQUFpQjtZQUMzQixPQUFPLEVBQ0wsNE1BQTRNO1lBQzlNLElBQUksRUFBRSxRQUFRO1lBQ2QsS0FBSyxFQUFFLE1BQU07WUFDYixJQUFJLEVBQUUsS0FBSztZQUNYLFlBQVksRUFBRSxJQUFJO1lBQ2xCLFVBQVUsRUFBRTtnQkFDVixvQkFBb0IsRUFBRSxLQUFLLEVBQUUsNERBQTREO2dCQUN6RixTQUFTLEVBQUUsVUFBVTtnQkFDckIsaUJBQWlCLEVBQUUsbUJBQW1CO2FBQ3ZDO1NBQ0YsQ0FBQztLQUNIOytHQXZGWSw4QkFBOEI7bUdBQTlCLDhCQUE4Qix1RkF0Ry9COzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzRFQsb3pCQXZEUyxhQUFhOzs0RkF1R1osOEJBQThCO2tCQTFHMUMsU0FBUzsrQkFDRSw2QkFBNkIsY0FDM0IsSUFBSSxXQUNQLENBQUMsYUFBYSxDQUFDLFlBQ2Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNEVCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgVGV4dENvbXBvbmVudCB9IGZyb20gJy4uL2NvbXBvbmVudHMvYXRvbXMvdGV4dC90ZXh0LmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUZXh0TWV0YWRhdGEgfSBmcm9tICcuLi9jb21wb25lbnRzL2F0b21zL3RleHQvdHlwZXMnO1xuXG4vKipcbiAqIENvbXByZWhlbnNpdmVMaW5rVGVzdENvbXBvbmVudCAtIENvbXBvbmVudGUgZGUgcHJ1ZWJhIGV4aGF1c3RpdmEgcGFyYSBlbCBwcm9jZXNhbWllbnRvIGRlIGVubGFjZXMuXG4gKlxuICogRXN0ZSBjb21wb25lbnRlIGRlbXVlc3RyYSB0b2RvcyBsb3MgY2Fzb3MgZWRnZSB5IGVzY2VuYXJpb3MgY29tcGxlam9zIGRlIHByb2Nlc2FtaWVudG8gZGUgZW5sYWNlcyxcbiAqIGluY2x1eWVuZG8gcHVudHVhY2nDs24sIFVSTHMgY29tcGxlamFzLCB5IG1lemNsYXMgZGUgZm9ybWF0b3MuXG4gKlxuICogQGV4YW1wbGUgVXNvIGVuIHRlbXBsYXRlOlxuICogYGBgaHRtbFxuICogPHZhbC1jb21wcmVoZW5zaXZlLWxpbmstdGVzdD48L3ZhbC1jb21wcmVoZW5zaXZlLWxpbmstdGVzdD5cbiAqIGBgYFxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd2YWwtY29tcHJlaGVuc2l2ZS1saW5rLXRlc3QnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbVGV4dENvbXBvbmVudF0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cImNvbXByZWhlbnNpdmUtdGVzdFwiPlxuICAgICAgPGgyPlBydWViYSBFeGhhdXN0aXZhIGRlIFByb2Nlc2FtaWVudG8gZGUgRW5sYWNlczwvaDI+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJ0ZXN0LXNlY3Rpb25cIj5cbiAgICAgICAgPGgzPuKchSBQdW50dWFjacOzbiBGaW5hbCAtIFNPTFVDSU9OQURPPC9oMz5cbiAgICAgICAgPHZhbC10ZXh0IFtwcm9wc109XCJwdW5jdHVhdGlvblByb3BzXCI+PC92YWwtdGV4dD5cbiAgICAgICAgPHAgY2xhc3M9XCJub3RlXCI+XG4gICAgICAgICAgPHN0cm9uZz5Fc3BlcmFkbzo8L3N0cm9uZz4gTG9zIGVubGFjZXMgbm8gaW5jbHV5ZW4gcHVudHVhY2nDs24gZmluYWwgKC4sOyE/KSwgcGVybyBsYSBwdW50dWFjacOzbiBzZSBwcmVzZXJ2YVxuICAgICAgICAgIGNvbW8gdGV4dG8gZGVzcHXDqXMgZGVsIGVubGFjZS5cbiAgICAgICAgPC9wPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJ0ZXN0LXNlY3Rpb25cIj5cbiAgICAgICAgPGgzPuKchSBVUkxzIENvbXBsZWphcyBjb24gUGFyw6FtZXRyb3MgLSBTT0xVQ0lPTkFETzwvaDM+XG4gICAgICAgIDx2YWwtdGV4dCBbcHJvcHNdPVwiY29tcGxleFVybFByb3BzXCI+PC92YWwtdGV4dD5cbiAgICAgICAgPHAgY2xhc3M9XCJub3RlXCI+XG4gICAgICAgICAgPHN0cm9uZz5Fc3BlcmFkbzo8L3N0cm9uZz4gVVJMcyBjb24gcXVlcnkgcGFyYW1zLCBmcmFnbWVudG9zIHkgcnV0YXMgY29tcGxlamFzIHNlIHByZXNlcnZhbiBjb21wbGV0YW1lbnRlLlxuICAgICAgICA8L3A+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cInRlc3Qtc2VjdGlvblwiPlxuICAgICAgICA8aDM+4pyFIFBhcsOpbnRlc2lzIEludGVsaWdlbnRlcyAtIFNPTFVDSU9OQURPPC9oMz5cbiAgICAgICAgPHZhbC10ZXh0IFtwcm9wc109XCJwYXJlbnRoZXNlc1Byb3BzXCI+PC92YWwtdGV4dD5cbiAgICAgICAgPHAgY2xhc3M9XCJub3RlXCI+XG4gICAgICAgICAgPHN0cm9uZz5Fc3BlcmFkbzo8L3N0cm9uZz4gUGFyw6ludGVzaXMgZGUgY29udGV4dG8gKHRleHRvKSB2cyBwYXLDqW50ZXNpcyBkZSBVUkwgc2UgbWFuZWphbiBjb3JyZWN0YW1lbnRlLlxuICAgICAgICA8L3A+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cInRlc3Qtc2VjdGlvblwiPlxuICAgICAgICA8aDM+4pyFIE1lemNsYSBkZSBGb3JtYXRvcyAtIFNPTFVDSU9OQURPPC9oMz5cbiAgICAgICAgPHZhbC10ZXh0IFtwcm9wc109XCJtaXhlZEZvcm1hdHNQcm9wc1wiPjwvdmFsLXRleHQ+XG4gICAgICAgIDxwIGNsYXNzPVwibm90ZVwiPlxuICAgICAgICAgIDxzdHJvbmc+RXNwZXJhZG86PC9zdHJvbmc+IEVubGFjZXMgTWFya2Rvd24sIFVSTHMgZGlyZWN0YXMgeSBydXRhcyBpbnRlcm5hcyBjb2V4aXN0ZW4gc2luIGNvbmZsaWN0b3MuXG4gICAgICAgIDwvcD5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2IGNsYXNzPVwidGVzdC1zZWN0aW9uXCI+XG4gICAgICAgIDxoMz7inIUgQ2Fzb3MgRXh0cmVtb3MgLSBTT0xVQ0lPTkFETzwvaDM+XG4gICAgICAgIDx2YWwtdGV4dCBbcHJvcHNdPVwiZWRnZUNhc2VzUHJvcHNcIj48L3ZhbC10ZXh0PlxuICAgICAgICA8cCBjbGFzcz1cIm5vdGVcIj5cbiAgICAgICAgICA8c3Ryb25nPkVzcGVyYWRvOjwvc3Ryb25nPiBDb21pbGxhcywgbcO6bHRpcGxlIHB1bnR1YWNpw7NuLCB5IFVSTHMgYWwgZmluYWwgZGUgb3JhY2lvbmVzIHNlIHByb2Nlc2FuXG4gICAgICAgICAgY29ycmVjdGFtZW50ZS5cbiAgICAgICAgPC9wPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJ0ZXN0LXNlY3Rpb25cIj5cbiAgICAgICAgPGgzPuKchSBVUkxzIGRlIERlc2Fycm9sbG8gLSBTT0xVQ0lPTkFETzwvaDM+XG4gICAgICAgIDx2YWwtdGV4dCBbcHJvcHNdPVwiZGV2VXJsc1Byb3BzXCI+PC92YWwtdGV4dD5cbiAgICAgICAgPHAgY2xhc3M9XCJub3RlXCI+XG4gICAgICAgICAgPHN0cm9uZz5Fc3BlcmFkbzo8L3N0cm9uZz4gVVJMcyBkZSBsb2NhbGhvc3QsIHB1ZXJ0b3MsIHkgcnV0YXMgZGUgZGVzYXJyb2xsbyBzZSBkZXRlY3RhbiBjb3JyZWN0YW1lbnRlLlxuICAgICAgICA8L3A+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgYCxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgLmNvbXByZWhlbnNpdmUtdGVzdCB7XG4gICAgICAgIHBhZGRpbmc6IDIwcHg7XG4gICAgICAgIG1heC13aWR0aDogMTAwMHB4O1xuICAgICAgICBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAnU2Vnb2UgVUknLCBSb2JvdG8sIHNhbnMtc2VyaWY7XG4gICAgICB9XG5cbiAgICAgIC50ZXN0LXNlY3Rpb24ge1xuICAgICAgICBtYXJnaW4tYm90dG9tOiAzMnB4O1xuICAgICAgICBwYWRkaW5nOiAyMHB4O1xuICAgICAgICBib3JkZXI6IDJweCBzb2xpZCB2YXIoLS1pb24tY29sb3Itc3VjY2VzcywgIzJkZDM2Zik7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDEycHg7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWlvbi1jb2xvci1zdWNjZXNzLXRpbnQsICM0MmQ3N2QpIDEwO1xuICAgICAgfVxuXG4gICAgICBoMiB7XG4gICAgICAgIGNvbG9yOiB2YXIoLS1pb24tY29sb3ItcHJpbWFyeSwgIzM4ODBmZik7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDI0cHg7XG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICAgIH1cblxuICAgICAgaDMge1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLXN1Y2Nlc3MsICMyZGQzNmYpO1xuICAgICAgICBtYXJnaW4tYm90dG9tOiAxNnB4O1xuICAgICAgICBmb250LXNpemU6IDE4cHg7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgIGdhcDogOHB4O1xuICAgICAgfVxuXG4gICAgICAubm90ZSB7XG4gICAgICAgIG1hcmdpbi10b3A6IDEycHg7XG4gICAgICAgIHBhZGRpbmc6IDEycHg7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWlvbi1jb2xvci1saWdodCwgI2Y0ZjVmOCk7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDhweDtcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLW1lZGl1bSwgIzkyOTQ5Yyk7XG4gICAgICAgIGJvcmRlci1sZWZ0OiA0cHggc29saWQgdmFyKC0taW9uLWNvbG9yLXByaW1hcnksICMzODgwZmYpO1xuICAgICAgfVxuXG4gICAgICAubm90ZSBzdHJvbmcge1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLWRhcmssICMyMjI0MjgpO1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIENvbXByZWhlbnNpdmVMaW5rVGVzdENvbXBvbmVudCB7XG4gIHB1bmN0dWF0aW9uUHJvcHM6IFRleHRNZXRhZGF0YSA9IHtcbiAgICBjb250ZW50OlxuICAgICAgJ0RpZmVyZW50ZXMgcHVudHVhY2lvbmVzOiBodHRwczovL2FuZ3VsYXIuaW8sIHRhbWJpw6luIGh0dHBzOi8vZ2l0aHViLmNvbSEgwr9Db25vY2VzIGh0dHBzOi8vdHlwZXNjcmlwdC5vcmc/IEZpbmFsOiBodHRwczovL3J4anMuZGV2LiBFbnRyZSBwYXLDqW50ZXNpcyAoaHR0cHM6Ly96b25lLmpzKSB5IGNvbiBjb21pbGxhcyBcImh0dHBzOi8vaW9uaWMuaW9cIi4nLFxuICAgIHNpemU6ICdtZWRpdW0nLFxuICAgIGNvbG9yOiAnZGFyaycsXG4gICAgYm9sZDogZmFsc2UsXG4gICAgcHJvY2Vzc0xpbmtzOiB0cnVlLFxuICAgIGxpbmtDb25maWc6IHtcbiAgICAgIG9wZW5FeHRlcm5hbEluTmV3VGFiOiB0cnVlLFxuICAgICAgbGlua0NsYXNzOiAndGVzdC1wdW5jdHVhdGlvbicsXG4gICAgICBleHRlcm5hbExpbmtDbGFzczogJ3Rlc3QtZXh0ZXJuYWwnLFxuICAgIH0sXG4gIH07XG5cbiAgY29tcGxleFVybFByb3BzOiBUZXh0TWV0YWRhdGEgPSB7XG4gICAgY29udGVudDpcbiAgICAgICdVUkxzIGNvbXBsZWphczogaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hbmd1bGFyL2FuZ3VsYXIvaXNzdWVzP3N0YXRlPW9wZW4mc29ydD11cGRhdGVkJnBlcl9wYWdlPTUwLCBiw7pzcXVlZGEgaHR0cHM6Ly9nb29nbGUuY29tL3NlYXJjaD9xPWFuZ3VsYXIraW9uaWMrY29tcG9uZW50cyNyZXN1bHRzLCB5IGRvY3VtZW50YWNpw7NuIGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9nZXR0aW5nLXN0YXJ0ZWQjZGV2ZWxvcG1lbnQtZW52aXJvbm1lbnQuJyxcbiAgICBzaXplOiAnbWVkaXVtJyxcbiAgICBjb2xvcjogJ2RhcmsnLFxuICAgIGJvbGQ6IGZhbHNlLFxuICAgIHByb2Nlc3NMaW5rczogdHJ1ZSxcbiAgICBsaW5rQ29uZmlnOiB7XG4gICAgICBvcGVuRXh0ZXJuYWxJbk5ld1RhYjogdHJ1ZSxcbiAgICAgIGxpbmtDbGFzczogJ3Rlc3QtY29tcGxleCcsXG4gICAgICBleHRlcm5hbExpbmtDbGFzczogJ3Rlc3QtZXh0ZXJuYWwnLFxuICAgIH0sXG4gIH07XG5cbiAgcGFyZW50aGVzZXNQcm9wczogVGV4dE1ldGFkYXRhID0ge1xuICAgIGNvbnRlbnQ6XG4gICAgICAnUGFyw6ludGVzaXMgZGUgY29udGV4dG8gKHZlciBodHRwczovL2RvY3MuYW5ndWxhci5pbykgdnMgVVJMcyBjb24gcGFyw6ludGVzaXMgaHR0cHM6Ly9leGFtcGxlLmNvbS9hcGkvbWV0aG9kKHBhcmFtKSBlbiBlbCBjb250ZW5pZG8uIFRhbWJpw6luIGZ1bmNpb25hIChodHRwczovL2lvbmljLmlvL2RvY3MpLicsXG4gICAgc2l6ZTogJ21lZGl1bScsXG4gICAgY29sb3I6ICdkYXJrJyxcbiAgICBib2xkOiBmYWxzZSxcbiAgICBwcm9jZXNzTGlua3M6IHRydWUsXG4gICAgbGlua0NvbmZpZzoge1xuICAgICAgb3BlbkV4dGVybmFsSW5OZXdUYWI6IHRydWUsXG4gICAgICBsaW5rQ2xhc3M6ICd0ZXN0LXBhcmVudGhlc2VzJyxcbiAgICAgIGV4dGVybmFsTGlua0NsYXNzOiAndGVzdC1leHRlcm5hbCcsXG4gICAgfSxcbiAgfTtcblxuICBtaXhlZEZvcm1hdHNQcm9wczogVGV4dE1ldGFkYXRhID0ge1xuICAgIGNvbnRlbnQ6XG4gICAgICAnRm9ybWF0b3MgbWV6Y2xhZG9zOiBbRG9jdW1lbnRhY2nDs24gb2ZpY2lhbF0oaHR0cHM6Ly9hbmd1bGFyLmlvL2RvY3MpLCBlbmxhY2UgZGlyZWN0byBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyLCBydXRhIGludGVybmEgL2Rhc2hib2FyZC9zZXR0aW5ncywgW2d1w61hIGRlIGluaWNpb10oL2dldHRpbmctc3RhcnRlZCksIHkgQVBJIGh0dHBzOi8vYXBpLmV4YW1wbGUuY29tL3YxL3VzZXJzP2FjdGl2ZT10cnVlLicsXG4gICAgc2l6ZTogJ21lZGl1bScsXG4gICAgY29sb3I6ICdkYXJrJyxcbiAgICBib2xkOiBmYWxzZSxcbiAgICBwcm9jZXNzTGlua3M6IHRydWUsXG4gICAgbGlua0NvbmZpZzoge1xuICAgICAgb3BlbkV4dGVybmFsSW5OZXdUYWI6IHRydWUsXG4gICAgICBvcGVuSW50ZXJuYWxJbk5ld1RhYjogZmFsc2UsXG4gICAgICBwcm9jZXNzTWFya2Rvd25MaW5rczogdHJ1ZSxcbiAgICAgIGxpbmtDbGFzczogJ3Rlc3QtbWl4ZWQnLFxuICAgICAgZXh0ZXJuYWxMaW5rQ2xhc3M6ICd0ZXN0LWV4dGVybmFsJyxcbiAgICAgIGludGVybmFsTGlua0NsYXNzOiAndGVzdC1pbnRlcm5hbCcsXG4gICAgfSxcbiAgfTtcblxuICBlZGdlQ2FzZXNQcm9wczogVGV4dE1ldGFkYXRhID0ge1xuICAgIGNvbnRlbnQ6XG4gICAgICAnQ2Fzb3MgZXh0cmVtb3M6IFwiaHR0cHM6Ly9xdW90ZWQtdXJsLmNvbVwiLCBtw7psdGlwbGUgcHVudHVhY2nDs24gaHR0cHM6Ly9leGFtcGxlLmNvbT8hISwgVVJMIGFsIGZpbmFsIGRlIG9yYWNpw7NuIGh0dHBzOi8vZmluYWwtdXJsLm9yZy4gVGFtYmnDqW4gY29uc2VjdXRpdm9zOiBodHRwczovL2ZpcnN0LmNvbSB5IGh0dHBzOi8vc2Vjb25kLmNvbS4nLFxuICAgIHNpemU6ICdtZWRpdW0nLFxuICAgIGNvbG9yOiAnZGFyaycsXG4gICAgYm9sZDogZmFsc2UsXG4gICAgcHJvY2Vzc0xpbmtzOiB0cnVlLFxuICAgIGxpbmtDb25maWc6IHtcbiAgICAgIG9wZW5FeHRlcm5hbEluTmV3VGFiOiB0cnVlLFxuICAgICAgbGlua0NsYXNzOiAndGVzdC1lZGdlJyxcbiAgICAgIGV4dGVybmFsTGlua0NsYXNzOiAndGVzdC1leHRlcm5hbCcsXG4gICAgfSxcbiAgfTtcblxuICBkZXZVcmxzUHJvcHM6IFRleHRNZXRhZGF0YSA9IHtcbiAgICBjb250ZW50OlxuICAgICAgJ1VSTHMgZGUgZGVzYXJyb2xsbzogaHR0cDovL2xvY2FsaG9zdDo0MjAwL2Rhc2hib2FyZCwgc2Vydmlkb3IgbG9jYWwgaHR0cHM6Ly8xMjcuMC4wLjE6ODA4MC9hcGkvc3RhdHVzLCBkZXNhcnJvbGxvIGh0dHA6Ly9kZXYuZXhhbXBsZS5jb206MzAwMC9kZWJ1Zz92ZXJib3NlPXRydWUsIHkgdMO6bmVsIGh0dHBzOi8vYWJjMTIzLm5ncm9rLmlvL3dlYmhvb2suJyxcbiAgICBzaXplOiAnbWVkaXVtJyxcbiAgICBjb2xvcjogJ2RhcmsnLFxuICAgIGJvbGQ6IGZhbHNlLFxuICAgIHByb2Nlc3NMaW5rczogdHJ1ZSxcbiAgICBsaW5rQ29uZmlnOiB7XG4gICAgICBvcGVuRXh0ZXJuYWxJbk5ld1RhYjogZmFsc2UsIC8vIFBhcmEgZGVzYXJyb2xsbywgcHVlZGUgc2VyIMO6dGlsIG5vIGFicmlyIGVuIG51ZXZhIHBlc3Rhw7FhXG4gICAgICBsaW5rQ2xhc3M6ICd0ZXN0LWRldicsXG4gICAgICBleHRlcm5hbExpbmtDbGFzczogJ3Rlc3QtZGV2LWV4dGVybmFsJyxcbiAgICB9LFxuICB9O1xufVxuIl19