@libs-ui/components-image-editor 0.1.1-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.
- package/README.md +259 -0
- package/defines/image-editor.define.d.ts +16 -0
- package/demo/image-editor-demo.component.d.ts +50 -0
- package/esm2022/defines/image-editor.define.mjs +89 -0
- package/esm2022/demo/image-editor-demo.component.mjs +157 -0
- package/esm2022/image-editor.component.mjs +796 -0
- package/esm2022/index.mjs +6 -0
- package/esm2022/interfaces/function-control-event.interface.mjs +2 -0
- package/esm2022/interfaces/image-editor.interface.mjs +2 -0
- package/esm2022/libs-ui-components-image-editor.mjs +5 -0
- package/esm2022/resize/resize.component.mjs +126 -0
- package/fesm2022/libs-ui-components-image-editor.mjs +1160 -0
- package/fesm2022/libs-ui-components-image-editor.mjs.map +1 -0
- package/image-editor.component.d.ts +118 -0
- package/index.d.ts +5 -0
- package/interfaces/function-control-event.interface.d.ts +4 -0
- package/interfaces/image-editor.interface.d.ts +52 -0
- package/package.json +35 -0
- package/resize/resize.component.d.ts +32 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { Component, ElementRef, ViewChild } from '@angular/core';
|
|
2
|
+
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
|
|
3
|
+
import { LibsUiComponentsImageEditorComponent } from '../image-editor.component';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export class LibsUiComponentsImageEditorDemoComponent {
|
|
6
|
+
imageFileInput;
|
|
7
|
+
imageSource = '';
|
|
8
|
+
showEditor = false;
|
|
9
|
+
editedImageUrl = '';
|
|
10
|
+
selectedFile = null;
|
|
11
|
+
imageName = '';
|
|
12
|
+
// Documentation data as regular properties
|
|
13
|
+
inputsDoc = [
|
|
14
|
+
{ name: 'imgSrc', type: 'string', default: 'Bắt buộc', description: 'Đường dẫn hoặc base64 của hình ảnh cần chỉnh sửa' },
|
|
15
|
+
{ name: 'originUrl', type: 'string', default: '-', description: 'URL gốc của hình ảnh' },
|
|
16
|
+
{ name: 'nameFile', type: 'string', default: '-', description: 'Tên file khi lưu' },
|
|
17
|
+
{ name: 'modeShowButton', type: "'save-file' | 'save-api'", default: "'save-file'", description: 'Chế độ nút lưu' },
|
|
18
|
+
{ name: 'mimetype', type: 'string', default: '-', description: 'Định dạng của hình ảnh' },
|
|
19
|
+
{ name: 'zIndex', type: 'number', default: '1200', description: 'z-index của component' },
|
|
20
|
+
{ name: 'hasZoom', type: 'boolean', default: 'false', description: 'Cho phép phóng to/thu nhỏ hình ảnh' },
|
|
21
|
+
{ name: 'aspectRatio', type: 'IAspectRatio', default: '-', description: 'Tỷ lệ khung hình mặc định' },
|
|
22
|
+
{ name: 'requiredCropFollowRatio', type: 'boolean', default: 'false', description: 'Bắt buộc cắt theo tỷ lệ đã chọn' },
|
|
23
|
+
];
|
|
24
|
+
outputsDoc = [
|
|
25
|
+
{ name: 'outClose', type: '{isClickButtonClose: boolean}', description: 'Sự kiện khi đóng trình chỉnh sửa' },
|
|
26
|
+
{ name: 'outSaveFile', type: 'ISaveFile', description: 'Sự kiện khi lưu file' },
|
|
27
|
+
{ name: 'outFunctionsControl', type: 'IImageEditorFunctionControlEvent', description: 'Sự kiện để kiểm soát các chức năng' },
|
|
28
|
+
];
|
|
29
|
+
interfacesDoc = [
|
|
30
|
+
{
|
|
31
|
+
name: 'ISaveFile',
|
|
32
|
+
code: "export interface ISaveFile {\n file: Blob;\n url: string;\n mode: 'save-file' | 'save-api' | 'save-api-as-new-file';\n}",
|
|
33
|
+
description: 'Interface định nghĩa dữ liệu khi lưu file.',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'IImageEditorFunctionControlEvent',
|
|
37
|
+
code: 'export interface IImageEditorFunctionControlEvent {\n cropImage: () => Promise<string>;\n setLoadingState: (loading: boolean) => void;\n}',
|
|
38
|
+
description: 'Interface định nghĩa các hàm điều khiển có thể được gọi từ bên ngoài component.',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'IAspectRatio',
|
|
42
|
+
code: 'export interface IAspectRatio {\n key: string;\n value: number;\n}',
|
|
43
|
+
description: 'Interface định nghĩa tỷ lệ khung hình.',
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
features = [
|
|
47
|
+
{
|
|
48
|
+
id: 1,
|
|
49
|
+
icon: '✂️',
|
|
50
|
+
title: 'Cắt ảnh',
|
|
51
|
+
description: 'Cắt hình ảnh theo khu vực tùy chỉnh hoặc dựa trên tỷ lệ định trước (1:1, 4:3, 16:9, v.v.).',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 2,
|
|
55
|
+
icon: '🔄',
|
|
56
|
+
title: 'Xoay và lật',
|
|
57
|
+
description: 'Xoay hình ảnh theo các góc khác nhau hoặc lật theo chiều ngang/dọc.',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 3,
|
|
61
|
+
icon: '📏',
|
|
62
|
+
title: 'Thay đổi kích thước',
|
|
63
|
+
description: 'Thay đổi kích thước hình ảnh theo tỷ lệ phần trăm hoặc kích thước cụ thể.',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 4,
|
|
67
|
+
icon: '💾',
|
|
68
|
+
title: 'Nhiều chế độ lưu',
|
|
69
|
+
description: 'Hỗ trợ nhiều chế độ lưu: tải xuống trực tiếp hoặc gửi đến API.',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 5,
|
|
73
|
+
icon: '🔍',
|
|
74
|
+
title: 'Phóng to/thu nhỏ',
|
|
75
|
+
description: 'Tính năng phóng to/thu nhỏ để xem chi tiết hình ảnh khi cần thiết.',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
codeExamples = [
|
|
79
|
+
{
|
|
80
|
+
id: 1,
|
|
81
|
+
title: 'Sử dụng cơ bản',
|
|
82
|
+
code: `import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n template: \`\n <libs_ui-components-image_editor\n [(imgSrc)]="imageSource"\n [modeShowButton]="'save-file'"\n [nameFile]="'image.jpg'"\n (outSaveFile)="onSaveFile($event)"\n (outClose)="onClose($event)">\n </libs_ui-components-image_editor>\n \`\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n\n onSaveFile(data: {file: Blob, url: string, mode: string}) {\n console.log('File đã được lưu:', data);\n }\n\n onClose(data: {isClickButtonClose: boolean}) {\n console.log('Đã đóng trình chỉnh sửa ảnh');\n }\n}`,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 2,
|
|
86
|
+
title: 'Sử dụng với tỷ lệ cố định',
|
|
87
|
+
code: `import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { IAspectRatio } from '@libs-ui/interfaces-types';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n template: \`\n <libs_ui-components-image_editor\n [(imgSrc)]="imageSource"\n [aspectRatio]="aspectRatio"\n [requiredCropFollowRatio]="true"\n (outSaveFile)="onSaveFile($event)">\n </libs_ui-components-image_editor>\n \`\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n aspectRatio: IAspectRatio = {\n key: '1:1',\n value: 1\n };\n\n onSaveFile(data: any) {\n console.log('Đã lưu hình ảnh với tỷ lệ 1:1');\n }\n}`,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 3,
|
|
91
|
+
title: 'Sử dụng với phần điều khiển bên ngoài',
|
|
92
|
+
code: `import { Component, ViewChild } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent, IImageEditorFunctionControlEvent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n template: \`\n <button (click)="cropAndSave()">Cắt và lưu ngay</button>\n <libs_ui-components-image_editor\n [(imgSrc)]="imageSource"\n (outFunctionsControl)="onFunctionsControl($event)">\n </libs_ui-components-image_editor>\n \`\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n editorFunctions!: IImageEditorFunctionControlEvent;\n\n onFunctionsControl(event: IImageEditorFunctionControlEvent) {\n this.editorFunctions = event;\n }\n\n async cropAndSave() {\n if (this.editorFunctions) {\n this.editorFunctions.setLoadingState(true);\n try {\n const dataUrl = await this.editorFunctions.cropImage();\n console.log('Hình ảnh đã được cắt:', dataUrl);\n } finally {\n this.editorFunctions.setLoadingState(false);\n }\n }\n }\n}`,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
copyToClipboard(text) {
|
|
96
|
+
navigator.clipboard
|
|
97
|
+
.writeText(text)
|
|
98
|
+
.then(() => {
|
|
99
|
+
alert('Đã sao chép vào clipboard');
|
|
100
|
+
})
|
|
101
|
+
.catch((err) => {
|
|
102
|
+
console.error('Không thể sao chép: ', err);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
onFileSelected(event) {
|
|
106
|
+
const input = event.target;
|
|
107
|
+
if (input.files && input.files.length > 0) {
|
|
108
|
+
this.selectedFile = input.files[0];
|
|
109
|
+
this.imageName = this.selectedFile.name;
|
|
110
|
+
console.log('File selected:', this.selectedFile.name);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
uploadAndEdit() {
|
|
114
|
+
if (!this.selectedFile) {
|
|
115
|
+
alert('Vui lòng chọn một file hình ảnh trước');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const reader = new FileReader();
|
|
119
|
+
reader.onload = (e) => {
|
|
120
|
+
if (e.target?.result) {
|
|
121
|
+
this.imageSource = e.target.result;
|
|
122
|
+
this.showEditor = true;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
reader.readAsDataURL(this.selectedFile);
|
|
126
|
+
}
|
|
127
|
+
onSaveImage(data) {
|
|
128
|
+
console.log('Image saved:', data);
|
|
129
|
+
this.editedImageUrl = data.url;
|
|
130
|
+
this.showEditor = false;
|
|
131
|
+
}
|
|
132
|
+
onCloseEditor(data) {
|
|
133
|
+
console.log('Editor closed:', data);
|
|
134
|
+
this.showEditor = false;
|
|
135
|
+
}
|
|
136
|
+
downloadImage() {
|
|
137
|
+
if (this.editedImageUrl) {
|
|
138
|
+
const link = document.createElement('a');
|
|
139
|
+
link.href = this.editedImageUrl;
|
|
140
|
+
link.download = this.imageName || 'edited-image.jpg';
|
|
141
|
+
link.click();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
handleFunctionControl(event) {
|
|
145
|
+
console.log(event);
|
|
146
|
+
}
|
|
147
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsImageEditorDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
148
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LibsUiComponentsImageEditorDemoComponent, isStandalone: true, selector: "lib-image-editor-demo", viewQueries: [{ propertyName: "imageFileInput", first: true, predicate: ["imageFileInput"], descendants: true }], ngImport: i0, template: "<div class=\"max-w-6xl mx-auto p-5 font-sans text-gray-800\">\n <header class=\"text-center py-10 bg-white rounded-lg mb-8 shadow-sm\">\n <h1 class=\"text-4xl font-bold text-gray-800 mb-2\">Demo Tr\u00ECnh Ch\u1EC9nh S\u1EEDa H\u00ECnh \u1EA2nh</h1>\n <p class=\"text-xl text-gray-500\">Th\u01B0 vi\u1EC7n component cho Angular \u0111\u1EC3 ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh</p>\n </header>\n\n <main>\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Gi\u1EDBi thi\u1EC7u</h2>\n <p>\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">@libs-ui/components-image-editor</code>\n l\u00E0 m\u1ED9t component Angular m\u1EA1nh m\u1EBD cho ph\u00E9p ng\u01B0\u1EDDi d\u00F9ng th\u1EF1c hi\u1EC7n c\u00E1c thao t\u00E1c ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh nh\u01B0 c\u1EAFt, thay \u0111\u1ED5i k\u00EDch th\u01B0\u1EDBc, xoay, l\u1EADt v\u00E0 \u00E1p d\u1EE5ng t\u1EF7 l\u1EC7 c\u1ED1 \u0111\u1ECBnh.\n </p>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E0i \u0111\u1EB7t</h2>\n\n <div class=\"mb-6\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-3\">Y\u00EAu c\u1EA7u</h3>\n <ul class=\"list-disc pl-5 space-y-2 text-gray-600\">\n <li>\n <span class=\"font-semibold\">Angular</span>\n : 18.0.0 tr\u1EDF l\u00EAn\n </li>\n <li>\n <span class=\"font-semibold\">Tailwind CSS</span>\n : 3.3.0 tr\u1EDF l\u00EAn\n </li>\n </ul>\n </div>\n\n <p class=\"mb-4\">\u0110\u1EC3 c\u00E0i \u0111\u1EB7t th\u01B0 vi\u1EC7n, s\u1EED d\u1EE5ng npm ho\u1EB7c yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>npm install @libs-ui/components-image-editor</code></pre>\n <button\n class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('npm install @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n\n <p class=\"mb-4\">Ho\u1EB7c v\u1EDBi yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>yarn add @libs-ui/components-image-editor</code></pre>\n <button\n class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('yarn add @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Demo tr\u1EF1c ti\u1EBFp</h2>\n <div>\n <p class=\"mb-4\">T\u1EA3i l\u00EAn h\u00ECnh \u1EA3nh v\u00E0 ch\u1EC9nh s\u1EEDa ngay tr\u00EAn tr\u00ECnh duy\u1EC7t:</p>\n <div class=\"flex flex-wrap items-center gap-4 mb-8\">\n <input\n type=\"file\"\n #imageFileInput\n accept=\"image/*\"\n class=\"border border-gray-300 rounded px-3 py-2\"\n (change)=\"onFileSelected($event)\" />\n <libs_ui-components-buttons-button\n label=\"T\u1EA3i l\u00EAn v\u00E0 ch\u1EC9nh s\u1EEDa\"\n (click)=\"uploadAndEdit()\"></libs_ui-components-buttons-button>\n </div>\n\n @if (editedImageUrl) {\n <div class=\"mt-8 p-6 bg-gray-50 rounded-lg\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">K\u1EBFt qu\u1EA3</h3>\n <div class=\"max-w-xl mx-auto mb-4 border border-gray-200 rounded-lg overflow-hidden shadow-md\">\n <img\n [src]=\"editedImageUrl\"\n alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\"\n class=\"w-full h-auto\" />\n </div>\n <div class=\"flex justify-center\">\n <libs_ui-components-buttons-button\n label=\"T\u1EA3i xu\u1ED1ng h\u00ECnh \u1EA3nh\"\n (click)=\"downloadImage()\"></libs_ui-components-buttons-button>\n </div>\n </div>\n }\n </div>\n </section>\n\n @if (showEditor) {\n <div class=\"fixed inset-0 z-50\">\n <libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"imageName || 'demo-image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n [hasZoom]=\"true\"\n (outSaveFile)=\"onSaveImage($event)\"\n (outClose)=\"onCloseEditor($event)\"\n (outFunctionsControl)=\"handleFunctionControl($event)\" />\n </div>\n }\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E1ch s\u1EED d\u1EE5ng</h2>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 1: S\u1EED d\u1EE5ng file HTML ri\u00EAng bi\u1EC7t</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (example.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onClose($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (example.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './example.component.html'\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n\n onSaveFile(data: {file: Blob, url: string, mode: string}) {\n console.log('File \u0111\u00E3 \u0111\u01B0\u1EE3c l\u01B0u:', data);\n }\n\n onClose(data: {isClickButtonClose: boolean}) {\n console.log('\u0110\u00E3 \u0111\u00F3ng tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 2: V\u1EDBi tr\u00ECnh ch\u1EC9nh s\u1EEDa c\u00F3 th\u1EC3 \u0111\u00F3ng/m\u1EDF</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (toggle-editor.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><button (click)=\"openEditor()\" class=\"px-4 py-2 bg-blue-500 text-white rounded\">\n M\u1EDF tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh\n</button>\n\n@if (showEditor) {\n <libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'my-image.jpg'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onCloseEditor($event)\">\n </libs_ui-components-image_editor>\n}\n\n@if (editedImageUrl) {\n <div class=\"mt-4\">\n <h3 class=\"text-lg font-semibold\">H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa:</h3>\n <img [src]=\"editedImageUrl\" alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\" class=\"mt-2 max-w-full h-auto\" />\n </div>\n}</code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (toggle-editor.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { ISaveFile } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-toggle-editor',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './toggle-editor.component.html'\n})\nexport class ToggleEditorComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n showEditor = false;\n editedImageUrl = '';\n\n openEditor() {\n this.showEditor = true;\n }\n\n onSaveFile(data: ISaveFile) {\n this.editedImageUrl = data.url;\n this.showEditor = false;\n console.log('\u0110\u00E3 l\u01B0u file:', data.file);\n }\n\n onCloseEditor(data: {isClickButtonClose: boolean}) {\n this.showEditor = false;\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 3: V\u1EDBi t\u1EF7 l\u1EC7 khung h\u00ECnh c\u1ED1 \u0111\u1ECBnh</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (fixed-ratio.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [aspectRatio]=\"aspectRatio\"\n [requiredCropFollowRatio]=\"true\"\n (outSaveFile)=\"onSaveFile($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (fixed-ratio.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { IAspectRatio } from '@libs-ui/interfaces-types';\n\n@Component({\n selector: 'app-fixed-ratio',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './fixed-ratio.component.html'\n})\nexport class FixedRatioComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n aspectRatio: IAspectRatio = {\n key: '1:1',\n value: 1\n };\n\n onSaveFile(data: any) {\n console.log('\u0110\u00E3 l\u01B0u h\u00ECnh \u1EA3nh v\u1EDBi t\u1EF7 l\u1EC7 1:1');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00E0i li\u1EC7u API</h2>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Inputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF li\u1EC7u</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u1EB7c \u0111\u1ECBnh</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3</th>\n </tr>\n </thead>\n <tbody>\n @for (input of inputsDoc; track input.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.name }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.type }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.default }}</td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Outputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF li\u1EC7u</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3</th>\n </tr>\n </thead>\n <tbody>\n @for (output of outputsDoc; track output.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.name }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.type }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ output.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Interfaces</h3>\n <div class=\"space-y-6\">\n @for (interfaceItem of interfacesDoc; track interfaceItem.name) {\n <div class=\"bg-gray-50 p-6 rounded-lg\">\n <h4 class=\"text-lg font-semibold text-gray-700 mb-3\">{{ interfaceItem.name }}</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm mb-3\"><code>{{ interfaceItem.code }}</code></pre>\n <p class=\"text-gray-600\">{{ interfaceItem.description }}</p>\n </div>\n }\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00EDnh n\u0103ng</h2>\n <ul class=\"space-y-6\">\n @for (feature of features; track feature.id) {\n <li class=\"flex items-start\">\n <span class=\"text-2xl text-blue-500\">{{ feature.icon }}</span>\n <div>\n <h3 class=\"text-lg font-semibold text-gray-700 mb-1\">{{ feature.title }}</h3>\n <p class=\"text-gray-600\">{{ feature.description }}</p>\n </div>\n </li>\n }\n </ul>\n </section>\n </main>\n</div>\n", styles: ["pre code{@apply font-mono;}.hover\\:bg-blue-600{transition:background-color .2s ease-in-out}.overflow-x-auto{-webkit-overflow-scrolling:touch}pre::-webkit-scrollbar{@apply h-1.5 bg-gray-100;}pre::-webkit-scrollbar-thumb{@apply bg-gray-300 rounded;}button:focus,input:focus{@apply outline-none ring-2 ring-blue-400 ring-opacity-50;}input[type=file]{@apply text-sm text-gray-600;}\n"], dependencies: [{ kind: "component", type: LibsUiComponentsButtonsButtonComponent, selector: "libs_ui-components-buttons-button", inputs: ["flagMouse", "type", "buttonCustom", "sizeButton", "label", "disable", "isPending", "imageLeft", "classInclude", "classIconLeft", "classIconRight", "classLabel", "iconOnlyType", "popover", "ignoreStopPropagationEvent", "zIndex", "widthLabelPopover", "styleIconLeft", "styleButton", "ignoreFocusWhenInputTab", "ignoreSetClickWhenShowPopover", "ignorePointerEvent", "isActive", "isHandlerEnterDocumentClickButton"], outputs: ["outClick", "outPopoverEvent", "outFunctionsControl"] }, { kind: "component", type: LibsUiComponentsImageEditorComponent, selector: "libs_ui-components-image_editor", inputs: ["modeShowButton", "mimetype", "zIndex", "imgSrc", "originUrl", "nameFile", "hasZoom", "aspectRatio", "requiredCropFollowRatio"], outputs: ["imgSrcChange", "outClose", "outSaveFile", "outFunctionsControl"] }] });
|
|
149
|
+
}
|
|
150
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsImageEditorDemoComponent, decorators: [{
|
|
151
|
+
type: Component,
|
|
152
|
+
args: [{ selector: 'lib-image-editor-demo', standalone: true, imports: [LibsUiComponentsButtonsButtonComponent, LibsUiComponentsImageEditorComponent], template: "<div class=\"max-w-6xl mx-auto p-5 font-sans text-gray-800\">\n <header class=\"text-center py-10 bg-white rounded-lg mb-8 shadow-sm\">\n <h1 class=\"text-4xl font-bold text-gray-800 mb-2\">Demo Tr\u00ECnh Ch\u1EC9nh S\u1EEDa H\u00ECnh \u1EA2nh</h1>\n <p class=\"text-xl text-gray-500\">Th\u01B0 vi\u1EC7n component cho Angular \u0111\u1EC3 ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh</p>\n </header>\n\n <main>\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Gi\u1EDBi thi\u1EC7u</h2>\n <p>\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">@libs-ui/components-image-editor</code>\n l\u00E0 m\u1ED9t component Angular m\u1EA1nh m\u1EBD cho ph\u00E9p ng\u01B0\u1EDDi d\u00F9ng th\u1EF1c hi\u1EC7n c\u00E1c thao t\u00E1c ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh nh\u01B0 c\u1EAFt, thay \u0111\u1ED5i k\u00EDch th\u01B0\u1EDBc, xoay, l\u1EADt v\u00E0 \u00E1p d\u1EE5ng t\u1EF7 l\u1EC7 c\u1ED1 \u0111\u1ECBnh.\n </p>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E0i \u0111\u1EB7t</h2>\n\n <div class=\"mb-6\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-3\">Y\u00EAu c\u1EA7u</h3>\n <ul class=\"list-disc pl-5 space-y-2 text-gray-600\">\n <li>\n <span class=\"font-semibold\">Angular</span>\n : 18.0.0 tr\u1EDF l\u00EAn\n </li>\n <li>\n <span class=\"font-semibold\">Tailwind CSS</span>\n : 3.3.0 tr\u1EDF l\u00EAn\n </li>\n </ul>\n </div>\n\n <p class=\"mb-4\">\u0110\u1EC3 c\u00E0i \u0111\u1EB7t th\u01B0 vi\u1EC7n, s\u1EED d\u1EE5ng npm ho\u1EB7c yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>npm install @libs-ui/components-image-editor</code></pre>\n <button\n class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('npm install @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n\n <p class=\"mb-4\">Ho\u1EB7c v\u1EDBi yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>yarn add @libs-ui/components-image-editor</code></pre>\n <button\n class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('yarn add @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Demo tr\u1EF1c ti\u1EBFp</h2>\n <div>\n <p class=\"mb-4\">T\u1EA3i l\u00EAn h\u00ECnh \u1EA3nh v\u00E0 ch\u1EC9nh s\u1EEDa ngay tr\u00EAn tr\u00ECnh duy\u1EC7t:</p>\n <div class=\"flex flex-wrap items-center gap-4 mb-8\">\n <input\n type=\"file\"\n #imageFileInput\n accept=\"image/*\"\n class=\"border border-gray-300 rounded px-3 py-2\"\n (change)=\"onFileSelected($event)\" />\n <libs_ui-components-buttons-button\n label=\"T\u1EA3i l\u00EAn v\u00E0 ch\u1EC9nh s\u1EEDa\"\n (click)=\"uploadAndEdit()\"></libs_ui-components-buttons-button>\n </div>\n\n @if (editedImageUrl) {\n <div class=\"mt-8 p-6 bg-gray-50 rounded-lg\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">K\u1EBFt qu\u1EA3</h3>\n <div class=\"max-w-xl mx-auto mb-4 border border-gray-200 rounded-lg overflow-hidden shadow-md\">\n <img\n [src]=\"editedImageUrl\"\n alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\"\n class=\"w-full h-auto\" />\n </div>\n <div class=\"flex justify-center\">\n <libs_ui-components-buttons-button\n label=\"T\u1EA3i xu\u1ED1ng h\u00ECnh \u1EA3nh\"\n (click)=\"downloadImage()\"></libs_ui-components-buttons-button>\n </div>\n </div>\n }\n </div>\n </section>\n\n @if (showEditor) {\n <div class=\"fixed inset-0 z-50\">\n <libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"imageName || 'demo-image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n [hasZoom]=\"true\"\n (outSaveFile)=\"onSaveImage($event)\"\n (outClose)=\"onCloseEditor($event)\"\n (outFunctionsControl)=\"handleFunctionControl($event)\" />\n </div>\n }\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E1ch s\u1EED d\u1EE5ng</h2>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 1: S\u1EED d\u1EE5ng file HTML ri\u00EAng bi\u1EC7t</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (example.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onClose($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (example.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './example.component.html'\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n\n onSaveFile(data: {file: Blob, url: string, mode: string}) {\n console.log('File \u0111\u00E3 \u0111\u01B0\u1EE3c l\u01B0u:', data);\n }\n\n onClose(data: {isClickButtonClose: boolean}) {\n console.log('\u0110\u00E3 \u0111\u00F3ng tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 2: V\u1EDBi tr\u00ECnh ch\u1EC9nh s\u1EEDa c\u00F3 th\u1EC3 \u0111\u00F3ng/m\u1EDF</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (toggle-editor.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><button (click)=\"openEditor()\" class=\"px-4 py-2 bg-blue-500 text-white rounded\">\n M\u1EDF tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh\n</button>\n\n@if (showEditor) {\n <libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'my-image.jpg'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onCloseEditor($event)\">\n </libs_ui-components-image_editor>\n}\n\n@if (editedImageUrl) {\n <div class=\"mt-4\">\n <h3 class=\"text-lg font-semibold\">H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa:</h3>\n <img [src]=\"editedImageUrl\" alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\" class=\"mt-2 max-w-full h-auto\" />\n </div>\n}</code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (toggle-editor.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { ISaveFile } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-toggle-editor',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './toggle-editor.component.html'\n})\nexport class ToggleEditorComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n showEditor = false;\n editedImageUrl = '';\n\n openEditor() {\n this.showEditor = true;\n }\n\n onSaveFile(data: ISaveFile) {\n this.editedImageUrl = data.url;\n this.showEditor = false;\n console.log('\u0110\u00E3 l\u01B0u file:', data.file);\n }\n\n onCloseEditor(data: {isClickButtonClose: boolean}) {\n this.showEditor = false;\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 3: V\u1EDBi t\u1EF7 l\u1EC7 khung h\u00ECnh c\u1ED1 \u0111\u1ECBnh</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (fixed-ratio.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [aspectRatio]=\"aspectRatio\"\n [requiredCropFollowRatio]=\"true\"\n (outSaveFile)=\"onSaveFile($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (fixed-ratio.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { IAspectRatio } from '@libs-ui/interfaces-types';\n\n@Component({\n selector: 'app-fixed-ratio',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './fixed-ratio.component.html'\n})\nexport class FixedRatioComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n aspectRatio: IAspectRatio = {\n key: '1:1',\n value: 1\n };\n\n onSaveFile(data: any) {\n console.log('\u0110\u00E3 l\u01B0u h\u00ECnh \u1EA3nh v\u1EDBi t\u1EF7 l\u1EC7 1:1');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00E0i li\u1EC7u API</h2>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Inputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF li\u1EC7u</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u1EB7c \u0111\u1ECBnh</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3</th>\n </tr>\n </thead>\n <tbody>\n @for (input of inputsDoc; track input.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.name }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.type }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.default }}</td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Outputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF li\u1EC7u</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3</th>\n </tr>\n </thead>\n <tbody>\n @for (output of outputsDoc; track output.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.name }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.type }}</code>\n </td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ output.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Interfaces</h3>\n <div class=\"space-y-6\">\n @for (interfaceItem of interfacesDoc; track interfaceItem.name) {\n <div class=\"bg-gray-50 p-6 rounded-lg\">\n <h4 class=\"text-lg font-semibold text-gray-700 mb-3\">{{ interfaceItem.name }}</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm mb-3\"><code>{{ interfaceItem.code }}</code></pre>\n <p class=\"text-gray-600\">{{ interfaceItem.description }}</p>\n </div>\n }\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00EDnh n\u0103ng</h2>\n <ul class=\"space-y-6\">\n @for (feature of features; track feature.id) {\n <li class=\"flex items-start\">\n <span class=\"text-2xl text-blue-500\">{{ feature.icon }}</span>\n <div>\n <h3 class=\"text-lg font-semibold text-gray-700 mb-1\">{{ feature.title }}</h3>\n <p class=\"text-gray-600\">{{ feature.description }}</p>\n </div>\n </li>\n }\n </ul>\n </section>\n </main>\n</div>\n", styles: ["pre code{@apply font-mono;}.hover\\:bg-blue-600{transition:background-color .2s ease-in-out}.overflow-x-auto{-webkit-overflow-scrolling:touch}pre::-webkit-scrollbar{@apply h-1.5 bg-gray-100;}pre::-webkit-scrollbar-thumb{@apply bg-gray-300 rounded;}button:focus,input:focus{@apply outline-none ring-2 ring-blue-400 ring-opacity-50;}input[type=file]{@apply text-sm text-gray-600;}\n"] }]
|
|
153
|
+
}], propDecorators: { imageFileInput: [{
|
|
154
|
+
type: ViewChild,
|
|
155
|
+
args: ['imageFileInput']
|
|
156
|
+
}] } });
|
|
157
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtZWRpdG9yLWRlbW8uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2ltYWdlLWVkaXRvci9zcmMvZGVtby9pbWFnZS1lZGl0b3ItZGVtby5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9saWJzLXVpL2NvbXBvbmVudHMvaW1hZ2UtZWRpdG9yL3NyYy9kZW1vL2ltYWdlLWVkaXRvci1kZW1vLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNqRSxPQUFPLEVBQUUsc0NBQXNDLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUM1RixPQUFPLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQzs7QUFXakYsTUFBTSxPQUFPLHdDQUF3QztJQUN0QixjQUFjLENBQWdDO0lBRTNFLFdBQVcsR0FBRyxFQUFFLENBQUM7SUFDakIsVUFBVSxHQUFHLEtBQUssQ0FBQztJQUNuQixjQUFjLEdBQUcsRUFBRSxDQUFDO0lBQ3BCLFlBQVksR0FBZ0IsSUFBSSxDQUFDO0lBQ2pDLFNBQVMsR0FBRyxFQUFFLENBQUM7SUFFZiwyQ0FBMkM7SUFDM0MsU0FBUyxHQUFHO1FBQ1YsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsa0RBQWtELEVBQUU7UUFDeEgsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsc0JBQXNCLEVBQUU7UUFDeEYsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxXQUFX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QUFTOytCQUNFLHVCQUF1QixjQUNyQixJQUFJLFdBQ1AsQ0FBQyxzQ0FBc0MsRUFBRSxvQ0FBb0MsQ0FBQzs4QkFLMUQsY0FBYztzQkFBMUMsU0FBUzt1QkFBQyxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTGlic1VpQ29tcG9uZW50c0J1dHRvbnNCdXR0b25Db21wb25lbnQgfSBmcm9tICdAbGlicy11aS9jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uJztcbmltcG9ydCB7IExpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudCB9IGZyb20gJy4uL2ltYWdlLWVkaXRvci5jb21wb25lbnQnO1xuaW1wb3J0IHsgSVNhdmVGaWxlIH0gZnJvbSAnLi4vaW50ZXJmYWNlcy9pbWFnZS1lZGl0b3IuaW50ZXJmYWNlJztcbmltcG9ydCB7IElJbWFnZUVkaXRvckZ1bmN0aW9uQ29udHJvbEV2ZW50IH0gZnJvbSAnLi4vaW50ZXJmYWNlcy9mdW5jdGlvbi1jb250cm9sLWV2ZW50LmludGVyZmFjZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1pbWFnZS1lZGl0b3ItZGVtbycsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtMaWJzVWlDb21wb25lbnRzQnV0dG9uc0J1dHRvbkNvbXBvbmVudCwgTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcbiAgdGVtcGxhdGVVcmw6ICcuL2ltYWdlLWVkaXRvci1kZW1vLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmw6ICcuL2ltYWdlLWVkaXRvci1kZW1vLmNvbXBvbmVudC5zY3NzJyxcbn0pXG5leHBvcnQgY2xhc3MgTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yRGVtb0NvbXBvbmVudCB7XG4gIEBWaWV3Q2hpbGQoJ2ltYWdlRmlsZUlucHV0JykgaW1hZ2VGaWxlSW5wdXQhOiBFbGVtZW50UmVmPEhUTUxJbnB1dEVsZW1lbnQ+O1xuXG4gIGltYWdlU291cmNlID0gJyc7XG4gIHNob3dFZGl0b3IgPSBmYWxzZTtcbiAgZWRpdGVkSW1hZ2VVcmwgPSAnJztcbiAgc2VsZWN0ZWRGaWxlOiBGaWxlIHwgbnVsbCA9IG51bGw7XG4gIGltYWdlTmFtZSA9ICcnO1xuXG4gIC8vIERvY3VtZW50YXRpb24gZGF0YSBhcyByZWd1bGFyIHByb3BlcnRpZXNcbiAgaW5wdXRzRG9jID0gW1xuICAgIHsgbmFtZTogJ2ltZ1NyYycsIHR5cGU6ICdzdHJpbmcnLCBkZWZhdWx0OiAnQuG6r3QgYnXhu5ljJywgZGVzY3JpcHRpb246ICfEkMaw4budbmcgZOG6q24gaG/hurdjIGJhc2U2NCBj4bunYSBow6xuaCDhuqNuaCBj4bqnbiBjaOG7iW5oIHPhu61hJyB9LFxuICAgIHsgbmFtZTogJ29yaWdpblVybCcsIHR5cGU6ICdzdHJpbmcnLCBkZWZhdWx0OiAnLScsIGRlc2NyaXB0aW9uOiAnVVJMIGfhu5FjIGPhu6dhIGjDrG5oIOG6o25oJyB9LFxuICAgIHsgbmFtZTogJ25hbWVGaWxlJywgdHlwZTogJ3N0cmluZycsIGRlZmF1bHQ6ICctJywgZGVzY3JpcHRpb246ICdUw6puIGZpbGUga2hpIGzGsHUnIH0sXG4gICAgeyBuYW1lOiAnbW9kZVNob3dCdXR0b24nLCB0eXBlOiBcIidzYXZlLWZpbGUnIHwgJ3NhdmUtYXBpJ1wiLCBkZWZhdWx0OiBcIidzYXZlLWZpbGUnXCIsIGRlc2NyaXB0aW9uOiAnQ2jhur8gxJHhu5kgbsO6dCBsxrB1JyB9LFxuICAgIHsgbmFtZTogJ21pbWV0eXBlJywgdHlwZTogJ3N0cmluZycsIGRlZmF1bHQ6ICctJywgZGVzY3JpcHRpb246ICfEkOG7i25oIGThuqFuZyBj4bunYSBow6xuaCDhuqNuaCcgfSxcbiAgICB7IG5hbWU6ICd6SW5kZXgnLCB0eXBlOiAnbnVtYmVyJywgZGVmYXVsdDogJzEyMDAnLCBkZXNjcmlwdGlvbjogJ3otaW5kZXggY+G7p2EgY29tcG9uZW50JyB9LFxuICAgIHsgbmFtZTogJ2hhc1pvb20nLCB0eXBlOiAnYm9vbGVhbicsIGRlZmF1bHQ6ICdmYWxzZScsIGRlc2NyaXB0aW9uOiAnQ2hvIHBow6lwIHBow7NuZyB0by90aHUgbmjhu48gaMOsbmgg4bqjbmgnIH0sXG4gICAgeyBuYW1lOiAnYXNwZWN0UmF0aW8nLCB0eXBlOiAnSUFzcGVjdFJhdGlvJywgZGVmYXVsdDogJy0nLCBkZXNjcmlwdGlvbjogJ1Thu7cgbOG7hyBraHVuZyBow6xuaCBt4bq3YyDEkeG7i25oJyB9LFxuICAgIHsgbmFtZTogJ3JlcXVpcmVkQ3JvcEZvbGxvd1JhdGlvJywgdHlwZTogJ2Jvb2xlYW4nLCBkZWZhdWx0OiAnZmFsc2UnLCBkZXNjcmlwdGlvbjogJ0Lhuq90IGJ14buZYyBj4bqvdCB0aGVvIHThu7cgbOG7hyDEkcOjIGNo4buNbicgfSxcbiAgXTtcblxuICBvdXRwdXRzRG9jID0gW1xuICAgIHsgbmFtZTogJ291dENsb3NlJywgdHlwZTogJ3tpc0NsaWNrQnV0dG9uQ2xvc2U6IGJvb2xlYW59JywgZGVzY3JpcHRpb246ICdT4buxIGtp4buHbiBraGkgxJHDs25nIHRyw6xuaCBjaOG7iW5oIHPhu61hJyB9LFxuICAgIHsgbmFtZTogJ291dFNhdmVGaWxlJywgdHlwZTogJ0lTYXZlRmlsZScsIGRlc2NyaXB0aW9uOiAnU+G7sSBraeG7h24ga2hpIGzGsHUgZmlsZScgfSxcbiAgICB7IG5hbWU6ICdvdXRGdW5jdGlvbnNDb250cm9sJywgdHlwZTogJ0lJbWFnZUVkaXRvckZ1bmN0aW9uQ29udHJvbEV2ZW50JywgZGVzY3JpcHRpb246ICdT4buxIGtp4buHbiDEkeG7gyBraeG7g20gc2/DoXQgY8OhYyBjaOG7qWMgbsSDbmcnIH0sXG4gIF07XG5cbiAgaW50ZXJmYWNlc0RvYyA9IFtcbiAgICB7XG4gICAgICBuYW1lOiAnSVNhdmVGaWxlJyxcbiAgICAgIGNvZGU6IFwiZXhwb3J0IGludGVyZmFjZSBJU2F2ZUZpbGUge1xcbiAgZmlsZTogQmxvYjtcXG4gIHVybDogc3RyaW5nO1xcbiAgbW9kZTogJ3NhdmUtZmlsZScgfCAnc2F2ZS1hcGknIHwgJ3NhdmUtYXBpLWFzLW5ldy1maWxlJztcXG59XCIsXG4gICAgICBkZXNjcmlwdGlvbjogJ0ludGVyZmFjZSDEkeG7i25oIG5naMSpYSBk4buvIGxp4buHdSBraGkgbMawdSBmaWxlLicsXG4gICAgfSxcbiAgICB7XG4gICAgICBuYW1lOiAnSUltYWdlRWRpdG9yRnVuY3Rpb25Db250cm9sRXZlbnQnLFxuICAgICAgY29kZTogJ2V4cG9ydCBpbnRlcmZhY2UgSUltYWdlRWRpdG9yRnVuY3Rpb25Db250cm9sRXZlbnQge1xcbiAgY3JvcEltYWdlOiAoKSA9PiBQcm9taXNlPHN0cmluZz47XFxuICBzZXRMb2FkaW5nU3RhdGU6IChsb2FkaW5nOiBib29sZWFuKSA9PiB2b2lkO1xcbn0nLFxuICAgICAgZGVzY3JpcHRpb246ICdJbnRlcmZhY2UgxJHhu4tuaCBuZ2jEqWEgY8OhYyBow6BtIMSRaeG7gXUga2hp4buDbiBjw7MgdGjhu4MgxJHGsOG7o2MgZ+G7jWkgdOG7qyBiw6puIG5nb8OgaSBjb21wb25lbnQuJyxcbiAgICB9LFxuICAgIHtcbiAgICAgIG5hbWU6ICdJQXNwZWN0UmF0aW8nLFxuICAgICAgY29kZTogJ2V4cG9ydCBpbnRlcmZhY2UgSUFzcGVjdFJhdGlvIHtcXG4gIGtleTogc3RyaW5nO1xcbiAgdmFsdWU6IG51bWJlcjtcXG59JyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnSW50ZXJmYWNlIMSR4buLbmggbmdoxKlhIHThu7cgbOG7hyBraHVuZyBow6xuaC4nLFxuICAgIH0sXG4gIF07XG5cbiAgZmVhdHVyZXMgPSBbXG4gICAge1xuICAgICAgaWQ6IDEsXG4gICAgICBpY29uOiAn4pyC77iPJyxcbiAgICAgIHRpdGxlOiAnQ+G6r3Qg4bqjbmgnLFxuICAgICAgZGVzY3JpcHRpb246ICdD4bqvdCBow6xuaCDhuqNuaCB0aGVvIGtodSB24buxYyB0w7l5IGNo4buJbmggaG/hurdjIGThu7FhIHRyw6puIHThu7cgbOG7hyDEkeG7i25oIHRyxrDhu5tjICgxOjEsIDQ6MywgMTY6OSwgdi52LikuJyxcbiAgICB9LFxuICAgIHtcbiAgICAgIGlkOiAyLFxuICAgICAgaWNvbjogJ/CflIQnLFxuICAgICAgdGl0bGU6ICdYb2F5IHbDoCBs4bqtdCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ1hvYXkgaMOsbmgg4bqjbmggdGhlbyBjw6FjIGfDs2Mga2jDoWMgbmhhdSBob+G6t2MgbOG6rXQgdGhlbyBjaGnhu4F1IG5nYW5nL2Thu41jLicsXG4gICAgfSxcbiAgICB7XG4gICAgICBpZDogMyxcbiAgICAgIGljb246ICfwn5OPJyxcbiAgICAgIHRpdGxlOiAnVGhheSDEkeG7lWkga8OtY2ggdGjGsOG7m2MnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGF5IMSR4buVaSBrw61jaCB0aMaw4bubYyBow6xuaCDhuqNuaCB0aGVvIHThu7cgbOG7hyBwaOG6p24gdHLEg20gaG/hurdjIGvDrWNoIHRoxrDhu5tjIGPhu6UgdGjhu4MuJyxcbiAgICB9LFxuICAgIHtcbiAgICAgIGlkOiA0LFxuICAgICAgaWNvbjogJ/Cfkr4nLFxuICAgICAgdGl0bGU6ICdOaGnhu4F1IGNo4bq/IMSR4buZIGzGsHUnLFxuICAgICAgZGVzY3JpcHRpb246ICdI4buXIHRy4bujIG5oaeG7gXUgY2jhur8gxJHhu5kgbMawdTogdOG6o2kgeHXhu5FuZyB0cuG7sWMgdGnhur9wIGhv4bq3YyBn4butaSDEkeG6v24gQVBJLicsXG4gICAgfSxcbiAgICB7XG4gICAgICBpZDogNSxcbiAgICAgIGljb246ICfwn5SNJyxcbiAgICAgIHRpdGxlOiAnUGjDs25nIHRvL3RodSBuaOG7jycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1TDrW5oIG7Eg25nIHBow7NuZyB0by90aHUgbmjhu48gxJHhu4MgeGVtIGNoaSB0aeG6v3QgaMOsbmgg4bqjbmgga2hpIGPhuqduIHRoaeG6v3QuJyxcbiAgICB9LFxuICBdO1xuXG4gIGNvZGVFeGFtcGxlcyA9IFtcbiAgICB7XG4gICAgICBpZDogMSxcbiAgICAgIHRpdGxlOiAnU+G7rSBk4bulbmcgY8ahIGLhuqNuJyxcbiAgICAgIGNvZGU6IGBpbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcXG5pbXBvcnQgeyBMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnQgfSBmcm9tICdAbGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcic7XFxuXFxuQENvbXBvbmVudCh7XFxuICBzZWxlY3RvcjogJ2FwcC1leGFtcGxlJyxcXG4gIHN0YW5kYWxvbmU6IHRydWUsXFxuICBpbXBvcnRzOiBbTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcXG4gIHRlbXBsYXRlOiBcXGBcXG4gICAgPGxpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3JcXG4gICAgICBbKGltZ1NyYyldPVwiaW1hZ2VTb3VyY2VcIlxcbiAgICAgIFttb2RlU2hvd0J1dHRvbl09XCInc2F2ZS1maWxlJ1wiXFxuICAgICAgW25hbWVGaWxlXT1cIidpbWFnZS5qcGcnXCJcXG4gICAgICAob3V0U2F2ZUZpbGUpPVwib25TYXZlRmlsZSgkZXZlbnQpXCJcXG4gICAgICAob3V0Q2xvc2UpPVwib25DbG9zZSgkZXZlbnQpXCI+XFxuICAgIDwvbGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvcj5cXG4gIFxcYFxcbn0pXFxuZXhwb3J0IGNsYXNzIEV4YW1wbGVDb21wb25lbnQge1xcbiAgaW1hZ2VTb3VyY2UgPSAnaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ltYWdlLmpwZyc7XFxuXFxuICBvblNhdmVGaWxlKGRhdGE6IHtmaWxlOiBCbG9iLCB1cmw6IHN0cmluZywgbW9kZTogc3RyaW5nfSkge1xcbiAgICBjb25zb2xlLmxvZygnRmlsZSDEkcOjIMSRxrDhu6NjIGzGsHU6JywgZGF0YSk7XFxuICB9XFxuXFxuICBvbkNsb3NlKGRhdGE6IHtpc0NsaWNrQnV0dG9uQ2xvc2U6IGJvb2xlYW59KSB7XFxuICAgIGNvbnNvbGUubG9nKCfEkMOjIMSRw7NuZyB0csOsbmggY2jhu4luaCBz4butYSDhuqNuaCcpO1xcbiAgfVxcbn1gLFxuICAgIH0sXG4gICAge1xuICAgICAgaWQ6IDIsXG4gICAgICB0aXRsZTogJ1Phu60gZOG7pW5nIHbhu5tpIHThu7cgbOG7hyBj4buRIMSR4buLbmgnLFxuICAgICAgY29kZTogYGltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xcbmltcG9ydCB7IExpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudCB9IGZyb20gJ0BsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJztcXG5pbXBvcnQgeyBJQXNwZWN0UmF0aW8gfSBmcm9tICdAbGlicy11aS9pbnRlcmZhY2VzLXR5cGVzJztcXG5cXG5AQ29tcG9uZW50KHtcXG4gIHNlbGVjdG9yOiAnYXBwLWV4YW1wbGUnLFxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcXG4gIGltcG9ydHM6IFtMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnRdLFxcbiAgdGVtcGxhdGU6IFxcYFxcbiAgICA8bGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvclxcbiAgICAgIFsoaW1nU3JjKV09XCJpbWFnZVNvdXJjZVwiXFxuICAgICAgW2FzcGVjdFJhdGlvXT1cImFzcGVjdFJhdGlvXCJcXG4gICAgICBbcmVxdWlyZWRDcm9wRm9sbG93UmF0aW9dPVwidHJ1ZVwiXFxuICAgICAgKG91dFNhdmVGaWxlKT1cIm9uU2F2ZUZpbGUoJGV2ZW50KVwiPlxcbiAgICA8L2xpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3I+XFxuICBcXGBcXG59KVxcbmV4cG9ydCBjbGFzcyBFeGFtcGxlQ29tcG9uZW50IHtcXG4gIGltYWdlU291cmNlID0gJ2h0dHBzOi8vZXhhbXBsZS5jb20vcGF0aC90by9pbWFnZS5qcGcnO1xcbiAgYXNwZWN0UmF0aW86IElBc3BlY3RSYXRpbyA9IHtcXG4gICAga2V5OiAnMToxJyxcXG4gICAgdmFsdWU6IDFcXG4gIH07XFxuXFxuICBvblNhdmVGaWxlKGRhdGE6IGFueSkge1xcbiAgICBjb25zb2xlLmxvZygnxJDDoyBsxrB1IGjDrG5oIOG6o25oIHbhu5tpIHThu7cgbOG7hyAxOjEnKTtcXG4gIH1cXG59YCxcbiAgICB9LFxuICAgIHtcbiAgICAgIGlkOiAzLFxuICAgICAgdGl0bGU6ICdT4butIGThu6VuZyB24bubaSBwaOG6p24gxJFp4buBdSBraGnhu4NuIGLDqm4gbmdvw6BpJyxcbiAgICAgIGNvZGU6IGBpbXBvcnQgeyBDb21wb25lbnQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xcbmltcG9ydCB7IExpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudCwgSUltYWdlRWRpdG9yRnVuY3Rpb25Db250cm9sRXZlbnQgfSBmcm9tICdAbGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcic7XFxuXFxuQENvbXBvbmVudCh7XFxuICBzZWxlY3RvcjogJ2FwcC1leGFtcGxlJyxcXG4gIHN0YW5kYWxvbmU6IHRydWUsXFxuICBpbXBvcnRzOiBbTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcXG4gIHRlbXBsYXRlOiBcXGBcXG4gICAgPGJ1dHRvbiAoY2xpY2spPVwiY3JvcEFuZFNhdmUoKVwiPkPhuq90IHbDoCBsxrB1IG5nYXk8L2J1dHRvbj5cXG4gICAgPGxpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3JcXG4gICAgICBbKGltZ1NyYyldPVwiaW1hZ2VTb3VyY2VcIlxcbiAgICAgIChvdXRGdW5jdGlvbnNDb250cm9sKT1cIm9uRnVuY3Rpb25zQ29udHJvbCgkZXZlbnQpXCI+XFxuICAgIDwvbGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvcj5cXG4gIFxcYFxcbn0pXFxuZXhwb3J0IGNsYXNzIEV4YW1wbGVDb21wb25lbnQge1xcbiAgaW1hZ2VTb3VyY2UgPSAnaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ltYWdlLmpwZyc7XFxuICBlZGl0b3JGdW5jdGlvbnMhOiBJSW1hZ2VFZGl0b3JGdW5jdGlvbkNvbnRyb2xFdmVudDtcXG5cXG4gIG9uRnVuY3Rpb25zQ29udHJvbChldmVudDogSUltYWdlRWRpdG9yRnVuY3Rpb25Db250cm9sRXZlbnQpIHtcXG4gICAgdGhpcy5lZGl0b3JGdW5jdGlvbnMgPSBldmVudDtcXG4gIH1cXG5cXG4gIGFzeW5jIGNyb3BBbmRTYXZlKCkge1xcbiAgICBpZiAodGhpcy5lZGl0b3JGdW5jdGlvbnMpIHtcXG4gICAgICB0aGlzLmVkaXRvckZ1bmN0aW9ucy5zZXRMb2FkaW5nU3RhdGUodHJ1ZSk7XFxuICAgICAgdHJ5IHtcXG4gICAgICAgIGNvbnN0IGRhdGFVcmwgPSBhd2FpdCB0aGlzLmVkaXRvckZ1bmN0aW9ucy5jcm9wSW1hZ2UoKTtcXG4gICAgICAgIGNvbnNvbGUubG9nKCdIw6xuaCDhuqNuaCDEkcOjIMSRxrDhu6NjIGPhuq90OicsIGRhdGFVcmwpO1xcbiAgICAgIH0gZmluYWxseSB7XFxuICAgICAgICB0aGlzLmVkaXRvckZ1bmN0aW9ucy5zZXRMb2FkaW5nU3RhdGUoZmFsc2UpO1xcbiAgICAgIH1cXG4gICAgfVxcbiAgfVxcbn1gLFxuICAgIH0sXG4gIF07XG5cbiAgY29weVRvQ2xpcGJvYXJkKHRleHQ6IHN0cmluZyk6IHZvaWQge1xuICAgIG5hdmlnYXRvci5jbGlwYm9hcmRcbiAgICAgIC53cml0ZVRleHQodGV4dClcbiAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgYWxlcnQoJ8SQw6Mgc2FvIGNow6lwIHbDoG8gY2xpcGJvYXJkJyk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignS2jDtG5nIHRo4buDIHNhbyBjaMOpcDogJywgZXJyKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgb25GaWxlU2VsZWN0ZWQoZXZlbnQ6IEV2ZW50KSB7XG4gICAgY29uc3QgaW5wdXQgPSBldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudDtcbiAgICBpZiAoaW5wdXQuZmlsZXMgJiYgaW5wdXQuZmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5zZWxlY3RlZEZpbGUgPSBpbnB1dC5maWxlc1swXTtcbiAgICAgIHRoaXMuaW1hZ2VOYW1lID0gdGhpcy5zZWxlY3RlZEZpbGUubmFtZTtcbiAgICAgIGNvbnNvbGUubG9nKCdGaWxlIHNlbGVjdGVkOicsIHRoaXMuc2VsZWN0ZWRGaWxlLm5hbWUpO1xuICAgIH1cbiAgfVxuXG4gIHVwbG9hZEFuZEVkaXQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnNlbGVjdGVkRmlsZSkge1xuICAgICAgYWxlcnQoJ1Z1aSBsw7JuZyBjaOG7jW4gbeG7mXQgZmlsZSBow6xuaCDhuqNuaCB0csaw4bubYycpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XG4gICAgcmVhZGVyLm9ubG9hZCA9IChlOiBQcm9ncmVzc0V2ZW50PEZpbGVSZWFkZXI+KSA9PiB7XG4gICAgICBpZiAoZS50YXJnZXQ/LnJlc3VsdCkge1xuICAgICAgICB0aGlzLmltYWdlU291cmNlID0gZS50YXJnZXQucmVzdWx0IGFzIHN0cmluZztcbiAgICAgICAgdGhpcy5zaG93RWRpdG9yID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKHRoaXMuc2VsZWN0ZWRGaWxlKTtcbiAgfVxuXG4gIG9uU2F2ZUltYWdlKGRhdGE6IElTYXZlRmlsZSk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKCdJbWFnZSBzYXZlZDonLCBkYXRhKTtcbiAgICB0aGlzLmVkaXRlZEltYWdlVXJsID0gZGF0YS51cmw7XG4gICAgdGhpcy5zaG93RWRpdG9yID0gZmFsc2U7XG4gIH1cblxuICBvbkNsb3NlRWRpdG9yKGRhdGE6IHsgaXNDbGlja0J1dHRvbkNsb3NlOiBib29sZWFuIH0pOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnRWRpdG9yIGNsb3NlZDonLCBkYXRhKTtcbiAgICB0aGlzLnNob3dFZGl0b3IgPSBmYWxzZTtcbiAgfVxuXG4gIGRvd25sb2FkSW1hZ2UoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZWRpdGVkSW1hZ2VVcmwpIHtcbiAgICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgICBsaW5rLmhyZWYgPSB0aGlzLmVkaXRlZEltYWdlVXJsO1xuICAgICAgbGluay5kb3dubG9hZCA9IHRoaXMuaW1hZ2VOYW1lIHx8ICdlZGl0ZWQtaW1hZ2UuanBnJztcbiAgICAgIGxpbmsuY2xpY2soKTtcbiAgICB9XG4gIH1cblxuICBoYW5kbGVGdW5jdGlvbkNvbnRyb2woZXZlbnQ6IElJbWFnZUVkaXRvckZ1bmN0aW9uQ29udHJvbEV2ZW50KSB7XG4gICAgY29uc29sZS5sb2coZXZlbnQpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwibWF4LXctNnhsIG14LWF1dG8gcC01IGZvbnQtc2FucyB0ZXh0LWdyYXktODAwXCI+XG4gIDxoZWFkZXIgY2xhc3M9XCJ0ZXh0LWNlbnRlciBweS0xMCBiZy13aGl0ZSByb3VuZGVkLWxnIG1iLTggc2hhZG93LXNtXCI+XG4gICAgPGgxIGNsYXNzPVwidGV4dC00eGwgZm9udC1ib2xkIHRleHQtZ3JheS04MDAgbWItMlwiPkRlbW8gVHLDrG5oIENo4buJbmggU+G7rWEgSMOsbmgg4bqibmg8L2gxPlxuICAgIDxwIGNsYXNzPVwidGV4dC14bCB0ZXh0LWdyYXktNTAwXCI+VGjGsCB2aeG7h24gY29tcG9uZW50IGNobyBBbmd1bGFyIMSR4buDIGNo4buJbmggc+G7rWEgaMOsbmgg4bqjbmg8L3A+XG4gIDwvaGVhZGVyPlxuXG4gIDxtYWluPlxuICAgIDxzZWN0aW9uIGNsYXNzPVwiYmctd2hpdGUgcm91bmRlZC1sZyBwLTggbWItOCBzaGFkb3ctc21cIj5cbiAgICAgIDxoMiBjbGFzcz1cInRleHQtMnhsIGZvbnQtYm9sZCB0ZXh0LWdyYXktODAwIG1iLTUgcGItMyBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj5HaeG7m2kgdGhp4buHdTwvaDI+XG4gICAgICA8cD5cbiAgICAgICAgPGNvZGUgY2xhc3M9XCJ0ZXh0LXNtIGJnLWdyYXktMTAwIHB4LTEuNSBweS0wLjUgcm91bmRlZFwiPiYjNjQ7bGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcjwvY29kZT5cbiAgICAgICAgbMOgIG3hu5l0IGNvbXBvbmVudCBBbmd1bGFyIG3huqFuaCBt4bq9IGNobyBwaMOpcCBuZ8aw4budaSBkw7luZyB0aOG7sWMgaGnhu4duIGPDoWMgdGhhbyB0w6FjIGNo4buJbmggc+G7rWEgaMOsbmgg4bqjbmggbmjGsCBj4bqvdCwgdGhheSDEkeG7lWkga8OtY2ggdGjGsOG7m2MsIHhvYXksIGzhuq10IHbDoCDDoXAgZOG7pW5nIHThu7cgbOG7hyBj4buRIMSR4buLbmguXG4gICAgICA8L3A+XG4gICAgPC9zZWN0aW9uPlxuXG4gICAgPHNlY3Rpb24gY2xhc3M9XCJiZy13aGl0ZSByb3VuZGVkLWxnIHAtOCBtYi04IHNoYWRvdy1zbVwiPlxuICAgICAgPGgyIGNsYXNzPVwidGV4dC0yeGwgZm9udC1ib2xkIHRleHQtZ3JheS04MDAgbWItNSBwYi0zIGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiPkPDoGkgxJHhurd0PC9oMj5cblxuICAgICAgPGRpdiBjbGFzcz1cIm1iLTZcIj5cbiAgICAgICAgPGgzIGNsYXNzPVwidGV4dC14bCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDAgbWItM1wiPlnDqnUgY+G6p3U8L2gzPlxuICAgICAgICA8dWwgY2xhc3M9XCJsaXN0LWRpc2MgcGwtNSBzcGFjZS15LTIgdGV4dC1ncmF5LTYwMFwiPlxuICAgICAgICAgIDxsaT5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZm9udC1zZW1pYm9sZFwiPkFuZ3VsYXI8L3NwYW4+XG4gICAgICAgICAgICA6IDE4LjAuMCB0cuG7nyBsw6puXG4gICAgICAgICAgPC9saT5cbiAgICAgICAgICA8bGk+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZvbnQtc2VtaWJvbGRcIj5UYWlsd2luZCBDU1M8L3NwYW4+XG4gICAgICAgICAgICA6IDMuMy4wIHRy4bufIGzDqm5cbiAgICAgICAgICA8L2xpPlxuICAgICAgICA8L3VsPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxwIGNsYXNzPVwibWItNFwiPsSQ4buDIGPDoGkgxJHhurd0IHRoxrAgdmnhu4duLCBz4butIGThu6VuZyBucG0gaG/hurdjIHlhcm46PC9wPlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgbWItNlwiPlxuICAgICAgICA8cHJlIGNsYXNzPVwiZmxleC0xIHRleHQtc20gb3ZlcmZsb3cteC1hdXRvXCI+PGNvZGU+bnBtIGluc3RhbGwgJiM2NDtsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yPC9jb2RlPjwvcHJlPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJtbC00IHB4LTMgcHktMSBiZy1ibHVlLTUwMCB0ZXh0LXdoaXRlIHJvdW5kZWQgaG92ZXI6YmctYmx1ZS02MDAgdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICAgIChjbGljayk9XCJjb3B5VG9DbGlwYm9hcmQoJ25wbSBpbnN0YWxsIEBsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJylcIj5cbiAgICAgICAgICBTYW8gY2jDqXBcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPHAgY2xhc3M9XCJtYi00XCI+SG/hurdjIHbhu5tpIHlhcm46PC9wPlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgbWItNlwiPlxuICAgICAgICA8cHJlIGNsYXNzPVwiZmxleC0xIHRleHQtc20gb3ZlcmZsb3cteC1hdXRvXCI+PGNvZGU+eWFybiBhZGQgJiM2NDtsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yPC9jb2RlPjwvcHJlPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgY2xhc3M9XCJtbC00IHB4LTMgcHktMSBiZy1ibHVlLTUwMCB0ZXh0LXdoaXRlIHJvdW5kZWQgaG92ZXI6YmctYmx1ZS02MDAgdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICAgIChjbGljayk9XCJjb3B5VG9DbGlwYm9hcmQoJ3lhcm4gYWRkIEBsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJylcIj5cbiAgICAgICAgICBTYW8gY2jDqXBcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICA8L3NlY3Rpb24+XG5cbiAgICA8c2VjdGlvbiBjbGFzcz1cImJnLXdoaXRlIHJvdW5kZWQtbGcgcC04IG1iLTggc2hhZG93LXNtXCI+XG4gICAgICA8aDIgY2xhc3M9XCJ0ZXh0LTJ4bCBmb250LWJvbGQgdGV4dC1ncmF5LTgwMCBtYi01IHBiLTMgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+RGVtbyB0cuG7sWMgdGnhur9wPC9oMj5cbiAgICAgIDxkaXY+XG4gICAgICAgIDxwIGNsYXNzPVwibWItNFwiPlThuqNpIGzDqm4gaMOsbmgg4bqjbmggdsOgIGNo4buJbmggc+G7rWEgbmdheSB0csOqbiB0csOsbmggZHV54buHdDo8L3A+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJmbGV4IGZsZXgtd3JhcCBpdGVtcy1jZW50ZXIgZ2FwLTQgbWItOFwiPlxuICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgdHlwZT1cImZpbGVcIlxuICAgICAgICAgICAgI2ltYWdlRmlsZUlucHV0XG4gICAgICAgICAgICBhY2NlcHQ9XCJpbWFnZS8qXCJcbiAgICAgICAgICAgIGNsYXNzPVwiYm9yZGVyIGJvcmRlci1ncmF5LTMwMCByb3VuZGVkIHB4LTMgcHktMlwiXG4gICAgICAgICAgICAoY2hhbmdlKT1cIm9uRmlsZVNlbGVjdGVkKCRldmVudClcIiAvPlxuICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b25cbiAgICAgICAgICAgIGxhYmVsPVwiVOG6o2kgbMOqbiB2w6AgY2jhu4luaCBz4butYVwiXG4gICAgICAgICAgICAoY2xpY2spPVwidXBsb2FkQW5kRWRpdCgpXCI+PC9saWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b24+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIEBpZiAoZWRpdGVkSW1hZ2VVcmwpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibXQtOCBwLTYgYmctZ3JheS01MCByb3VuZGVkLWxnXCI+XG4gICAgICAgICAgICA8aDMgY2xhc3M9XCJ0ZXh0LXhsIGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMCBtYi00XCI+S+G6v3QgcXXhuqM8L2gzPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1heC13LXhsIG14LWF1dG8gbWItNCBib3JkZXIgYm9yZGVyLWdyYXktMjAwIHJvdW5kZWQtbGcgb3ZlcmZsb3ctaGlkZGVuIHNoYWRvdy1tZFwiPlxuICAgICAgICAgICAgICA8aW1nXG4gICAgICAgICAgICAgICAgW3NyY109XCJlZGl0ZWRJbWFnZVVybFwiXG4gICAgICAgICAgICAgICAgYWx0PVwiSMOsbmgg4bqjbmggxJHDoyBjaOG7iW5oIHPhu61hXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cInctZnVsbCBoLWF1dG9cIiAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBqdXN0aWZ5LWNlbnRlclwiPlxuICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uXG4gICAgICAgICAgICAgICAgbGFiZWw9XCJU4bqjaSB4deG7kW5nIGjDrG5oIOG6o25oXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwiZG93bmxvYWRJbWFnZSgpXCI+PC9saWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgPC9zZWN0aW9uPlxuXG4gICAgQGlmIChzaG93RWRpdG9yKSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiZml4ZWQgaW5zZXQtMCB6LTUwXCI+XG4gICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtaW1hZ2VfZWRpdG9yXG4gICAgICAgICAgWyhpbWdTcmMpXT1cImltYWdlU291cmNlXCJcbiAgICAgICAgICBbbmFtZUZpbGVdPVwiaW1hZ2VOYW1lIHx8ICdkZW1vLWltYWdlLmpwZydcIlxuICAgICAgICAgIFttb2RlU2hvd0J1dHRvbl09XCInc2F2ZS1maWxlJ1wiXG4gICAgICAgICAgW2hhc1pvb21dPVwidHJ1ZVwiXG4gICAgICAgICAgKG91dFNhdmVGaWxlKT1cIm9uU2F2ZUltYWdlKCRldmVudClcIlxuICAgICAgICAgIChvdXRDbG9zZSk9XCJvbkNsb3NlRWRpdG9yKCRldmVudClcIlxuICAgICAgICAgIChvdXRGdW5jdGlvbnNDb250cm9sKT1cImhhbmRsZUZ1bmN0aW9uQ29udHJvbCgkZXZlbnQpXCIgLz5cbiAgICAgIDwvZGl2PlxuICAgIH1cblxuICAgIDxzZWN0aW9uIGNsYXNzPVwiYmctd2hpdGUgcm91bmRlZC1sZyBwLTggbWItOCBzaGFkb3ctc21cIj5cbiAgICAgIDxoMiBjbGFzcz1cInRleHQtMnhsIGZvbnQtYm9sZCB0ZXh0LWdyYXktODAwIG1iLTUgcGItMyBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj5Dw6FjaCBz4butIGThu6VuZzwvaDI+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJtYi04XCI+XG4gICAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTRcIj5Dw6FjaCAxOiBT4butIGThu6VuZyBmaWxlIEhUTUwgcmnDqm5nIGJp4buHdDwvaDM+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImdyaWQgZ3JpZC1jb2xzLTEgbWQ6Z3JpZC1jb2xzLTIgZ2FwLTYgbWItNFwiPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8aDQgY2xhc3M9XCJmb250LXNlbWlib2xkIG1iLTIgdGV4dC1ncmF5LTcwMFwiPkhUTUwgKGV4YW1wbGUuY29tcG9uZW50Lmh0bWwpPC9oND5cbiAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJiZy1ncmF5LTEwMCBwLTQgcm91bmRlZC1sZyBvdmVyZmxvdy14LWF1dG8gdGV4dC1zbVwiPjxjb2RlPiZsdDtsaWJzX3VpLWNvbXBvbmVudHMtaW1hZ2VfZWRpdG9yXG4gIFsoaW1nU3JjKV09XCJpbWFnZVNvdXJjZVwiXG4gIFtuYW1lRmlsZV09XCInaW1hZ2UuanBnJ1wiXG4gIFttb2RlU2hvd0J1dHRvbl09XCInc2F2ZS1maWxlJ1wiXG4gIChvdXRTYXZlRmlsZSk9XCJvblNhdmVGaWxlKCRldmVudClcIlxuICAob3V0Q2xvc2UpPVwib25DbG9zZSgkZXZlbnQpXCImZ3Q7XG4mbHQ7L2xpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3ImZ3Q7PC9jb2RlPjwvcHJlPlxuICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgIDxoNCBjbGFzcz1cImZvbnQtc2VtaWJvbGQgbWItMiB0ZXh0LWdyYXktNzAwXCI+VHlwZVNjcmlwdCAoZXhhbXBsZS5jb21wb25lbnQudHMpPC9oND5cbiAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJiZy1ncmF5LTEwMCBwLTQgcm91bmRlZC1sZyBvdmVyZmxvdy14LWF1dG8gdGV4dC1zbVwiPjxjb2RlPmltcG9ydCAmIzEyMzsgQ29tcG9uZW50ICYjMTI1OyBmcm9tICcmIzY0O2FuZ3VsYXIvY29yZSc7XG5pbXBvcnQgJiMxMjM7IExpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudCAmIzEyNTsgZnJvbSAnJiM2NDtsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJztcblxuJiM2NDtDb21wb25lbnQoJiMxMjM7XG4gIHNlbGVjdG9yOiAnYXBwLWV4YW1wbGUnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcbiAgdGVtcGxhdGVVcmw6ICcuL2V4YW1wbGUuY29tcG9uZW50Lmh0bWwnXG4mIzEyNTspXG5leHBvcnQgY2xhc3MgRXhhbXBsZUNvbXBvbmVudCAmIzEyMztcbiAgaW1hZ2VTb3VyY2UgPSAnaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ltYWdlLmpwZyc7XG5cbiAgb25TYXZlRmlsZShkYXRhOiAmIzEyMztmaWxlOiBCbG9iLCB1cmw6IHN0cmluZywgbW9kZTogc3RyaW5nJiMxMjU7KSAmIzEyMztcbiAgICBjb25zb2xlLmxvZygnRmlsZSDEkcOjIMSRxrDhu6NjIGzGsHU6JywgZGF0YSk7XG4gICYjMTI1O1xuXG4gIG9uQ2xvc2UoZGF0YTogJiMxMjM7aXNDbGlja0J1dHRvbkNsb3NlOiBib29sZWFuJiMxMjU7KSAmIzEyMztcbiAgICBjb25zb2xlLmxvZygnxJDDoyDEkcOzbmcgdHLDrG5oIGNo4buJbmggc+G7rWEg4bqjbmgnKTtcbiAgJiMxMjU7XG4mIzEyNTs8L2NvZGU+PC9wcmU+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJtYi04XCI+XG4gICAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTRcIj5Dw6FjaCAyOiBW4bubaSB0csOsbmggY2jhu4luaCBz4butYSBjw7MgdGjhu4MgxJHDs25nL23hu588L2gzPlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJncmlkIGdyaWQtY29scy0xIG1kOmdyaWQtY29scy0yIGdhcC02IG1iLTRcIj5cbiAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPGg0IGNsYXNzPVwiZm9udC1zZW1pYm9sZCBtYi0yIHRleHQtZ3JheS03MDBcIj5IVE1MICh0b2dnbGUtZWRpdG9yLmNvbXBvbmVudC5odG1sKTwvaDQ+XG4gICAgICAgICAgICA8cHJlIGNsYXNzPVwiYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgb3ZlcmZsb3cteC1hdXRvIHRleHQtc21cIj48Y29kZT4mbHQ7YnV0dG9uIChjbGljayk9XCJvcGVuRWRpdG9yKClcIiBjbGFzcz1cInB4LTQgcHktMiBiZy1ibHVlLTUwMCB0ZXh0LXdoaXRlIHJvdW5kZWRcIiZndDtcbiAgTeG7nyB0csOsbmggY2jhu4luaCBz4butYSDhuqNuaFxuJmx0Oy9idXR0b24mZ3Q7XG5cbiYjNjQ7aWYgKHNob3dFZGl0b3IpICYjMTIzO1xuICAmbHQ7bGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvclxuICAgIFsoaW1nU3JjKV09XCJpbWFnZVNvdXJjZVwiXG4gICAgW25hbWVGaWxlXT1cIidteS1pbWFnZS5qcGcnXCJcbiAgICAob3V0U2F2ZUZpbGUpPVwib25TYXZlRmlsZSgkZXZlbnQpXCJcbiAgICAob3V0Q2xvc2UpPVwib25DbG9zZUVkaXRvcigkZXZlbnQpXCImZ3Q7XG4gICZsdDsvbGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvciZndDtcbiYjMTI1O1xuXG4mIzY0O2lmIChlZGl0ZWRJbWFnZVVybCkgJiMxMjM7XG4gICZsdDtkaXYgY2xhc3M9XCJtdC00XCImZ3Q7XG4gICAgJmx0O2gzIGNsYXNzPVwidGV4dC1sZyBmb250LXNlbWlib2xkXCImZ3Q7SMOsbmgg4bqjbmggxJHDoyBjaOG7iW5oIHPhu61hOiZsdDsvaDMmZ3Q7XG4gICAgJmx0O2ltZyBbc3JjXT1cImVkaXRlZEltYWdlVXJsXCIgYWx0PVwiSMOsbmgg4bqjbmggxJHDoyBjaOG7iW5oIHPhu61hXCIgY2xhc3M9XCJtdC0yIG1heC13LWZ1bGwgaC1hdXRvXCIgLyZndDtcbiAgJmx0Oy9kaXYmZ3Q7XG4mIzEyNTs8L2NvZGU+PC9wcmU+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPGg0IGNsYXNzPVwiZm9udC1zZW1pYm9sZCBtYi0yIHRleHQtZ3JheS03MDBcIj5UeXBlU2NyaXB0ICh0b2dnbGUtZWRpdG9yLmNvbXBvbmVudC50cyk8L2g0PlxuICAgICAgICAgICAgPHByZSBjbGFzcz1cImJnLWdyYXktMTAwIHAtNCByb3VuZGVkLWxnIG92ZXJmbG93LXgtYXV0byB0ZXh0LXNtXCI+PGNvZGU+aW1wb3J0ICYjMTIzOyBDb21wb25lbnQgJiMxMjU7IGZyb20gJyYjNjQ7YW5ndWxhci9jb3JlJztcbmltcG9ydCAmIzEyMzsgTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50ICYjMTI1OyBmcm9tICcmIzY0O2xpYnMtdWkvY29tcG9uZW50cy1pbWFnZS1lZGl0b3InO1xuaW1wb3J0ICYjMTIzOyBJU2F2ZUZpbGUgJiMxMjU7IGZyb20gJyYjNjQ7bGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcic7XG5cbiYjNjQ7Q29tcG9uZW50KCYjMTIzO1xuICBzZWxlY3RvcjogJ2FwcC10b2dnbGUtZWRpdG9yJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0xpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudF0sXG4gIHRlbXBsYXRlVXJsOiAnLi90b2dnbGUtZWRpdG9yLmNvbXBvbmVudC5odG1sJ1xuJiMxMjU7KVxuZXhwb3J0IGNsYXNzIFRvZ2dsZUVkaXRvckNvbXBvbmVudCAmIzEyMztcbiAgaW1hZ2VTb3VyY2UgPSAnaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ltYWdlLmpwZyc7XG4gIHNob3dFZGl0b3IgPSBmYWxzZTtcbiAgZWRpdGVkSW1hZ2VVcmwgPSAnJztcblxuICBvcGVuRWRpdG9yKCkgJiMxMjM7XG4gICAgdGhpcy5zaG93RWRpdG9yID0gdHJ1ZTtcbiAgJiMxMjU7XG5cbiAgb25TYXZlRmlsZShkYXRhOiBJU2F2ZUZpbGUpICYjMTIzO1xuICAgIHRoaXMuZWRpdGVkSW1hZ2VVcmwgPSBkYXRhLnVybDtcbiAgICB0aGlzLnNob3dFZGl0b3IgPSBmYWxzZTtcbiAgICBjb25zb2xlLmxvZygnxJDDoyBsxrB1IGZpbGU6JywgZGF0YS5maWxlKTtcbiAgJiMxMjU7XG5cbiAgb25DbG9zZUVkaXRvcihkYXRhOiAmIzEyMztpc0NsaWNrQnV0dG9uQ2xvc2U6IGJvb2xlYW4mIzEyNTspICYjMTIzO1xuICAgIHRoaXMuc2hvd0VkaXRvciA9IGZhbHNlO1xuICAmIzEyNTtcbiYjMTI1OzwvY29kZT48L3ByZT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cIm1iLThcIj5cbiAgICAgICAgPGgzIGNsYXNzPVwidGV4dC14bCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDAgbWItNFwiPkPDoWNoIDM6IFbhu5tpIHThu7cgbOG7hyBraHVuZyBow6xuaCBj4buRIMSR4buLbmg8L2gzPlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJncmlkIGdyaWQtY29scy0xIG1kOmdyaWQtY29scy0yIGdhcC02IG1iLTRcIj5cbiAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPGg0IGNsYXNzPVwiZm9udC1zZW1pYm9sZCBtYi0yIHRleHQtZ3JheS03MDBcIj5IVE1MIChmaXhlZC1yYXRpby5jb21wb25lbnQuaHRtbCk8L2g0PlxuICAgICAgICAgICAgPHByZSBjbGFzcz1cImJnLWdyYXktMTAwIHAtNCByb3VuZGVkLWxnIG92ZXJmbG93LXgtYXV0byB0ZXh0LXNtXCI+PGNvZGU+Jmx0O2xpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3JcbiAgWyhpbWdTcmMpXT1cImltYWdlU291cmNlXCJcbiAgW2FzcGVjdFJhdGlvXT1cImFzcGVjdFJhdGlvXCJcbiAgW3JlcXVpcmVkQ3JvcEZvbGxvd1JhdGlvXT1cInRydWVcIlxuICAob3V0U2F2ZUZpbGUpPVwib25TYXZlRmlsZSgkZXZlbnQpXCImZ3Q7XG4mbHQ7L2xpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3ImZ3Q7PC9jb2RlPjwvcHJlPlxuICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgIDxoNCBjbGFzcz1cImZvbnQtc2VtaWJvbGQgbWItMiB0ZXh0LWdyYXktNzAwXCI+VHlwZVNjcmlwdCAoZml4ZWQtcmF0aW8uY29tcG9uZW50LnRzKTwvaDQ+XG4gICAgICAgICAgICA8cHJlIGNsYXNzPVwiYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgb3ZlcmZsb3cteC1hdXRvIHRleHQtc21cIj48Y29kZT5pbXBvcnQgJiMxMjM7IENvbXBvbmVudCAmIzEyNTsgZnJvbSAnJiM2NDthbmd1bGFyL2NvcmUnO1xuaW1wb3J0ICYjMTIzOyBMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnQgJiMxMjU7IGZyb20gJyYjNjQ7bGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcic7XG5pbXBvcnQgJiMxMjM7IElBc3BlY3RSYXRpbyAmIzEyNTsgZnJvbSAnJiM2NDtsaWJzLXVpL2ludGVyZmFjZXMtdHlwZXMnO1xuXG4mIzY0O0NvbXBvbmVudCgmIzEyMztcbiAgc2VsZWN0b3I6ICdhcHAtZml4ZWQtcmF0aW8nLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcbiAgdGVtcGxhdGVVcmw6ICcuL2ZpeGVkLXJhdGlvLmNvbXBvbmVudC5odG1sJ1xuJiMxMjU7KVxuZXhwb3J0IGNsYXNzIEZpeGVkUmF0aW9Db21wb25lbnQgJiMxMjM7XG4gIGltYWdlU291cmNlID0gJ2h0dHBzOi8vZXhhbXBsZS5jb20vcGF0aC90by9pbWFnZS5qcGcnO1xuICBhc3BlY3RSYXRpbzogSUFzcGVjdFJhdGlvID0gJiMxMjM7XG4gICAga2V5OiAnMToxJyxcbiAgICB2YWx1ZTogMVxuICAmIzEyNTs7XG5cbiAgb25TYXZlRmlsZShkYXRhOiBhbnkpICYjMTIzO1xuICAgIGNvbnNvbGUubG9nKCfEkMOjIGzGsHUgaMOsbmgg4bqjbmggduG7m2kgdOG7tyBs4buHIDE6MScpO1xuICAmIzEyNTtcbiYjMTI1OzwvY29kZT48L3ByZT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L3NlY3Rpb24+XG5cbiAgICA8c2VjdGlvbiBjbGFzcz1cImJnLXdoaXRlIHJvdW5kZWQtbGcgcC04IG1iLTggc2hhZG93LXNtXCI+XG4gICAgICA8aDIgY2xhc3M9XCJ0ZXh0LTJ4bCBmb250LWJvbGQgdGV4dC1ncmF5LTgwMCBtYi01IHBiLTMgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+VMOgaSBsaeG7h3UgQVBJPC9oMj5cblxuICAgICAgPGgzIGNsYXNzPVwidGV4dC14bCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDAgbWItNFwiPklucHV0czwvaDM+XG4gICAgICA8ZGl2IGNsYXNzPVwib3ZlcmZsb3cteC1hdXRvIG1iLThcIj5cbiAgICAgICAgPHRhYmxlIGNsYXNzPVwibWluLXctZnVsbCBiZy13aGl0ZSBib3JkZXIgYm9yZGVyLWdyYXktMjAwXCI+XG4gICAgICAgICAgPHRoZWFkPlxuICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJweS0zIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwIGJnLWdyYXktMTAwIHRleHQtbGVmdCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDBcIj5Uw6puPC90aD5cbiAgICAgICAgICAgICAgPHRoIGNsYXNzPVwicHktMyBweC00IGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMCBiZy1ncmF5LTEwMCB0ZXh0LWxlZnQgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwXCI+S2nhu4N1IGThu68gbGnhu4d1PC90aD5cbiAgICAgICAgICAgICAgPHRoIGNsYXNzPVwicHktMyBweC00IGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMCBiZy1ncmF5LTEwMCB0ZXh0LWxlZnQgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwXCI+TeG6t2MgxJHhu4tuaDwvdGg+XG4gICAgICAgICAgICAgIDx0aCBjbGFzcz1cInB5LTMgcHgtNCBib3JkZXItYiBib3JkZXItZ3JheS0yMDAgYmctZ3JheS0xMDAgdGV4dC1sZWZ0IGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMFwiPk3DtCB04bqjPC90aD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC90aGVhZD5cbiAgICAgICAgICA8dGJvZHk+XG4gICAgICAgICAgICBAZm9yIChpbnB1dCBvZiBpbnB1dHNEb2M7IHRyYWNrIGlucHV0Lm5hbWUpIHtcbiAgICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cInB5LTIgcHgtNCBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj5cbiAgICAgICAgICAgICAgICAgIDxjb2RlIGNsYXNzPVwidGV4dC1zbSBiZy1ncmF5LTEwMCBweC0xLjUgcHktMC41IHJvdW5kZWRcIj57eyBpbnB1dC5uYW1lIH19PC9jb2RlPlxuICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwicHktMiBweC00IGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiPlxuICAgICAgICAgICAgICAgICAgPGNvZGUgY2xhc3M9XCJ0ZXh0LXNtIGJnLWdyYXktMTAwIHB4LTEuNSBweS0wLjUgcm91bmRlZFwiPnt7IGlucHV0LnR5cGUgfX08L2NvZGU+XG4gICAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+e3sgaW5wdXQuZGVmYXVsdCB9fTwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwicHktMiBweC00IGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiPnt7IGlucHV0LmRlc2NyaXB0aW9uIH19PC90ZD5cbiAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L3Rib2R5PlxuICAgICAgICA8L3RhYmxlPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTRcIj5PdXRwdXRzPC9oMz5cbiAgICAgIDxkaXYgY2xhc3M9XCJvdmVyZmxvdy14LWF1dG8gbWItOFwiPlxuICAgICAgICA8dGFibGUgY2xhc3M9XCJtaW4tdy1mdWxsIGJnLXdoaXRlIGJvcmRlciBib3JkZXItZ3JheS0yMDBcIj5cbiAgICAgICAgICA8dGhlYWQ+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0aCBjbGFzcz1cInB5LTMgcHgtNCBib3JkZXItYiBib3JkZXItZ3JheS0yMDAgYmctZ3JheS0xMDAgdGV4dC1sZWZ0IGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMFwiPlTDqm48L3RoPlxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJweS0zIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwIGJnLWdyYXktMTAwIHRleHQtbGVmdCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDBcIj5LaeG7g3UgZOG7ryBsaeG7h3U8L3RoPlxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJweS0zIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwIGJnLWdyYXktMTAwIHRleHQtbGVmdCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDBcIj5Nw7QgdOG6ozwvdGg+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvdGhlYWQ+XG4gICAgICAgICAgPHRib2R5PlxuICAgICAgICAgICAgQGZvciAob3V0cHV0IG9mIG91dHB1dHNEb2M7IHRyYWNrIG91dHB1dC5uYW1lKSB7XG4gICAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+XG4gICAgICAgICAgICAgICAgICA8Y29kZSBjbGFzcz1cInRleHQtc20gYmctZ3JheS0xMDAgcHgtMS41IHB5LTAuNSByb3VuZGVkXCI+e3sgb3V0cHV0Lm5hbWUgfX08L2NvZGU+XG4gICAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+XG4gICAgICAgICAgICAgICAgICA8Y29kZSBjbGFzcz1cInRleHQtc20gYmctZ3JheS0xMDAgcHgtMS41IHB5LTAuNSByb3VuZGVkXCI+e3sgb3V0cHV0LnR5cGUgfX08L2NvZGU+XG4gICAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+e3sgb3V0cHV0LmRlc2NyaXB0aW9uIH19PC90ZD5cbiAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L3Rib2R5PlxuICAgICAgICA8L3RhYmxlPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTRcIj5JbnRlcmZhY2VzPC9oMz5cbiAgICAgIDxkaXYgY2xhc3M9XCJzcGFjZS15LTZcIj5cbiAgICAgICAgQGZvciAoaW50ZXJmYWNlSXRlbSBvZiBpbnRlcmZhY2VzRG9jOyB0cmFjayBpbnRlcmZhY2VJdGVtLm5hbWUpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmctZ3JheS01MCBwLTYgcm91bmRlZC1sZ1wiPlxuICAgICAgICAgICAgPGg0IGNsYXNzPVwidGV4dC1sZyBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDAgbWItM1wiPnt7IGludGVyZmFjZUl0ZW0ubmFtZSB9fTwvaDQ+XG4gICAgICAgICAgICA8cHJlIGNsYXNzPVwiYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgb3ZlcmZsb3cteC1hdXRvIHRleHQtc20gbWItM1wiPjxjb2RlPnt7IGludGVyZmFjZUl0ZW0uY29kZSB9fTwvY29kZT48L3ByZT5cbiAgICAgICAgICAgIDxwIGNsYXNzPVwidGV4dC1ncmF5LTYwMFwiPnt7IGludGVyZmFjZUl0ZW0uZGVzY3JpcHRpb24gfX08L3A+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuICAgIDwvc2VjdGlvbj5cblxuICAgIDxzZWN0aW9uIGNsYXNzPVwiYmctd2hpdGUgcm91bmRlZC1sZyBwLTggbWItOCBzaGFkb3ctc21cIj5cbiAgICAgIDxoMiBjbGFzcz1cInRleHQtMnhsIGZvbnQtYm9sZCB0ZXh0LWdyYXktODAwIG1iLTUgcGItMyBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj5Uw61uaCBuxINuZzwvaDI+XG4gICAgICA8dWwgY2xhc3M9XCJzcGFjZS15LTZcIj5cbiAgICAgICAgQGZvciAoZmVhdHVyZSBvZiBmZWF0dXJlczsgdHJhY2sgZmVhdHVyZS5pZCkge1xuICAgICAgICAgIDxsaSBjbGFzcz1cImZsZXggaXRlbXMtc3RhcnRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC0yeGwgdGV4dC1ibHVlLTUwMFwiPnt7IGZlYXR1cmUuaWNvbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgIDxoMyBjbGFzcz1cInRleHQtbGcgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTFcIj57eyBmZWF0dXJlLnRpdGxlIH19PC9oMz5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJ0ZXh0LWdyYXktNjAwXCI+e3sgZmVhdHVyZS5kZXNjcmlwdGlvbiB9fTwvcD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvbGk+XG4gICAgICAgIH1cbiAgICAgIDwvdWw+XG4gICAgPC9zZWN0aW9uPlxuICA8L21haW4+XG48L2Rpdj5cbiJdfQ==
|