@gravitee/ui-components 3.24.1 → 3.24.2-migrate-codemirror-4150e72

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 (114) hide show
  1. package/CHANGELOG.md +1237 -0
  2. package/LICENSE.txt +202 -0
  3. package/README.md +195 -0
  4. package/package.json +18 -2
  5. package/src/.eslintrc.js +19 -0
  6. package/src/atoms/gv-autocomplete.js +156 -132
  7. package/src/atoms/gv-button.js +248 -74
  8. package/src/atoms/gv-checkbox.js +103 -45
  9. package/src/atoms/gv-date-picker-calendar.js +393 -312
  10. package/src/atoms/gv-date-picker-cell.js +81 -57
  11. package/src/atoms/gv-date-picker.js +319 -180
  12. package/src/atoms/gv-file-upload.js +195 -85
  13. package/src/atoms/gv-icon.js +34 -13
  14. package/src/atoms/gv-image.js +66 -31
  15. package/src/atoms/gv-input-message.js +37 -12
  16. package/src/atoms/gv-input.js +144 -120
  17. package/src/atoms/gv-link.js +125 -47
  18. package/src/atoms/gv-message.js +69 -18
  19. package/src/atoms/gv-metric.js +68 -19
  20. package/src/atoms/gv-relative-time.js +38 -67
  21. package/src/atoms/gv-select-native.js +220 -120
  22. package/src/atoms/gv-select.js +233 -132
  23. package/src/atoms/gv-spinner.js +26 -5
  24. package/src/atoms/gv-state.js +66 -25
  25. package/src/atoms/gv-switch.js +160 -40
  26. package/src/atoms/gv-tag.js +78 -26
  27. package/src/atoms/gv-text.js +83 -22
  28. package/src/charts/gv-chart-bar.js +18 -22
  29. package/src/charts/gv-chart-gauge.js +31 -28
  30. package/src/charts/gv-chart-histogram.js +10 -18
  31. package/src/charts/gv-chart-line.js +59 -70
  32. package/src/charts/gv-chart-map.js +42 -44
  33. package/src/charts/gv-chart-pie.js +14 -18
  34. package/src/index.js +1 -1
  35. package/src/lib/cron-expression.js +35 -40
  36. package/src/lib/date.js +1 -10
  37. package/src/lib/events.js +1 -3
  38. package/src/lib/http-client-schema-form.js +12 -13
  39. package/src/lib/http.js +56 -57
  40. package/src/lib/i18n.js +22 -30
  41. package/src/lib/item.js +12 -13
  42. package/src/lib/properties.js +42 -77
  43. package/src/lib/schema-form.js +5 -4
  44. package/src/lib/studio.js +60 -13
  45. package/src/lib/style.js +8 -8
  46. package/src/lib/text-format.js +7 -14
  47. package/src/lib/theme.js +5 -8
  48. package/src/lib/utils.js +18 -17
  49. package/src/mixins/chart-element.js +54 -31
  50. package/src/mixins/input-element.js +44 -59
  51. package/src/mixins/item-resource.js +32 -34
  52. package/src/mixins/keyboard-element.js +5 -6
  53. package/src/mixins/update-after-browser.js +1 -4
  54. package/src/mixins/with-resize-observer.js +13 -23
  55. package/src/mixins/with-skeleton-attribute.js +48 -54
  56. package/src/molecules/gv-card-full.js +147 -26
  57. package/src/molecules/gv-card-list.js +42 -13
  58. package/src/molecules/gv-card.js +91 -17
  59. package/src/molecules/gv-category-list.js +17 -6
  60. package/src/molecules/gv-category.js +103 -23
  61. package/src/molecules/gv-code-editor.js +407 -0
  62. package/src/molecules/gv-code-hint.js +25 -8
  63. package/src/molecules/gv-code.js +156 -59
  64. package/src/molecules/gv-confirm.js +71 -41
  65. package/src/molecules/gv-cron-editor.js +389 -143
  66. package/src/molecules/gv-dropdown-menu.js +46 -14
  67. package/src/molecules/gv-expandable.js +59 -31
  68. package/src/molecules/gv-expression-language.js +136 -241
  69. package/src/molecules/gv-identity-picture.js +65 -42
  70. package/src/molecules/gv-list.js +134 -42
  71. package/src/molecules/gv-metrics.js +49 -37
  72. package/src/molecules/gv-modal.js +95 -28
  73. package/src/molecules/gv-nav.js +75 -49
  74. package/src/molecules/gv-option.js +130 -57
  75. package/src/molecules/gv-plans.js +209 -86
  76. package/src/molecules/gv-popover.js +177 -57
  77. package/src/molecules/gv-promote.js +146 -28
  78. package/src/molecules/gv-rating-list.js +195 -69
  79. package/src/molecules/gv-rating.js +105 -52
  80. package/src/molecules/gv-row-expandable.js +11 -5
  81. package/src/molecules/gv-row.js +147 -21
  82. package/src/molecules/gv-stats.js +48 -23
  83. package/src/molecules/gv-stepper.js +187 -43
  84. package/src/molecules/gv-table.js +309 -199
  85. package/src/molecules/gv-tree.js +156 -33
  86. package/src/organisms/gv-documentation.js +127 -44
  87. package/src/organisms/gv-header.js +195 -37
  88. package/src/organisms/gv-http-client.js +168 -32
  89. package/src/organisms/gv-menu.js +158 -37
  90. package/src/organisms/gv-newsletter-subscription.js +189 -48
  91. package/src/organisms/gv-pagination.js +77 -49
  92. package/src/organisms/gv-properties.js +492 -271
  93. package/src/organisms/gv-resizable-views.js +259 -41
  94. package/src/organisms/gv-resources.js +275 -168
  95. package/src/organisms/gv-schema-form-array.js +159 -49
  96. package/src/organisms/gv-schema-form-control-object.js +73 -59
  97. package/src/organisms/gv-schema-form-control.js +134 -107
  98. package/src/organisms/gv-schema-form.js +284 -196
  99. package/src/organisms/gv-tabs.js +98 -66
  100. package/src/organisms/gv-user-menu.js +201 -36
  101. package/src/organisms/gv-vertical-menu.js +61 -20
  102. package/src/policy-studio/gv-flow-step.js +245 -105
  103. package/src/policy-studio/gv-flow.js +304 -125
  104. package/src/policy-studio/gv-policy-studio-menu.js +471 -157
  105. package/src/policy-studio/gv-policy-studio.js +761 -688
  106. package/src/styles/empty.js +20 -3
  107. package/src/styles/input.js +245 -3
  108. package/src/styles/link.js +16 -3
  109. package/src/styles/shapes.js +0 -1
  110. package/src/styles/skeleton.js +37 -3
  111. package/src/styles/zoom.js +24 -3
  112. package/src/theme/definition.json +1762 -0
  113. package/src/theme/gv-theme.js +60 -21
  114. package/wc/gv-code-editor.js +1 -0
@@ -0,0 +1,407 @@
1
+ /*
2
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { LitElement, html, css } from 'lit-element';
17
+
18
+ import { shapeClipboard } from '../styles/shapes';
19
+ import { dispatchCustomEvent } from '../lib/events';
20
+ import { uuid } from '../lib/utils';
21
+ import { classMap } from 'lit-html/directives/class-map';
22
+
23
+ import { EditorView, basicSetup } from '@codemirror/basic-setup';
24
+ import { EditorState, Compartment, Prec, EditorSelection } from '@codemirror/state';
25
+ import { autocompletion, startCompletion, pickedCompletion } from '@codemirror/autocomplete';
26
+ import { json } from '@codemirror/lang-json';
27
+ import { languages } from '@codemirror/language-data';
28
+ import { placeholder, keymap } from '@codemirror/view';
29
+ import { get } from 'object-path';
30
+
31
+ const languageCompartment = new Compartment();
32
+ const readonlyCompartment = new Compartment();
33
+ const placeholderCompartment = new Compartment();
34
+
35
+ /**
36
+ * Code editor component
37
+ *
38
+ * ## Details
39
+ * * has @theme facet
40
+ *
41
+ * @fires gv-code:input - input events with the `value` on `detail`
42
+ * @fires gv-code:ready - event dispatch when component is ready
43
+ * @fires gv-code:clipboard-copy - event dispatch when component the `value` has been copied to clipboard
44
+ *
45
+ * @attr {String} label - code language
46
+ * @attr {String} value - code content to be highlighted
47
+ * @attr {options} Object - options based on codemirror https://codemirror.net/doc/manual.html#config
48
+ * @attr {Object} grammar - The grammar for Expression Language support
49
+ * @attr {String} placeholder - an example value to display in the input when empty
50
+ * @attr {Number} rows - number of rows of the text element
51
+ * @attr {Boolean} large - for a large input (only if the field has one row)
52
+ * @attr {Boolean} medium - for a medium input (only if the field has one row) (Default)
53
+ * @attr {Boolean} small - for a small input (only if the field has one row)
54
+ *
55
+ * @attr {Boolean} [clipboard=false]- true if field has clipboard button
56
+ * @attr {Boolean} [autofocus=false] - true to put the focus on the input
57
+ * @attr {Boolean} [readonly=false] - true if field is readonly mode
58
+ */
59
+ export class GvCodeEditor extends LitElement {
60
+ static get properties() {
61
+ return {
62
+ value: { type: String },
63
+ readonly: { type: Boolean },
64
+ placeholder: { type: String },
65
+ options: { type: Object },
66
+ rows: { type: Number },
67
+ clipboard: { type: Boolean },
68
+ grammar: { type: Object },
69
+ _clipboardIcon: { type: String },
70
+ _codeMirror: { type: Object },
71
+ _error: { type: String, attribute: false },
72
+ };
73
+ }
74
+
75
+ constructor() {
76
+ super();
77
+ this._id = `gv-code-${uuid()}`;
78
+ this.value = '';
79
+ this.readonly = false;
80
+ this.autofocus = false;
81
+ this.clipboard = false;
82
+ this._clipboardIcon = shapeClipboard;
83
+ }
84
+
85
+ render() {
86
+ const classes = {
87
+ singleLine: this.singleLine,
88
+ };
89
+ return html` <div id="${this._id}" class="${classMap(classes)}"></div> `;
90
+ }
91
+
92
+ _onChange() {
93
+ dispatchCustomEvent(this, 'input', this.value);
94
+ }
95
+
96
+ get singleLine() {
97
+ return this.rows === 1;
98
+ }
99
+
100
+ _getModelType(typeId) {
101
+ if (this.grammar != null) {
102
+ return get(this.grammar, `_types.${typeId}`);
103
+ }
104
+ return null;
105
+ }
106
+
107
+ _isMap(typeId) {
108
+ return ['Map', 'HttpHeaders', 'MultiValueMap'].includes(typeId);
109
+ }
110
+
111
+ _getEnum(typeId) {
112
+ if (this.grammar != null) {
113
+ return get(this.grammar, `_enums.${typeId}`);
114
+ }
115
+ return [''];
116
+ }
117
+
118
+ _convertType(type) {
119
+ if (type) {
120
+ const lowerType = type.toLowerCase();
121
+ if (lowerType === 'string') {
122
+ // class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
123
+ return 'text';
124
+ } else if (lowerType === 'httpheaders' || lowerType === 'multivaluemap') {
125
+ return 'type';
126
+ } else if (lowerType === 'int' || lowerType === 'long') {
127
+ return 'variable';
128
+ } else if (lowerType.includes('[]')) {
129
+ return 'enum';
130
+ }
131
+ }
132
+ return 'variable';
133
+ }
134
+
135
+ _autocomplete(ctx) {
136
+ const { handler, match } = this._completionHandlers
137
+ .filter((handler) => (this.grammar != null && handler.supportEL === true) || handler.supportEL !== true)
138
+ .map((handler) => ({ handler, match: handler.expr ? ctx.matchBefore(handler.expr) : true }))
139
+ .find(({ match, expr }) => match);
140
+ return handler.run.call(this, ctx, match);
141
+ }
142
+
143
+ _buildMethods(type) {
144
+ const modelType = this._getModelType(type);
145
+ return modelType.methods.map(({ name, params = [], returnType }) => {
146
+ const command = `${name}()`;
147
+ const displayParams = params.map((p) => `${p.type} ${p.name}`);
148
+ const label = `${name}(${displayParams.join(', ')})`;
149
+ const detail = `return ${returnType}`;
150
+ return {
151
+ type: 'method',
152
+ command,
153
+ apply: (view, completion, from, to) => {
154
+ const anchor = from + name.length + 1;
155
+ view.dispatch({
156
+ changes: { from, to, insert: completion.command },
157
+ selection: { anchor },
158
+ userEvent: 'input.complete',
159
+ annotations: pickedCompletion.of(view),
160
+ });
161
+ },
162
+ label,
163
+ detail,
164
+ };
165
+ });
166
+ }
167
+
168
+ get _completionHandlers() {
169
+ return [
170
+ {
171
+ expr: /{#[a-z]*/,
172
+ supportEL: true,
173
+ run(ctx, match) {
174
+ const prefix = match.text.replaceAll('{#', '');
175
+ const from = ctx.pos - prefix.length;
176
+ const options = Object.keys(this.grammar)
177
+ .filter((command) => !command.startsWith('_') && command.startsWith(prefix))
178
+ .map((command) => {
179
+ return {
180
+ // class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
181
+ type: 'variable',
182
+ command,
183
+ apply: command,
184
+ label: command,
185
+ };
186
+ });
187
+ return { from, options };
188
+ },
189
+ },
190
+ {
191
+ expr: /{#[a-z]*.[a-zA-Z]*/,
192
+ run(ctx, match) {
193
+ const tokens = match.text.split('.');
194
+ const key = tokens[0].replaceAll('{#', '');
195
+ const prefix = tokens[1];
196
+ const candidate = this.grammar[key][prefix];
197
+ let options = [];
198
+ let from = ctx.pos;
199
+ if (candidate) {
200
+ // const modelType = this._getModelType(candidate._type);
201
+ if (this._isMap(candidate._type)) {
202
+ options = this._getEnum(candidate._type).map((value) => {
203
+ const type = this._convertType(candidate._type);
204
+ const command = `['${value}'][0]`;
205
+ return {
206
+ type,
207
+ command,
208
+ apply: command,
209
+ label: value,
210
+ };
211
+ });
212
+ }
213
+ } else {
214
+ from -= prefix.length;
215
+ const candidate = this.grammar[key];
216
+ if (candidate._type) {
217
+ options = this._buildMethods(candidate._type);
218
+ } else {
219
+ options = Object.keys(candidate)
220
+ .filter((command) => !command.startsWith('_') && command.startsWith(prefix))
221
+ .map((command) => ({
222
+ type: this._convertType(candidate[command]._type),
223
+ command,
224
+ apply: command,
225
+ label: command,
226
+ }));
227
+ }
228
+ }
229
+ return { from, options };
230
+ },
231
+ },
232
+ {
233
+ expr: /{#[a-z]*.[a-zA-Z]*.[a-zA-Z]*/,
234
+ run(ctx, match) {
235
+ const tokens = match.text.split('.');
236
+ const key = tokens[0].replaceAll('{#', '');
237
+ const word = tokens[1];
238
+ const prefix = tokens[2];
239
+ const candidate = this.grammar[key][word];
240
+ let options = [];
241
+ let from = ctx.pos;
242
+ if (candidate) {
243
+ if (this._isMap(candidate._type)) {
244
+ options = this._getEnum(candidate._type)
245
+ .filter((command) => !command.startsWith('_') && command.startsWith(prefix))
246
+ .map((label) => {
247
+ const type = this._convertType(candidate._type);
248
+ return {
249
+ type,
250
+ command: `['${label}'][0]`,
251
+ apply(view, completion, _from, to) {
252
+ const from = _from - prefix.length - 1;
253
+ view.dispatch({
254
+ changes: { from, to, insert: completion.command },
255
+ selection: { anchor: from + completion.command.length },
256
+ userEvent: 'input.complete',
257
+ annotations: pickedCompletion.of(view),
258
+ });
259
+ },
260
+ label,
261
+ };
262
+ });
263
+ } else {
264
+ if (candidate._type) {
265
+ options = this._buildMethods(candidate._type);
266
+ } else {
267
+ from -= prefix.length;
268
+ options = Object.keys(candidate)
269
+ .filter((command) => command.startsWith(prefix))
270
+ .map((command) => {
271
+ return {
272
+ type: this._convertType(candidate[command]._type),
273
+ command,
274
+ apply: command,
275
+ label: command,
276
+ };
277
+ });
278
+ }
279
+ }
280
+ }
281
+ return { from, options };
282
+ },
283
+ },
284
+ {
285
+ run(ctx) {
286
+ const autocompleteLanguage = ctx.state.languageDataAt('autocomplete', ctx.pos);
287
+ if (autocompleteLanguage.length > 0) {
288
+ return autocompleteLanguage[0](ctx);
289
+ }
290
+ return { from: ctx.pos, options: [] };
291
+ },
292
+ },
293
+ ];
294
+ }
295
+
296
+ getExtensions() {
297
+ return [
298
+ basicSetup,
299
+ languageCompartment.of(json()),
300
+ placeholderCompartment.of(placeholder(this.placeholder || '')),
301
+ EditorState.transactionFilter.of((tr) => (this.singleLine && tr.newDoc.lines > 1 ? [] : tr)),
302
+ readonlyCompartment.of(EditorView.editable.of(!this.readonly)),
303
+ EditorView.updateListener.of((update) => {
304
+ this.value = update.view.contentDOM.innerText;
305
+ }),
306
+ autocompletion({
307
+ activateOnTyping: true,
308
+ override: [this._autocomplete.bind(this)],
309
+ }),
310
+ Prec.high(this.insertELKeymap()),
311
+ ];
312
+ }
313
+
314
+ insertELKeymap() {
315
+ return keymap.of([
316
+ {
317
+ key: 'Ctrl-Shift-e',
318
+ mac: 'Cmd-Shift-e',
319
+ run(view) {
320
+ view.dispatch(
321
+ view.state.changeByRange((range) => ({
322
+ changes: [{ from: range.from, to: range.to, insert: '{#}' }],
323
+ range: EditorSelection.range(range.from + 2, range.to + 2),
324
+ })),
325
+ );
326
+ startCompletion(view);
327
+ return true;
328
+ },
329
+ },
330
+ ]);
331
+ }
332
+
333
+ firstUpdated() {
334
+ super.firstUpdated();
335
+ const parent = this.shadowRoot.querySelector(`[id=${this._id}]`);
336
+ this._editorState = EditorState.create({
337
+ doc: this.value,
338
+ extensions: this.getExtensions(),
339
+ });
340
+ this._editorView = new EditorView({
341
+ root: this.shadowRoot,
342
+ parent,
343
+ state: this._editorState,
344
+ });
345
+ parent.appendChild(this._editorView.dom);
346
+ }
347
+
348
+ async updated(properties) {
349
+ if (properties.has('placeholder')) {
350
+ this._editorView.dispatch({
351
+ effects: placeholderCompartment.reconfigure(placeholder(this.placeholder)),
352
+ });
353
+ }
354
+ if (properties.has('value')) {
355
+ this._editorState.update({ changes: { from: 0, to: this._editorState.doc.length, insert: this.value } });
356
+ }
357
+ if (properties.has('readonly')) {
358
+ this._editorView.dispatch({
359
+ effects: readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly)),
360
+ });
361
+ }
362
+
363
+ if (properties.has('options') && this.options) {
364
+ if (this.options.mode) {
365
+ const language = languages.find((language) => {
366
+ return language.name.toUpperCase() === this.options.mode.toUpperCase() || language.alias.includes(this.options.mode);
367
+ });
368
+ if (language != null) {
369
+ if (language.support == null) {
370
+ await language.load();
371
+ }
372
+ this._editorView.dispatch({
373
+ effects: languageCompartment.reconfigure(language.support.extension),
374
+ });
375
+ } else {
376
+ console.warn(
377
+ `Cannot find language ${this.options.mode}, please use language supported by CodeMirror 6`,
378
+ languages.map((l) => l.name),
379
+ );
380
+ }
381
+ }
382
+ }
383
+ }
384
+
385
+ static get styles() {
386
+ return [
387
+ // language=CSS
388
+ css`
389
+ :host {
390
+ box-sizing: border-box;
391
+ display: block;
392
+ margin: 0 0.2rem 0.2rem 0.2rem;
393
+ }
394
+
395
+ .singleLine .cm-gutters {
396
+ display: none;
397
+ }
398
+
399
+ .singleLine .cm-scroller {
400
+ overflow: hidden;
401
+ }
402
+ `,
403
+ ];
404
+ }
405
+ }
406
+
407
+ window.customElements.define('gv-code-editor', GvCodeEditor);
@@ -14,10 +14,10 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { css, html, LitElement } from 'lit';
17
+
17
18
  /**
18
19
  * Code hint component
19
20
  */
20
-
21
21
  export class GvCodeHint extends LitElement {
22
22
  render() {
23
23
  return html`<slot></slot>`;
@@ -25,12 +25,10 @@ export class GvCodeHint extends LitElement {
25
25
 
26
26
  updated(_changedProperties) {
27
27
  super.updated(_changedProperties);
28
-
29
28
  if (this.firstElementChild != null) {
30
29
  const elementNodeListOf = this.firstElementChild.querySelectorAll('.CodeMirror-hint');
31
- elementNodeListOf.forEach(e => {
30
+ elementNodeListOf.forEach((e) => {
32
31
  e.style = 'padding: 4px;border-radius: 2px;white-space: pre;cursor: pointer;';
33
-
34
32
  if (e.classList.contains('CodeMirror-hint-active')) {
35
33
  e.style.backgroundColor = 'var(--gv-theme-color, #5a7684)';
36
34
  e.style.color = 'white';
@@ -40,10 +38,29 @@ export class GvCodeHint extends LitElement {
40
38
  }
41
39
 
42
40
  static get styles() {
43
- return [// language=CSS
44
- css`::slotted(.CodeMirror-hints){position:absolute;z-index:80;overflow:hidden;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px rgba(0,0,0,.2);border-radius:3px;border:1px solid silver;background:#fff;font-family:monospace;max-height:20em;overflow-y:auto}`];
41
+ return [
42
+ // language=CSS
43
+ css`
44
+ ::slotted(.CodeMirror-hints) {
45
+ position: absolute;
46
+ z-index: 80;
47
+ overflow: hidden;
48
+ list-style: none;
49
+ margin: 0;
50
+ padding: 2px;
51
+ -webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
52
+ -moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
53
+ box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
54
+ border-radius: 3px;
55
+ border: 1px solid silver;
56
+ background: white;
57
+ font-family: monospace;
58
+ max-height: 20em;
59
+ overflow-y: auto;
60
+ }
61
+ `,
62
+ ];
45
63
  }
46
-
47
64
  }
65
+
48
66
  window.customElements.define('gv-code-hint', GvCodeHint);
49
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4vbm9kZV9tb2R1bGVzL0BncmF2aXRlZS91aS1jb21wb25lbnRzL21vbGVjdWxlcy9ndi1jb2RlLWhpbnQuanMiXSwibmFtZXMiOlsiY3NzIiwiaHRtbCIsIkxpdEVsZW1lbnQiLCJHdkNvZGVIaW50IiwicmVuZGVyIiwidXBkYXRlZCIsIl9jaGFuZ2VkUHJvcGVydGllcyIsImZpcnN0RWxlbWVudENoaWxkIiwiZWxlbWVudE5vZGVMaXN0T2YiLCJxdWVyeVNlbGVjdG9yQWxsIiwiZm9yRWFjaCIsImUiLCJzdHlsZSIsImNsYXNzTGlzdCIsImNvbnRhaW5zIiwiYmFja2dyb3VuZENvbG9yIiwiY29sb3IiLCJzdHlsZXMiLCJ3aW5kb3ciLCJjdXN0b21FbGVtZW50cyIsImRlZmluZSJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBU0EsR0FBVCxFQUFjQyxJQUFkLEVBQW9CQyxVQUFwQixRQUFzQyxLQUF0QztBQUVBO0FBQ0E7QUFDQTs7QUFDQSxPQUFPLE1BQU1DLFVBQU4sU0FBeUJELFVBQXpCLENBQW9DO0FBQ3pDRSxFQUFBQSxNQUFNLEdBQUc7QUFDUCxXQUFPSCxJQUFJLGVBQVg7QUFDRDs7QUFFREksRUFBQUEsT0FBTyxDQUFDQyxrQkFBRCxFQUFxQjtBQUMxQixVQUFNRCxPQUFOLENBQWNDLGtCQUFkOztBQUNBLFFBQUksS0FBS0MsaUJBQUwsSUFBMEIsSUFBOUIsRUFBb0M7QUFDbEMsWUFBTUMsaUJBQWlCLEdBQUcsS0FBS0QsaUJBQUwsQ0FBdUJFLGdCQUF2QixDQUF3QyxrQkFBeEMsQ0FBMUI7QUFDQUQsTUFBQUEsaUJBQWlCLENBQUNFLE9BQWxCLENBQTJCQyxDQUFELElBQU87QUFDL0JBLFFBQUFBLENBQUMsQ0FBQ0MsS0FBRixHQUFVLG1FQUFWOztBQUNBLFlBQUlELENBQUMsQ0FBQ0UsU0FBRixDQUFZQyxRQUFaLENBQXFCLHdCQUFyQixDQUFKLEVBQW9EO0FBQ2xESCxVQUFBQSxDQUFDLENBQUNDLEtBQUYsQ0FBUUcsZUFBUixHQUEwQixnQ0FBMUI7QUFDQUosVUFBQUEsQ0FBQyxDQUFDQyxLQUFGLENBQVFJLEtBQVIsR0FBZ0IsT0FBaEI7QUFDRDtBQUNGLE9BTkQ7QUFPRDtBQUNGOztBQUVnQixhQUFOQyxNQUFNLEdBQUc7QUFDbEIsV0FBTyxDQUNMO0FBQ0FqQixJQUFBQSxHQUFHLGdXQUZFLENBQVA7QUFzQkQ7O0FBMUN3QztBQTZDM0NrQixNQUFNLENBQUNDLGNBQVAsQ0FBc0JDLE1BQXRCLENBQTZCLGNBQTdCLEVBQTZDakIsVUFBN0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IChDKSAyMDE1IFRoZSBHcmF2aXRlZSB0ZWFtIChodHRwOi8vZ3Jhdml0ZWUuaW8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuaW1wb3J0IHsgY3NzLCBodG1sLCBMaXRFbGVtZW50IH0gZnJvbSAnbGl0JztcblxuLyoqXG4gKiBDb2RlIGhpbnQgY29tcG9uZW50XG4gKi9cbmV4cG9ydCBjbGFzcyBHdkNvZGVIaW50IGV4dGVuZHMgTGl0RWxlbWVudCB7XG4gIHJlbmRlcigpIHtcbiAgICByZXR1cm4gaHRtbGA8c2xvdD48L3Nsb3Q+YDtcbiAgfVxuXG4gIHVwZGF0ZWQoX2NoYW5nZWRQcm9wZXJ0aWVzKSB7XG4gICAgc3VwZXIudXBkYXRlZChfY2hhbmdlZFByb3BlcnRpZXMpO1xuICAgIGlmICh0aGlzLmZpcnN0RWxlbWVudENoaWxkICE9IG51bGwpIHtcbiAgICAgIGNvbnN0IGVsZW1lbnROb2RlTGlzdE9mID0gdGhpcy5maXJzdEVsZW1lbnRDaGlsZC5xdWVyeVNlbGVjdG9yQWxsKCcuQ29kZU1pcnJvci1oaW50Jyk7XG4gICAgICBlbGVtZW50Tm9kZUxpc3RPZi5mb3JFYWNoKChlKSA9PiB7XG4gICAgICAgIGUuc3R5bGUgPSAncGFkZGluZzogNHB4O2JvcmRlci1yYWRpdXM6IDJweDt3aGl0ZS1zcGFjZTogcHJlO2N1cnNvcjogcG9pbnRlcjsnO1xuICAgICAgICBpZiAoZS5jbGFzc0xpc3QuY29udGFpbnMoJ0NvZGVNaXJyb3ItaGludC1hY3RpdmUnKSkge1xuICAgICAgICAgIGUuc3R5bGUuYmFja2dyb3VuZENvbG9yID0gJ3ZhcigtLWd2LXRoZW1lLWNvbG9yLCAjNWE3Njg0KSc7XG4gICAgICAgICAgZS5zdHlsZS5jb2xvciA9ICd3aGl0ZSc7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBnZXQgc3R5bGVzKCkge1xuICAgIHJldHVybiBbXG4gICAgICAvLyBsYW5ndWFnZT1DU1NcbiAgICAgIGNzc2BcbiAgICAgICAgOjpzbG90dGVkKC5Db2RlTWlycm9yLWhpbnRzKSB7XG4gICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICAgIHotaW5kZXg6IDgwO1xuICAgICAgICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgICAgICAgbGlzdC1zdHlsZTogbm9uZTtcbiAgICAgICAgICBtYXJnaW46IDA7XG4gICAgICAgICAgcGFkZGluZzogMnB4O1xuICAgICAgICAgIC13ZWJraXQtYm94LXNoYWRvdzogMnB4IDNweCA1cHggcmdiYSgwLCAwLCAwLCAwLjIpO1xuICAgICAgICAgIC1tb3otYm94LXNoYWRvdzogMnB4IDNweCA1cHggcmdiYSgwLCAwLCAwLCAwLjIpO1xuICAgICAgICAgIGJveC1zaGFkb3c6IDJweCAzcHggNXB4IHJnYmEoMCwgMCwgMCwgMC4yKTtcbiAgICAgICAgICBib3JkZXItcmFkaXVzOiAzcHg7XG4gICAgICAgICAgYm9yZGVyOiAxcHggc29saWQgc2lsdmVyO1xuICAgICAgICAgIGJhY2tncm91bmQ6IHdoaXRlO1xuICAgICAgICAgIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7XG4gICAgICAgICAgbWF4LWhlaWdodDogMjBlbTtcbiAgICAgICAgICBvdmVyZmxvdy15OiBhdXRvO1xuICAgICAgICB9XG4gICAgICBgLFxuICAgIF07XG4gIH1cbn1cblxud2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnZ3YtY29kZS1oaW50JywgR3ZDb2RlSGludCk7XG4iXX0=