@libs-ui/components-image-editor 0.2.30-6.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 +254 -0
- package/defines/image-editor.define.d.ts +16 -0
- package/demo/image-editor-demo.component.d.ts +48 -0
- package/esm2022/defines/image-editor.define.mjs +89 -0
- package/esm2022/demo/image-editor-demo.component.mjs +154 -0
- package/esm2022/image-editor.component.mjs +781 -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 +125 -0
- package/fesm2022/libs-ui-components-image-editor.mjs +1141 -0
- package/fesm2022/libs-ui-components-image-editor.mjs.map +1 -0
- package/image-editor.component.d.ts +117 -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,154 @@
|
|
|
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.writeText(text).then(() => {
|
|
97
|
+
alert('Đã sao chép vào clipboard');
|
|
98
|
+
}).catch(err => {
|
|
99
|
+
console.error('Không thể sao chép: ', err);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
onFileSelected(event) {
|
|
103
|
+
const input = event.target;
|
|
104
|
+
if (input.files && input.files.length > 0) {
|
|
105
|
+
this.selectedFile = input.files[0];
|
|
106
|
+
this.imageName = this.selectedFile.name;
|
|
107
|
+
console.log('File selected:', this.selectedFile.name);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
uploadAndEdit() {
|
|
111
|
+
if (!this.selectedFile) {
|
|
112
|
+
alert('Vui lòng chọn một file hình ảnh trước');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const reader = new FileReader();
|
|
116
|
+
reader.onload = (e) => {
|
|
117
|
+
if (e.target?.result) {
|
|
118
|
+
this.imageSource = e.target.result;
|
|
119
|
+
this.showEditor = true;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
reader.readAsDataURL(this.selectedFile);
|
|
123
|
+
}
|
|
124
|
+
onSaveImage(data) {
|
|
125
|
+
console.log('Image saved:', data);
|
|
126
|
+
this.editedImageUrl = data.url;
|
|
127
|
+
this.showEditor = false;
|
|
128
|
+
}
|
|
129
|
+
onCloseEditor(data) {
|
|
130
|
+
console.log('Editor closed:', data);
|
|
131
|
+
this.showEditor = false;
|
|
132
|
+
}
|
|
133
|
+
downloadImage() {
|
|
134
|
+
if (this.editedImageUrl) {
|
|
135
|
+
const link = document.createElement('a');
|
|
136
|
+
link.href = this.editedImageUrl;
|
|
137
|
+
link.download = this.imageName || 'edited-image.jpg';
|
|
138
|
+
link.click();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsImageEditorDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
142
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", 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> l\u00E0 m\u1ED9t\n 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\n 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><span class=\"font-semibold\">Angular</span>: 18.0.0 tr\u1EDF l\u00EAn</li>\n <li><span class=\"font-semibold\">Tailwind CSS</span>: 3.3.0 tr\u1EDF l\u00EAn</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 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 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 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 label=\"T\u1EA3i l\u00EAn v\u00E0 ch\u1EC9nh s\u1EEDa\"\n (click)=\"uploadAndEdit()\">\n </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 [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 label=\"T\u1EA3i xu\u1ED1ng h\u00ECnh \u1EA3nh\"\n (click)=\"downloadImage()\">\n </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 [(imgSrc)]=\"imageSource\"\n [nameFile]=\"imageName || 'demo-image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n [hasZoom]=\"true\"\n (outSaveFile)=\"onSaveImage($event)\"\n (outClose)=\"onCloseEditor($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\n li\u1EC7u\n </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\n </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\n </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\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.type }}</code></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\n li\u1EC7u\n </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\n </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\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.type }}</code></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\n 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"] }] });
|
|
143
|
+
}
|
|
144
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsImageEditorDemoComponent, decorators: [{
|
|
145
|
+
type: Component,
|
|
146
|
+
args: [{ selector: 'lib-image-editor-demo', standalone: true, imports: [
|
|
147
|
+
LibsUiComponentsButtonsButtonComponent,
|
|
148
|
+
LibsUiComponentsImageEditorComponent
|
|
149
|
+
], 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> l\u00E0 m\u1ED9t\n 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\n 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><span class=\"font-semibold\">Angular</span>: 18.0.0 tr\u1EDF l\u00EAn</li>\n <li><span class=\"font-semibold\">Tailwind CSS</span>: 3.3.0 tr\u1EDF l\u00EAn</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 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 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 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 label=\"T\u1EA3i l\u00EAn v\u00E0 ch\u1EC9nh s\u1EEDa\"\n (click)=\"uploadAndEdit()\">\n </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 [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 label=\"T\u1EA3i xu\u1ED1ng h\u00ECnh \u1EA3nh\"\n (click)=\"downloadImage()\">\n </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 [(imgSrc)]=\"imageSource\"\n [nameFile]=\"imageName || 'demo-image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n [hasZoom]=\"true\"\n (outSaveFile)=\"onSaveImage($event)\"\n (outClose)=\"onCloseEditor($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\n li\u1EC7u\n </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\n </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\n </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\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.type }}</code></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\n li\u1EC7u\n </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\n </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\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.type }}</code></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\n 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"] }]
|
|
150
|
+
}], propDecorators: { imageFileInput: [{
|
|
151
|
+
type: ViewChild,
|
|
152
|
+
args: ['imageFileInput']
|
|
153
|
+
}] } });
|
|
154
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtZWRpdG9yLWRlbW8uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy11aS9jb21wb25lbnRzL2ltYWdlLWVkaXRvci9zcmMvZGVtby9pbWFnZS1lZGl0b3ItZGVtby5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9saWJzLXVpL2NvbXBvbmVudHMvaW1hZ2UtZWRpdG9yL3NyYy9kZW1vL2ltYWdlLWVkaXRvci1kZW1vLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNqRSxPQUFPLEVBQUUsc0NBQXNDLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUM1RixPQUFPLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQzs7QUFhakYsTUFBTSxPQUFPLHdDQUF3QztJQUN0QixjQUFjLENBQWdDO0lBRTNFLFdBQVcsR0FBRyxFQUFFLENBQUM7SUFDakIsVUFBVSxHQUFHLEtBQUssQ0FBQztJQUNuQixjQUFjLEdBQUcsRUFBRSxDQUFDO0lBQ3BCLFlBQVksR0FBZ0IsSUFBSSxDQUFDO0lBQ2pDLFNBQVMsR0FBRyxFQUFFLENBQUM7SUFFZiwyQ0FBMkM7SUFDM0MsU0FBUyxHQUFHO1FBQ1YsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsa0RBQWtELEVBQUU7UUFDeEgsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsc0JBQXNCLEVBQUU7UUFDeEYsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxXQUFX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c0JBQTFDLFNBQVM7dUJBQUMsZ0JBQWdCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IExpYnNVaUNvbXBvbmVudHNCdXR0b25zQnV0dG9uQ29tcG9uZW50IH0gZnJvbSAnQGxpYnMtdWkvY29tcG9uZW50cy1idXR0b25zLWJ1dHRvbic7XG5pbXBvcnQgeyBMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnQgfSBmcm9tICcuLi9pbWFnZS1lZGl0b3IuY29tcG9uZW50JztcbmltcG9ydCB7IElTYXZlRmlsZSB9IGZyb20gJy4uL2ludGVyZmFjZXMvaW1hZ2UtZWRpdG9yLmludGVyZmFjZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1pbWFnZS1lZGl0b3ItZGVtbycsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBMaWJzVWlDb21wb25lbnRzQnV0dG9uc0J1dHRvbkNvbXBvbmVudCxcbiAgICBMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnRcbiAgXSxcbiAgdGVtcGxhdGVVcmw6ICcuL2ltYWdlLWVkaXRvci1kZW1vLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmw6ICcuL2ltYWdlLWVkaXRvci1kZW1vLmNvbXBvbmVudC5zY3NzJ1xufSlcbmV4cG9ydCBjbGFzcyBMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JEZW1vQ29tcG9uZW50IHtcbiAgQFZpZXdDaGlsZCgnaW1hZ2VGaWxlSW5wdXQnKSBpbWFnZUZpbGVJbnB1dCE6IEVsZW1lbnRSZWY8SFRNTElucHV0RWxlbWVudD47XG5cbiAgaW1hZ2VTb3VyY2UgPSAnJztcbiAgc2hvd0VkaXRvciA9IGZhbHNlO1xuICBlZGl0ZWRJbWFnZVVybCA9ICcnO1xuICBzZWxlY3RlZEZpbGU6IEZpbGUgfCBudWxsID0gbnVsbDtcbiAgaW1hZ2VOYW1lID0gJyc7XG5cbiAgLy8gRG9jdW1lbnRhdGlvbiBkYXRhIGFzIHJlZ3VsYXIgcHJvcGVydGllc1xuICBpbnB1dHNEb2MgPSBbXG4gICAgeyBuYW1lOiAnaW1nU3JjJywgdHlwZTogJ3N0cmluZycsIGRlZmF1bHQ6ICdC4bqvdCBideG7mWMnLCBkZXNjcmlwdGlvbjogJ8SQxrDhu51uZyBk4bqrbiBob+G6t2MgYmFzZTY0IGPhu6dhIGjDrG5oIOG6o25oIGPhuqduIGNo4buJbmggc+G7rWEnIH0sXG4gICAgeyBuYW1lOiAnb3JpZ2luVXJsJywgdHlwZTogJ3N0cmluZycsIGRlZmF1bHQ6ICctJywgZGVzY3JpcHRpb246ICdVUkwgZ+G7kWMgY+G7p2EgaMOsbmgg4bqjbmgnIH0sXG4gICAgeyBuYW1lOiAnbmFtZUZpbGUnLCB0eXBlOiAnc3RyaW5nJywgZGVmYXVsdDogJy0nLCBkZXNjcmlwdGlvbjogJ1TDqm4gZmlsZSBraGkgbMawdScgfSxcbiAgICB7IG5hbWU6ICdtb2RlU2hvd0J1dHRvbicsIHR5cGU6ICdcXCdzYXZlLWZpbGVcXCcgfCBcXCdzYXZlLWFwaVxcJycsIGRlZmF1bHQ6ICdcXCdzYXZlLWZpbGVcXCcnLCBkZXNjcmlwdGlvbjogJ0No4bq/IMSR4buZIG7DunQgbMawdScgfSxcbiAgICB7IG5hbWU6ICdtaW1ldHlwZScsIHR5cGU6ICdzdHJpbmcnLCBkZWZhdWx0OiAnLScsIGRlc2NyaXB0aW9uOiAnxJDhu4tuaCBk4bqhbmcgY+G7p2EgaMOsbmgg4bqjbmgnIH0sXG4gICAgeyBuYW1lOiAnekluZGV4JywgdHlwZTogJ251bWJlcicsIGRlZmF1bHQ6ICcxMjAwJywgZGVzY3JpcHRpb246ICd6LWluZGV4IGPhu6dhIGNvbXBvbmVudCcgfSxcbiAgICB7IG5hbWU6ICdoYXNab29tJywgdHlwZTogJ2Jvb2xlYW4nLCBkZWZhdWx0OiAnZmFsc2UnLCBkZXNjcmlwdGlvbjogJ0NobyBwaMOpcCBwaMOzbmcgdG8vdGh1IG5o4buPIGjDrG5oIOG6o25oJyB9LFxuICAgIHsgbmFtZTogJ2FzcGVjdFJhdGlvJywgdHlwZTogJ0lBc3BlY3RSYXRpbycsIGRlZmF1bHQ6ICctJywgZGVzY3JpcHRpb246ICdU4bu3IGzhu4cga2h1bmcgaMOsbmggbeG6t2MgxJHhu4tuaCcgfSxcbiAgICB7IG5hbWU6ICdyZXF1aXJlZENyb3BGb2xsb3dSYXRpbycsIHR5cGU6ICdib29sZWFuJywgZGVmYXVsdDogJ2ZhbHNlJywgZGVzY3JpcHRpb246ICdC4bqvdCBideG7mWMgY+G6r3QgdGhlbyB04bu3IGzhu4cgxJHDoyBjaOG7jW4nIH1cbiAgXTtcblxuICBvdXRwdXRzRG9jID0gW1xuICAgIHsgbmFtZTogJ291dENsb3NlJywgdHlwZTogJ3tpc0NsaWNrQnV0dG9uQ2xvc2U6IGJvb2xlYW59JywgZGVzY3JpcHRpb246ICdT4buxIGtp4buHbiBraGkgxJHDs25nIHRyw6xuaCBjaOG7iW5oIHPhu61hJyB9LFxuICAgIHsgbmFtZTogJ291dFNhdmVGaWxlJywgdHlwZTogJ0lTYXZlRmlsZScsIGRlc2NyaXB0aW9uOiAnU+G7sSBraeG7h24ga2hpIGzGsHUgZmlsZScgfSxcbiAgICB7IG5hbWU6ICdvdXRGdW5jdGlvbnNDb250cm9sJywgdHlwZTogJ0lJbWFnZUVkaXRvckZ1bmN0aW9uQ29udHJvbEV2ZW50JywgZGVzY3JpcHRpb246ICdT4buxIGtp4buHbiDEkeG7gyBraeG7g20gc2/DoXQgY8OhYyBjaOG7qWMgbsSDbmcnIH1cbiAgXTtcblxuICBpbnRlcmZhY2VzRG9jID0gW1xuICAgIHtcbiAgICAgIG5hbWU6ICdJU2F2ZUZpbGUnLFxuICAgICAgY29kZTogJ2V4cG9ydCBpbnRlcmZhY2UgSVNhdmVGaWxlIHtcXG4gIGZpbGU6IEJsb2I7XFxuICB1cmw6IHN0cmluZztcXG4gIG1vZGU6IFxcJ3NhdmUtZmlsZVxcJyB8IFxcJ3NhdmUtYXBpXFwnIHwgXFwnc2F2ZS1hcGktYXMtbmV3LWZpbGVcXCc7XFxufScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0ludGVyZmFjZSDEkeG7i25oIG5naMSpYSBk4buvIGxp4buHdSBraGkgbMawdSBmaWxlLidcbiAgICB9LFxuICAgIHtcbiAgICAgIG5hbWU6ICdJSW1hZ2VFZGl0b3JGdW5jdGlvbkNvbnRyb2xFdmVudCcsXG4gICAgICBjb2RlOiAnZXhwb3J0IGludGVyZmFjZSBJSW1hZ2VFZGl0b3JGdW5jdGlvbkNvbnRyb2xFdmVudCB7XFxuICBjcm9wSW1hZ2U6ICgpID0+IFByb21pc2U8c3RyaW5nPjtcXG4gIHNldExvYWRpbmdTdGF0ZTogKGxvYWRpbmc6IGJvb2xlYW4pID0+IHZvaWQ7XFxufScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0ludGVyZmFjZSDEkeG7i25oIG5naMSpYSBjw6FjIGjDoG0gxJFp4buBdSBraGnhu4NuIGPDsyB0aOG7gyDEkcaw4bujYyBn4buNaSB04burIGLDqm4gbmdvw6BpIGNvbXBvbmVudC4nXG4gICAgfSxcbiAgICB7XG4gICAgICBuYW1lOiAnSUFzcGVjdFJhdGlvJyxcbiAgICAgIGNvZGU6ICdleHBvcnQgaW50ZXJmYWNlIElBc3BlY3RSYXRpbyB7XFxuICBrZXk6IHN0cmluZztcXG4gIHZhbHVlOiBudW1iZXI7XFxufScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0ludGVyZmFjZSDEkeG7i25oIG5naMSpYSB04bu3IGzhu4cga2h1bmcgaMOsbmguJ1xuICAgIH1cbiAgXTtcblxuICBmZWF0dXJlcyA9IFtcbiAgICB7XG4gICAgICBpZDogMSxcbiAgICAgIGljb246ICfinILvuI8nLFxuICAgICAgdGl0bGU6ICdD4bqvdCDhuqNuaCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ0Phuq90IGjDrG5oIOG6o25oIHRoZW8ga2h1IHbhu7FjIHTDuXkgY2jhu4luaCBob+G6t2MgZOG7sWEgdHLDqm4gdOG7tyBs4buHIMSR4buLbmggdHLGsOG7m2MgKDE6MSwgNDozLCAxNjo5LCB2LnYuKS4nXG4gICAgfSxcbiAgICB7XG4gICAgICBpZDogMixcbiAgICAgIGljb246ICfwn5SEJyxcbiAgICAgIHRpdGxlOiAnWG9heSB2w6AgbOG6rXQnLFxuICAgICAgZGVzY3JpcHRpb246ICdYb2F5IGjDrG5oIOG6o25oIHRoZW8gY8OhYyBnw7NjIGtow6FjIG5oYXUgaG/hurdjIGzhuq10IHRoZW8gY2hp4buBdSBuZ2FuZy9k4buNYy4nXG4gICAgfSxcbiAgICB7XG4gICAgICBpZDogMyxcbiAgICAgIGljb246ICfwn5OPJyxcbiAgICAgIHRpdGxlOiAnVGhheSDEkeG7lWkga8OtY2ggdGjGsOG7m2MnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGF5IMSR4buVaSBrw61jaCB0aMaw4bubYyBow6xuaCDhuqNuaCB0aGVvIHThu7cgbOG7hyBwaOG6p24gdHLEg20gaG/hurdjIGvDrWNoIHRoxrDhu5tjIGPhu6UgdGjhu4MuJ1xuICAgIH0sXG4gICAge1xuICAgICAgaWQ6IDQsXG4gICAgICBpY29uOiAn8J+SvicsXG4gICAgICB0aXRsZTogJ05oaeG7gXUgY2jhur8gxJHhu5kgbMawdScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0jhu5cgdHLhu6Mgbmhp4buBdSBjaOG6vyDEkeG7mSBsxrB1OiB04bqjaSB4deG7kW5nIHRy4buxYyB0aeG6v3AgaG/hurdjIGfhu61pIMSR4bq/biBBUEkuJ1xuICAgIH0sXG4gICAge1xuICAgICAgaWQ6IDUsXG4gICAgICBpY29uOiAn8J+UjScsXG4gICAgICB0aXRsZTogJ1Bow7NuZyB0by90aHUgbmjhu48nLFxuICAgICAgZGVzY3JpcHRpb246ICdUw61uaCBuxINuZyBwaMOzbmcgdG8vdGh1IG5o4buPIMSR4buDIHhlbSBjaGkgdGnhur90IGjDrG5oIOG6o25oIGtoaSBj4bqnbiB0aGnhur90LidcbiAgICB9XG4gIF07XG5cbiAgY29kZUV4YW1wbGVzID0gW1xuICAgIHtcbiAgICAgIGlkOiAxLFxuICAgICAgdGl0bGU6ICdT4butIGThu6VuZyBjxqEgYuG6o24nLFxuICAgICAgY29kZTogYGltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xcbmltcG9ydCB7IExpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudCB9IGZyb20gJ0BsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJztcXG5cXG5AQ29tcG9uZW50KHtcXG4gIHNlbGVjdG9yOiAnYXBwLWV4YW1wbGUnLFxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcXG4gIGltcG9ydHM6IFtMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnRdLFxcbiAgdGVtcGxhdGU6IFxcYFxcbiAgICA8bGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvclxcbiAgICAgIFsoaW1nU3JjKV09XCJpbWFnZVNvdXJjZVwiXFxuICAgICAgW21vZGVTaG93QnV0dG9uXT1cIidzYXZlLWZpbGUnXCJcXG4gICAgICBbbmFtZUZpbGVdPVwiJ2ltYWdlLmpwZydcIlxcbiAgICAgIChvdXRTYXZlRmlsZSk9XCJvblNhdmVGaWxlKCRldmVudClcIlxcbiAgICAgIChvdXRDbG9zZSk9XCJvbkNsb3NlKCRldmVudClcIj5cXG4gICAgPC9saWJzX3VpLWNvbXBvbmVudHMtaW1hZ2VfZWRpdG9yPlxcbiAgXFxgXFxufSlcXG5leHBvcnQgY2xhc3MgRXhhbXBsZUNvbXBvbmVudCB7XFxuICBpbWFnZVNvdXJjZSA9ICdodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG8vaW1hZ2UuanBnJztcXG5cXG4gIG9uU2F2ZUZpbGUoZGF0YToge2ZpbGU6IEJsb2IsIHVybDogc3RyaW5nLCBtb2RlOiBzdHJpbmd9KSB7XFxuICAgIGNvbnNvbGUubG9nKCdGaWxlIMSRw6MgxJHGsOG7o2MgbMawdTonLCBkYXRhKTtcXG4gIH1cXG5cXG4gIG9uQ2xvc2UoZGF0YToge2lzQ2xpY2tCdXR0b25DbG9zZTogYm9vbGVhbn0pIHtcXG4gICAgY29uc29sZS5sb2coJ8SQw6MgxJHDs25nIHRyw6xuaCBjaOG7iW5oIHPhu61hIOG6o25oJyk7XFxuICB9XFxufWBcbiAgICB9LFxuICAgIHtcbiAgICAgIGlkOiAyLFxuICAgICAgdGl0bGU6ICdT4butIGThu6VuZyB24bubaSB04bu3IGzhu4cgY+G7kSDEkeG7i25oJyxcbiAgICAgIGNvZGU6IGBpbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcXG5pbXBvcnQgeyBMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnQgfSBmcm9tICdAbGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcic7XFxuaW1wb3J0IHsgSUFzcGVjdFJhdGlvIH0gZnJvbSAnQGxpYnMtdWkvaW50ZXJmYWNlcy10eXBlcyc7XFxuXFxuQENvbXBvbmVudCh7XFxuICBzZWxlY3RvcjogJ2FwcC1leGFtcGxlJyxcXG4gIHN0YW5kYWxvbmU6IHRydWUsXFxuICBpbXBvcnRzOiBbTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcXG4gIHRlbXBsYXRlOiBcXGBcXG4gICAgPGxpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3JcXG4gICAgICBbKGltZ1NyYyldPVwiaW1hZ2VTb3VyY2VcIlxcbiAgICAgIFthc3BlY3RSYXRpb109XCJhc3BlY3RSYXRpb1wiXFxuICAgICAgW3JlcXVpcmVkQ3JvcEZvbGxvd1JhdGlvXT1cInRydWVcIlxcbiAgICAgIChvdXRTYXZlRmlsZSk9XCJvblNhdmVGaWxlKCRldmVudClcIj5cXG4gICAgPC9saWJzX3VpLWNvbXBvbmVudHMtaW1hZ2VfZWRpdG9yPlxcbiAgXFxgXFxufSlcXG5leHBvcnQgY2xhc3MgRXhhbXBsZUNvbXBvbmVudCB7XFxuICBpbWFnZVNvdXJjZSA9ICdodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG8vaW1hZ2UuanBnJztcXG4gIGFzcGVjdFJhdGlvOiBJQXNwZWN0UmF0aW8gPSB7XFxuICAgIGtleTogJzE6MScsXFxuICAgIHZhbHVlOiAxXFxuICB9O1xcblxcbiAgb25TYXZlRmlsZShkYXRhOiBhbnkpIHtcXG4gICAgY29uc29sZS5sb2coJ8SQw6MgbMawdSBow6xuaCDhuqNuaCB24bubaSB04bu3IGzhu4cgMToxJyk7XFxuICB9XFxufWBcbiAgICB9LFxuICAgIHtcbiAgICAgIGlkOiAzLFxuICAgICAgdGl0bGU6ICdT4butIGThu6VuZyB24bubaSBwaOG6p24gxJFp4buBdSBraGnhu4NuIGLDqm4gbmdvw6BpJyxcbiAgICAgIGNvZGU6IGBpbXBvcnQgeyBDb21wb25lbnQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xcbmltcG9ydCB7IExpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudCwgSUltYWdlRWRpdG9yRnVuY3Rpb25Db250cm9sRXZlbnQgfSBmcm9tICdAbGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcic7XFxuXFxuQENvbXBvbmVudCh7XFxuICBzZWxlY3RvcjogJ2FwcC1leGFtcGxlJyxcXG4gIHN0YW5kYWxvbmU6IHRydWUsXFxuICBpbXBvcnRzOiBbTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcXG4gIHRlbXBsYXRlOiBcXGBcXG4gICAgPGJ1dHRvbiAoY2xpY2spPVwiY3JvcEFuZFNhdmUoKVwiPkPhuq90IHbDoCBsxrB1IG5nYXk8L2J1dHRvbj5cXG4gICAgPGxpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3JcXG4gICAgICBbKGltZ1NyYyldPVwiaW1hZ2VTb3VyY2VcIlxcbiAgICAgIChvdXRGdW5jdGlvbnNDb250cm9sKT1cIm9uRnVuY3Rpb25zQ29udHJvbCgkZXZlbnQpXCI+XFxuICAgIDwvbGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvcj5cXG4gIFxcYFxcbn0pXFxuZXhwb3J0IGNsYXNzIEV4YW1wbGVDb21wb25lbnQge1xcbiAgaW1hZ2VTb3VyY2UgPSAnaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ltYWdlLmpwZyc7XFxuICBlZGl0b3JGdW5jdGlvbnMhOiBJSW1hZ2VFZGl0b3JGdW5jdGlvbkNvbnRyb2xFdmVudDtcXG5cXG4gIG9uRnVuY3Rpb25zQ29udHJvbChldmVudDogSUltYWdlRWRpdG9yRnVuY3Rpb25Db250cm9sRXZlbnQpIHtcXG4gICAgdGhpcy5lZGl0b3JGdW5jdGlvbnMgPSBldmVudDtcXG4gIH1cXG5cXG4gIGFzeW5jIGNyb3BBbmRTYXZlKCkge1xcbiAgICBpZiAodGhpcy5lZGl0b3JGdW5jdGlvbnMpIHtcXG4gICAgICB0aGlzLmVkaXRvckZ1bmN0aW9ucy5zZXRMb2FkaW5nU3RhdGUodHJ1ZSk7XFxuICAgICAgdHJ5IHtcXG4gICAgICAgIGNvbnN0IGRhdGFVcmwgPSBhd2FpdCB0aGlzLmVkaXRvckZ1bmN0aW9ucy5jcm9wSW1hZ2UoKTtcXG4gICAgICAgIGNvbnNvbGUubG9nKCdIw6xuaCDhuqNuaCDEkcOjIMSRxrDhu6NjIGPhuq90OicsIGRhdGFVcmwpO1xcbiAgICAgIH0gZmluYWxseSB7XFxuICAgICAgICB0aGlzLmVkaXRvckZ1bmN0aW9ucy5zZXRMb2FkaW5nU3RhdGUoZmFsc2UpO1xcbiAgICAgIH1cXG4gICAgfVxcbiAgfVxcbn1gXG4gICAgfVxuICBdO1xuXG4gIGNvcHlUb0NsaXBib2FyZCh0ZXh0OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBuYXZpZ2F0b3IuY2xpcGJvYXJkLndyaXRlVGV4dCh0ZXh0KS50aGVuKCgpID0+IHtcbiAgICAgIGFsZXJ0KCfEkMOjIHNhbyBjaMOpcCB2w6BvIGNsaXBib2FyZCcpO1xuICAgIH0pLmNhdGNoKGVyciA9PiB7XG4gICAgICBjb25zb2xlLmVycm9yKCdLaMO0bmcgdGjhu4Mgc2FvIGNow6lwOiAnLCBlcnIpO1xuICAgIH0pO1xuICB9XG5cbiAgb25GaWxlU2VsZWN0ZWQoZXZlbnQ6IEV2ZW50KSB7XG4gICAgY29uc3QgaW5wdXQgPSBldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudDtcbiAgICBpZiAoaW5wdXQuZmlsZXMgJiYgaW5wdXQuZmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5zZWxlY3RlZEZpbGUgPSBpbnB1dC5maWxlc1swXTtcbiAgICAgIHRoaXMuaW1hZ2VOYW1lID0gdGhpcy5zZWxlY3RlZEZpbGUubmFtZTtcbiAgICAgIGNvbnNvbGUubG9nKCdGaWxlIHNlbGVjdGVkOicsIHRoaXMuc2VsZWN0ZWRGaWxlLm5hbWUpO1xuICAgIH1cbiAgfVxuXG4gIHVwbG9hZEFuZEVkaXQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnNlbGVjdGVkRmlsZSkge1xuICAgICAgYWxlcnQoJ1Z1aSBsw7JuZyBjaOG7jW4gbeG7mXQgZmlsZSBow6xuaCDhuqNuaCB0csaw4bubYycpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XG4gICAgcmVhZGVyLm9ubG9hZCA9IChlOiBQcm9ncmVzc0V2ZW50PEZpbGVSZWFkZXI+KSA9PiB7XG4gICAgICBpZiAoZS50YXJnZXQ/LnJlc3VsdCkge1xuICAgICAgICB0aGlzLmltYWdlU291cmNlID0gZS50YXJnZXQucmVzdWx0IGFzIHN0cmluZztcbiAgICAgICAgdGhpcy5zaG93RWRpdG9yID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKHRoaXMuc2VsZWN0ZWRGaWxlKTtcbiAgfVxuXG4gIG9uU2F2ZUltYWdlKGRhdGE6IElTYXZlRmlsZSk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKCdJbWFnZSBzYXZlZDonLCBkYXRhKTtcbiAgICB0aGlzLmVkaXRlZEltYWdlVXJsID0gZGF0YS51cmw7XG4gICAgdGhpcy5zaG93RWRpdG9yID0gZmFsc2U7XG4gIH1cblxuICBvbkNsb3NlRWRpdG9yKGRhdGE6IHsgaXNDbGlja0J1dHRvbkNsb3NlOiBib29sZWFuIH0pOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnRWRpdG9yIGNsb3NlZDonLCBkYXRhKTtcbiAgICB0aGlzLnNob3dFZGl0b3IgPSBmYWxzZTtcbiAgfVxuXG4gIGRvd25sb2FkSW1hZ2UoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZWRpdGVkSW1hZ2VVcmwpIHtcbiAgICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgICBsaW5rLmhyZWYgPSB0aGlzLmVkaXRlZEltYWdlVXJsO1xuICAgICAgbGluay5kb3dubG9hZCA9IHRoaXMuaW1hZ2VOYW1lIHx8ICdlZGl0ZWQtaW1hZ2UuanBnJztcbiAgICAgIGxpbmsuY2xpY2soKTtcbiAgICB9XG4gIH1cbn0gIiwiPGRpdiBjbGFzcz1cIm1heC13LTZ4bCBteC1hdXRvIHAtNSBmb250LXNhbnMgdGV4dC1ncmF5LTgwMFwiPlxuICA8aGVhZGVyIGNsYXNzPVwidGV4dC1jZW50ZXIgcHktMTAgYmctd2hpdGUgcm91bmRlZC1sZyBtYi04IHNoYWRvdy1zbVwiPlxuICAgIDxoMSBjbGFzcz1cInRleHQtNHhsIGZvbnQtYm9sZCB0ZXh0LWdyYXktODAwIG1iLTJcIj5EZW1vIFRyw6xuaCBDaOG7iW5oIFPhu61hIEjDrG5oIOG6om5oPC9oMT5cbiAgICA8cCBjbGFzcz1cInRleHQteGwgdGV4dC1ncmF5LTUwMFwiPlRoxrAgdmnhu4duIGNvbXBvbmVudCBjaG8gQW5ndWxhciDEkeG7gyBjaOG7iW5oIHPhu61hIGjDrG5oIOG6o25oPC9wPlxuICA8L2hlYWRlcj5cblxuICA8bWFpbj5cbiAgICA8c2VjdGlvbiBjbGFzcz1cImJnLXdoaXRlIHJvdW5kZWQtbGcgcC04IG1iLTggc2hhZG93LXNtXCI+XG4gICAgICA8aDIgY2xhc3M9XCJ0ZXh0LTJ4bCBmb250LWJvbGQgdGV4dC1ncmF5LTgwMCBtYi01IHBiLTMgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+R2nhu5tpIHRoaeG7h3U8L2gyPlxuICAgICAgPHA+XG4gICAgICAgIDxjb2RlIGNsYXNzPVwidGV4dC1zbSBiZy1ncmF5LTEwMCBweC0xLjUgcHktMC41IHJvdW5kZWRcIj4mIzY0O2xpYnMtdWkvY29tcG9uZW50cy1pbWFnZS1lZGl0b3I8L2NvZGU+IGzDoCBt4buZdFxuICAgICAgICBjb21wb25lbnQgQW5ndWxhciBt4bqhbmggbeG6vSBjaG8gcGjDqXAgbmfGsOG7nWkgZMO5bmcgdGjhu7FjIGhp4buHbiBjw6FjIHRoYW8gdMOhYyBjaOG7iW5oIHPhu61hIGjDrG5oIOG6o25oIG5oxrAgY+G6r3QsIHRoYXkgxJHhu5VpIGvDrWNoXG4gICAgICAgIHRoxrDhu5tjLCB4b2F5LCBs4bqtdCB2w6Agw6FwIGThu6VuZyB04bu3IGzhu4cgY+G7kSDEkeG7i25oLlxuICAgICAgPC9wPlxuICAgIDwvc2VjdGlvbj5cblxuICAgIDxzZWN0aW9uIGNsYXNzPVwiYmctd2hpdGUgcm91bmRlZC1sZyBwLTggbWItOCBzaGFkb3ctc21cIj5cbiAgICAgIDxoMiBjbGFzcz1cInRleHQtMnhsIGZvbnQtYm9sZCB0ZXh0LWdyYXktODAwIG1iLTUgcGItMyBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj5Dw6BpIMSR4bq3dDwvaDI+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJtYi02XCI+XG4gICAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTNcIj5Zw6p1IGPhuqd1PC9oMz5cbiAgICAgICAgPHVsIGNsYXNzPVwibGlzdC1kaXNjIHBsLTUgc3BhY2UteS0yIHRleHQtZ3JheS02MDBcIj5cbiAgICAgICAgICA8bGk+PHNwYW4gY2xhc3M9XCJmb250LXNlbWlib2xkXCI+QW5ndWxhcjwvc3Bhbj46IDE4LjAuMCB0cuG7nyBsw6puPC9saT5cbiAgICAgICAgICA8bGk+PHNwYW4gY2xhc3M9XCJmb250LXNlbWlib2xkXCI+VGFpbHdpbmQgQ1NTPC9zcGFuPjogMy4zLjAgdHLhu58gbMOqbjwvbGk+XG4gICAgICAgIDwvdWw+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPHAgY2xhc3M9XCJtYi00XCI+xJDhu4MgY8OgaSDEkeG6t3QgdGjGsCB2aeG7h24sIHPhu60gZOG7pW5nIG5wbSBob+G6t2MgeWFybjo8L3A+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJmbGV4IGl0ZW1zLWNlbnRlciBiZy1ncmF5LTEwMCBwLTQgcm91bmRlZC1sZyBtYi02XCI+XG4gICAgICAgIDxwcmUgY2xhc3M9XCJmbGV4LTEgdGV4dC1zbSBvdmVyZmxvdy14LWF1dG9cIj48Y29kZT5ucG0gaW5zdGFsbCAmIzY0O2xpYnMtdWkvY29tcG9uZW50cy1pbWFnZS1lZGl0b3I8L2NvZGU+PC9wcmU+XG4gICAgICAgIDxidXR0b24gY2xhc3M9XCJtbC00IHB4LTMgcHktMSBiZy1ibHVlLTUwMCB0ZXh0LXdoaXRlIHJvdW5kZWQgaG92ZXI6YmctYmx1ZS02MDAgdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICAgIChjbGljayk9XCJjb3B5VG9DbGlwYm9hcmQoJ25wbSBpbnN0YWxsIEBsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJylcIj5cbiAgICAgICAgICBTYW8gY2jDqXBcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPHAgY2xhc3M9XCJtYi00XCI+SG/hurdjIHbhu5tpIHlhcm46PC9wPlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgbWItNlwiPlxuICAgICAgICA8cHJlIGNsYXNzPVwiZmxleC0xIHRleHQtc20gb3ZlcmZsb3cteC1hdXRvXCI+PGNvZGU+eWFybiBhZGQgJiM2NDtsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yPC9jb2RlPjwvcHJlPlxuICAgICAgICA8YnV0dG9uIGNsYXNzPVwibWwtNCBweC0zIHB5LTEgYmctYmx1ZS01MDAgdGV4dC13aGl0ZSByb3VuZGVkIGhvdmVyOmJnLWJsdWUtNjAwIHRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAoY2xpY2spPVwiY29weVRvQ2xpcGJvYXJkKCd5YXJuIGFkZCBAbGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcicpXCI+XG4gICAgICAgICAgU2FvIGNow6lwXG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9zZWN0aW9uPlxuXG4gICAgPHNlY3Rpb24gY2xhc3M9XCJiZy13aGl0ZSByb3VuZGVkLWxnIHAtOCBtYi04IHNoYWRvdy1zbVwiPlxuICAgICAgPGgyIGNsYXNzPVwidGV4dC0yeGwgZm9udC1ib2xkIHRleHQtZ3JheS04MDAgbWItNSBwYi0zIGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiPkRlbW8gdHLhu7FjIHRp4bq/cDwvaDI+XG4gICAgICA8ZGl2PlxuICAgICAgICA8cCBjbGFzcz1cIm1iLTRcIj5U4bqjaSBsw6puIGjDrG5oIOG6o25oIHbDoCBjaOG7iW5oIHPhu61hIG5nYXkgdHLDqm4gdHLDrG5oIGR1eeG7h3Q6PC9wPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBmbGV4LXdyYXAgaXRlbXMtY2VudGVyIGdhcC00IG1iLThcIj5cbiAgICAgICAgICA8aW5wdXQgdHlwZT1cImZpbGVcIlxuICAgICAgICAgICAgI2ltYWdlRmlsZUlucHV0XG4gICAgICAgICAgICBhY2NlcHQ9XCJpbWFnZS8qXCJcbiAgICAgICAgICAgIGNsYXNzPVwiYm9yZGVyIGJvcmRlci1ncmF5LTMwMCByb3VuZGVkIHB4LTMgcHktMlwiXG4gICAgICAgICAgICAoY2hhbmdlKT1cIm9uRmlsZVNlbGVjdGVkKCRldmVudClcIiAvPlxuICAgICAgICAgIDxsaWJzX3VpLWNvbXBvbmVudHMtYnV0dG9ucy1idXR0b24gbGFiZWw9XCJU4bqjaSBsw6puIHbDoCBjaOG7iW5oIHPhu61hXCJcbiAgICAgICAgICAgIChjbGljayk9XCJ1cGxvYWRBbmRFZGl0KClcIj5cbiAgICAgICAgICA8L2xpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvbj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgQGlmIChlZGl0ZWRJbWFnZVVybCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJtdC04IHAtNiBiZy1ncmF5LTUwIHJvdW5kZWQtbGdcIj5cbiAgICAgICAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTRcIj5L4bq/dCBxdeG6ozwvaDM+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibWF4LXcteGwgbXgtYXV0byBtYi00IGJvcmRlciBib3JkZXItZ3JheS0yMDAgcm91bmRlZC1sZyBvdmVyZmxvdy1oaWRkZW4gc2hhZG93LW1kXCI+XG4gICAgICAgICAgICAgIDxpbWcgW3NyY109XCJlZGl0ZWRJbWFnZVVybFwiXG4gICAgICAgICAgICAgICAgYWx0PVwiSMOsbmgg4bqjbmggxJHDoyBjaOG7iW5oIHPhu61hXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cInctZnVsbCBoLWF1dG9cIiAvPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBqdXN0aWZ5LWNlbnRlclwiPlxuICAgICAgICAgICAgICA8bGlic191aS1jb21wb25lbnRzLWJ1dHRvbnMtYnV0dG9uIGxhYmVsPVwiVOG6o2kgeHXhu5FuZyBow6xuaCDhuqNuaFwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImRvd25sb2FkSW1hZ2UoKVwiPlxuICAgICAgICAgICAgICA8L2xpYnNfdWktY29tcG9uZW50cy1idXR0b25zLWJ1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cbiAgICA8L3NlY3Rpb24+XG5cbiAgICBAaWYgKHNob3dFZGl0b3IpIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJmaXhlZCBpbnNldC0wIHotNTBcIj5cbiAgICAgICAgPGxpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3IgWyhpbWdTcmMpXT1cImltYWdlU291cmNlXCJcbiAgICAgICAgICBbbmFtZUZpbGVdPVwiaW1hZ2VOYW1lIHx8ICdkZW1vLWltYWdlLmpwZydcIlxuICAgICAgICAgIFttb2RlU2hvd0J1dHRvbl09XCInc2F2ZS1maWxlJ1wiXG4gICAgICAgICAgW2hhc1pvb21dPVwidHJ1ZVwiXG4gICAgICAgICAgKG91dFNhdmVGaWxlKT1cIm9uU2F2ZUltYWdlKCRldmVudClcIlxuICAgICAgICAgIChvdXRDbG9zZSk9XCJvbkNsb3NlRWRpdG9yKCRldmVudClcIiAvPlxuICAgICAgPC9kaXY+XG4gICAgfVxuXG4gICAgPHNlY3Rpb24gY2xhc3M9XCJiZy13aGl0ZSByb3VuZGVkLWxnIHAtOCBtYi04IHNoYWRvdy1zbVwiPlxuICAgICAgPGgyIGNsYXNzPVwidGV4dC0yeGwgZm9udC1ib2xkIHRleHQtZ3JheS04MDAgbWItNSBwYi0zIGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiPkPDoWNoIHPhu60gZOG7pW5nPC9oMj5cblxuICAgICAgPGRpdiBjbGFzcz1cIm1iLThcIj5cbiAgICAgICAgPGgzIGNsYXNzPVwidGV4dC14bCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDAgbWItNFwiPkPDoWNoIDE6IFPhu60gZOG7pW5nIGZpbGUgSFRNTCByacOqbmcgYmnhu4d0PC9oMz5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZ3JpZCBncmlkLWNvbHMtMSBtZDpncmlkLWNvbHMtMiBnYXAtNiBtYi00XCI+XG4gICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgIDxoNCBjbGFzcz1cImZvbnQtc2VtaWJvbGQgbWItMiB0ZXh0LWdyYXktNzAwXCI+SFRNTCAoZXhhbXBsZS5jb21wb25lbnQuaHRtbCk8L2g0PlxuICAgICAgICAgICAgPHByZSBjbGFzcz1cImJnLWdyYXktMTAwIHAtNCByb3VuZGVkLWxnIG92ZXJmbG93LXgtYXV0byB0ZXh0LXNtXCI+PGNvZGU+Jmx0O2xpYnNfdWktY29tcG9uZW50cy1pbWFnZV9lZGl0b3JcbiAgWyhpbWdTcmMpXT1cImltYWdlU291cmNlXCJcbiAgW25hbWVGaWxlXT1cIidpbWFnZS5qcGcnXCJcbiAgW21vZGVTaG93QnV0dG9uXT1cIidzYXZlLWZpbGUnXCJcbiAgKG91dFNhdmVGaWxlKT1cIm9uU2F2ZUZpbGUoJGV2ZW50KVwiXG4gIChvdXRDbG9zZSk9XCJvbkNsb3NlKCRldmVudClcIiZndDtcbiZsdDsvbGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvciZndDs8L2NvZGU+PC9wcmU+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPGg0IGNsYXNzPVwiZm9udC1zZW1pYm9sZCBtYi0yIHRleHQtZ3JheS03MDBcIj5UeXBlU2NyaXB0IChleGFtcGxlLmNvbXBvbmVudC50cyk8L2g0PlxuICAgICAgICAgICAgPHByZSBjbGFzcz1cImJnLWdyYXktMTAwIHAtNCByb3VuZGVkLWxnIG92ZXJmbG93LXgtYXV0byB0ZXh0LXNtXCI+PGNvZGU+aW1wb3J0ICYjMTIzOyBDb21wb25lbnQgJiMxMjU7IGZyb20gJyYjNjQ7YW5ndWxhci9jb3JlJztcbmltcG9ydCAmIzEyMzsgTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50ICYjMTI1OyBmcm9tICcmIzY0O2xpYnMtdWkvY29tcG9uZW50cy1pbWFnZS1lZGl0b3InO1xuXG4mIzY0O0NvbXBvbmVudCgmIzEyMztcbiAgc2VsZWN0b3I6ICdhcHAtZXhhbXBsZScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnRdLFxuICB0ZW1wbGF0ZVVybDogJy4vZXhhbXBsZS5jb21wb25lbnQuaHRtbCdcbiYjMTI1OylcbmV4cG9ydCBjbGFzcyBFeGFtcGxlQ29tcG9uZW50ICYjMTIzO1xuICBpbWFnZVNvdXJjZSA9ICdodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG8vaW1hZ2UuanBnJztcblxuICBvblNhdmVGaWxlKGRhdGE6ICYjMTIzO2ZpbGU6IEJsb2IsIHVybDogc3RyaW5nLCBtb2RlOiBzdHJpbmcmIzEyNTspICYjMTIzO1xuICAgIGNvbnNvbGUubG9nKCdGaWxlIMSRw6MgxJHGsOG7o2MgbMawdTonLCBkYXRhKTtcbiAgJiMxMjU7XG5cbiAgb25DbG9zZShkYXRhOiAmIzEyMztpc0NsaWNrQnV0dG9uQ2xvc2U6IGJvb2xlYW4mIzEyNTspICYjMTIzO1xuICAgIGNvbnNvbGUubG9nKCfEkMOjIMSRw7NuZyB0csOsbmggY2jhu4luaCBz4butYSDhuqNuaCcpO1xuICAmIzEyNTtcbiYjMTI1OzwvY29kZT48L3ByZT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cIm1iLThcIj5cbiAgICAgICAgPGgzIGNsYXNzPVwidGV4dC14bCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDAgbWItNFwiPkPDoWNoIDI6IFbhu5tpIHRyw6xuaCBjaOG7iW5oIHPhu61hIGPDsyB0aOG7gyDEkcOzbmcvbeG7nzwvaDM+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImdyaWQgZ3JpZC1jb2xzLTEgbWQ6Z3JpZC1jb2xzLTIgZ2FwLTYgbWItNFwiPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8aDQgY2xhc3M9XCJmb250LXNlbWlib2xkIG1iLTIgdGV4dC1ncmF5LTcwMFwiPkhUTUwgKHRvZ2dsZS1lZGl0b3IuY29tcG9uZW50Lmh0bWwpPC9oND5cbiAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJiZy1ncmF5LTEwMCBwLTQgcm91bmRlZC1sZyBvdmVyZmxvdy14LWF1dG8gdGV4dC1zbVwiPjxjb2RlPiZsdDtidXR0b24gKGNsaWNrKT1cIm9wZW5FZGl0b3IoKVwiIGNsYXNzPVwicHgtNCBweS0yIGJnLWJsdWUtNTAwIHRleHQtd2hpdGUgcm91bmRlZFwiJmd0O1xuICBN4bufIHRyw6xuaCBjaOG7iW5oIHPhu61hIOG6o25oXG4mbHQ7L2J1dHRvbiZndDtcblxuJiM2NDtpZiAoc2hvd0VkaXRvcikgJiMxMjM7XG4gICZsdDtsaWJzX3VpLWNvbXBvbmVudHMtaW1hZ2VfZWRpdG9yXG4gICAgWyhpbWdTcmMpXT1cImltYWdlU291cmNlXCJcbiAgICBbbmFtZUZpbGVdPVwiJ215LWltYWdlLmpwZydcIlxuICAgIChvdXRTYXZlRmlsZSk9XCJvblNhdmVGaWxlKCRldmVudClcIlxuICAgIChvdXRDbG9zZSk9XCJvbkNsb3NlRWRpdG9yKCRldmVudClcIiZndDtcbiAgJmx0Oy9saWJzX3VpLWNvbXBvbmVudHMtaW1hZ2VfZWRpdG9yJmd0O1xuJiMxMjU7XG5cbiYjNjQ7aWYgKGVkaXRlZEltYWdlVXJsKSAmIzEyMztcbiAgJmx0O2RpdiBjbGFzcz1cIm10LTRcIiZndDtcbiAgICAmbHQ7aDMgY2xhc3M9XCJ0ZXh0LWxnIGZvbnQtc2VtaWJvbGRcIiZndDtIw6xuaCDhuqNuaCDEkcOjIGNo4buJbmggc+G7rWE6Jmx0Oy9oMyZndDtcbiAgICAmbHQ7aW1nIFtzcmNdPVwiZWRpdGVkSW1hZ2VVcmxcIiBhbHQ9XCJIw6xuaCDhuqNuaCDEkcOjIGNo4buJbmggc+G7rWFcIiBjbGFzcz1cIm10LTIgbWF4LXctZnVsbCBoLWF1dG9cIiAvJmd0O1xuICAmbHQ7L2RpdiZndDtcbiYjMTI1OzwvY29kZT48L3ByZT5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8aDQgY2xhc3M9XCJmb250LXNlbWlib2xkIG1iLTIgdGV4dC1ncmF5LTcwMFwiPlR5cGVTY3JpcHQgKHRvZ2dsZS1lZGl0b3IuY29tcG9uZW50LnRzKTwvaDQ+XG4gICAgICAgICAgICA8cHJlIGNsYXNzPVwiYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgb3ZlcmZsb3cteC1hdXRvIHRleHQtc21cIj48Y29kZT5pbXBvcnQgJiMxMjM7IENvbXBvbmVudCAmIzEyNTsgZnJvbSAnJiM2NDthbmd1bGFyL2NvcmUnO1xuaW1wb3J0ICYjMTIzOyBMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnQgJiMxMjU7IGZyb20gJyYjNjQ7bGlicy11aS9jb21wb25lbnRzLWltYWdlLWVkaXRvcic7XG5pbXBvcnQgJiMxMjM7IElTYXZlRmlsZSAmIzEyNTsgZnJvbSAnJiM2NDtsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJztcblxuJiM2NDtDb21wb25lbnQoJiMxMjM7XG4gIHNlbGVjdG9yOiAnYXBwLXRvZ2dsZS1lZGl0b3InLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbTGlic1VpQ29tcG9uZW50c0ltYWdlRWRpdG9yQ29tcG9uZW50XSxcbiAgdGVtcGxhdGVVcmw6ICcuL3RvZ2dsZS1lZGl0b3IuY29tcG9uZW50Lmh0bWwnXG4mIzEyNTspXG5leHBvcnQgY2xhc3MgVG9nZ2xlRWRpdG9yQ29tcG9uZW50ICYjMTIzO1xuICBpbWFnZVNvdXJjZSA9ICdodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG8vaW1hZ2UuanBnJztcbiAgc2hvd0VkaXRvciA9IGZhbHNlO1xuICBlZGl0ZWRJbWFnZVVybCA9ICcnO1xuXG4gIG9wZW5FZGl0b3IoKSAmIzEyMztcbiAgICB0aGlzLnNob3dFZGl0b3IgPSB0cnVlO1xuICAmIzEyNTtcblxuICBvblNhdmVGaWxlKGRhdGE6IElTYXZlRmlsZSkgJiMxMjM7XG4gICAgdGhpcy5lZGl0ZWRJbWFnZVVybCA9IGRhdGEudXJsO1xuICAgIHRoaXMuc2hvd0VkaXRvciA9IGZhbHNlO1xuICAgIGNvbnNvbGUubG9nKCfEkMOjIGzGsHUgZmlsZTonLCBkYXRhLmZpbGUpO1xuICAmIzEyNTtcblxuICBvbkNsb3NlRWRpdG9yKGRhdGE6ICYjMTIzO2lzQ2xpY2tCdXR0b25DbG9zZTogYm9vbGVhbiYjMTI1OykgJiMxMjM7XG4gICAgdGhpcy5zaG93RWRpdG9yID0gZmFsc2U7XG4gICYjMTI1O1xuJiMxMjU7PC9jb2RlPjwvcHJlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2IGNsYXNzPVwibWItOFwiPlxuICAgICAgICA8aDMgY2xhc3M9XCJ0ZXh0LXhsIGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMCBtYi00XCI+Q8OhY2ggMzogVuG7m2kgdOG7tyBs4buHIGtodW5nIGjDrG5oIGPhu5EgxJHhu4tuaDwvaDM+XG5cbiAgICAgICAgPGRpdiBjbGFzcz1cImdyaWQgZ3JpZC1jb2xzLTEgbWQ6Z3JpZC1jb2xzLTIgZ2FwLTYgbWItNFwiPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8aDQgY2xhc3M9XCJmb250LXNlbWlib2xkIG1iLTIgdGV4dC1ncmF5LTcwMFwiPkhUTUwgKGZpeGVkLXJhdGlvLmNvbXBvbmVudC5odG1sKTwvaDQ+XG4gICAgICAgICAgICA8cHJlIGNsYXNzPVwiYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgb3ZlcmZsb3cteC1hdXRvIHRleHQtc21cIj48Y29kZT4mbHQ7bGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvclxuICBbKGltZ1NyYyldPVwiaW1hZ2VTb3VyY2VcIlxuICBbYXNwZWN0UmF0aW9dPVwiYXNwZWN0UmF0aW9cIlxuICBbcmVxdWlyZWRDcm9wRm9sbG93UmF0aW9dPVwidHJ1ZVwiXG4gIChvdXRTYXZlRmlsZSk9XCJvblNhdmVGaWxlKCRldmVudClcIiZndDtcbiZsdDsvbGlic191aS1jb21wb25lbnRzLWltYWdlX2VkaXRvciZndDs8L2NvZGU+PC9wcmU+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPGg0IGNsYXNzPVwiZm9udC1zZW1pYm9sZCBtYi0yIHRleHQtZ3JheS03MDBcIj5UeXBlU2NyaXB0IChmaXhlZC1yYXRpby5jb21wb25lbnQudHMpPC9oND5cbiAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJiZy1ncmF5LTEwMCBwLTQgcm91bmRlZC1sZyBvdmVyZmxvdy14LWF1dG8gdGV4dC1zbVwiPjxjb2RlPmltcG9ydCAmIzEyMzsgQ29tcG9uZW50ICYjMTI1OyBmcm9tICcmIzY0O2FuZ3VsYXIvY29yZSc7XG5pbXBvcnQgJiMxMjM7IExpYnNVaUNvbXBvbmVudHNJbWFnZUVkaXRvckNvbXBvbmVudCAmIzEyNTsgZnJvbSAnJiM2NDtsaWJzLXVpL2NvbXBvbmVudHMtaW1hZ2UtZWRpdG9yJztcbmltcG9ydCAmIzEyMzsgSUFzcGVjdFJhdGlvICYjMTI1OyBmcm9tICcmIzY0O2xpYnMtdWkvaW50ZXJmYWNlcy10eXBlcyc7XG5cbiYjNjQ7Q29tcG9uZW50KCYjMTIzO1xuICBzZWxlY3RvcjogJ2FwcC1maXhlZC1yYXRpbycsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtMaWJzVWlDb21wb25lbnRzSW1hZ2VFZGl0b3JDb21wb25lbnRdLFxuICB0ZW1wbGF0ZVVybDogJy4vZml4ZWQtcmF0aW8uY29tcG9uZW50Lmh0bWwnXG4mIzEyNTspXG5leHBvcnQgY2xhc3MgRml4ZWRSYXRpb0NvbXBvbmVudCAmIzEyMztcbiAgaW1hZ2VTb3VyY2UgPSAnaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ltYWdlLmpwZyc7XG4gIGFzcGVjdFJhdGlvOiBJQXNwZWN0UmF0aW8gPSAmIzEyMztcbiAgICBrZXk6ICcxOjEnLFxuICAgIHZhbHVlOiAxXG4gICYjMTI1OztcblxuICBvblNhdmVGaWxlKGRhdGE6IGFueSkgJiMxMjM7XG4gICAgY29uc29sZS5sb2coJ8SQw6MgbMawdSBow6xuaCDhuqNuaCB24bubaSB04bu3IGzhu4cgMToxJyk7XG4gICYjMTI1O1xuJiMxMjU7PC9jb2RlPjwvcHJlPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvc2VjdGlvbj5cblxuICAgIDxzZWN0aW9uIGNsYXNzPVwiYmctd2hpdGUgcm91bmRlZC1sZyBwLTggbWItOCBzaGFkb3ctc21cIj5cbiAgICAgIDxoMiBjbGFzcz1cInRleHQtMnhsIGZvbnQtYm9sZCB0ZXh0LWdyYXktODAwIG1iLTUgcGItMyBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj5Uw6BpIGxp4buHdSBBUEk8L2gyPlxuXG4gICAgICA8aDMgY2xhc3M9XCJ0ZXh0LXhsIGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMCBtYi00XCI+SW5wdXRzPC9oMz5cbiAgICAgIDxkaXYgY2xhc3M9XCJvdmVyZmxvdy14LWF1dG8gbWItOFwiPlxuICAgICAgICA8dGFibGUgY2xhc3M9XCJtaW4tdy1mdWxsIGJnLXdoaXRlIGJvcmRlciBib3JkZXItZ3JheS0yMDBcIj5cbiAgICAgICAgICA8dGhlYWQ+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0aCBjbGFzcz1cInB5LTMgcHgtNCBib3JkZXItYiBib3JkZXItZ3JheS0yMDAgYmctZ3JheS0xMDAgdGV4dC1sZWZ0IGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMFwiPlTDqm48L3RoPlxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJweS0zIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwIGJnLWdyYXktMTAwIHRleHQtbGVmdCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDBcIj5LaeG7g3UgZOG7r1xuICAgICAgICAgICAgICAgIGxp4buHdVxuICAgICAgICAgICAgICA8L3RoPlxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJweS0zIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwIGJnLWdyYXktMTAwIHRleHQtbGVmdCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDBcIj5N4bq3YyDEkeG7i25oXG4gICAgICAgICAgICAgIDwvdGg+XG4gICAgICAgICAgICAgIDx0aCBjbGFzcz1cInB5LTMgcHgtNCBib3JkZXItYiBib3JkZXItZ3JheS0yMDAgYmctZ3JheS0xMDAgdGV4dC1sZWZ0IGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMFwiPk3DtCB04bqjXG4gICAgICAgICAgICAgIDwvdGg+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvdGhlYWQ+XG4gICAgICAgICAgPHRib2R5PlxuICAgICAgICAgICAgQGZvciAoaW5wdXQgb2YgaW5wdXRzRG9jOyB0cmFjayBpbnB1dC5uYW1lKSB7XG4gICAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+PGNvZGVcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXNtIGJnLWdyYXktMTAwIHB4LTEuNSBweS0wLjUgcm91bmRlZFwiPnt7IGlucHV0Lm5hbWUgfX08L2NvZGU+PC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+PGNvZGVcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXNtIGJnLWdyYXktMTAwIHB4LTEuNSBweS0wLjUgcm91bmRlZFwiPnt7IGlucHV0LnR5cGUgfX08L2NvZGU+PC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+e3sgaW5wdXQuZGVmYXVsdCB9fTwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwicHktMiBweC00IGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiPnt7IGlucHV0LmRlc2NyaXB0aW9uIH19PC90ZD5cbiAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L3Rib2R5PlxuICAgICAgICA8L3RhYmxlPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTRcIj5PdXRwdXRzPC9oMz5cbiAgICAgIDxkaXYgY2xhc3M9XCJvdmVyZmxvdy14LWF1dG8gbWItOFwiPlxuICAgICAgICA8dGFibGUgY2xhc3M9XCJtaW4tdy1mdWxsIGJnLXdoaXRlIGJvcmRlciBib3JkZXItZ3JheS0yMDBcIj5cbiAgICAgICAgICA8dGhlYWQ+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0aCBjbGFzcz1cInB5LTMgcHgtNCBib3JkZXItYiBib3JkZXItZ3JheS0yMDAgYmctZ3JheS0xMDAgdGV4dC1sZWZ0IGZvbnQtc2VtaWJvbGQgdGV4dC1ncmF5LTcwMFwiPlTDqm48L3RoPlxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJweS0zIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwIGJnLWdyYXktMTAwIHRleHQtbGVmdCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDBcIj5LaeG7g3UgZOG7r1xuICAgICAgICAgICAgICAgIGxp4buHdVxuICAgICAgICAgICAgICA8L3RoPlxuICAgICAgICAgICAgICA8dGggY2xhc3M9XCJweS0zIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwIGJnLWdyYXktMTAwIHRleHQtbGVmdCBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDBcIj5Nw7QgdOG6o1xuICAgICAgICAgICAgICA8L3RoPlxuICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICA8L3RoZWFkPlxuICAgICAgICAgIDx0Ym9keT5cbiAgICAgICAgICAgIEBmb3IgKG91dHB1dCBvZiBvdXRwdXRzRG9jOyB0cmFjayBvdXRwdXQubmFtZSkge1xuICAgICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwicHktMiBweC00IGJvcmRlci1iIGJvcmRlci1ncmF5LTIwMFwiPjxjb2RlXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwidGV4dC1zbSBiZy1ncmF5LTEwMCBweC0xLjUgcHktMC41IHJvdW5kZWRcIj57eyBvdXRwdXQubmFtZSB9fTwvY29kZT48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cInB5LTIgcHgtNCBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj48Y29kZVxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cInRleHQtc20gYmctZ3JheS0xMDAgcHgtMS41IHB5LTAuNSByb3VuZGVkXCI+e3sgb3V0cHV0LnR5cGUgfX08L2NvZGU+PC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJweS0yIHB4LTQgYm9yZGVyLWIgYm9yZGVyLWdyYXktMjAwXCI+e3sgb3V0cHV0LmRlc2NyaXB0aW9uIH19PC90ZD5cbiAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L3Rib2R5PlxuICAgICAgICA8L3RhYmxlPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxoMyBjbGFzcz1cInRleHQteGwgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTRcIj5JbnRlcmZhY2VzPC9oMz5cbiAgICAgIDxkaXYgY2xhc3M9XCJzcGFjZS15LTZcIj5cbiAgICAgICAgQGZvciAoaW50ZXJmYWNlSXRlbSBvZiBpbnRlcmZhY2VzRG9jOyB0cmFjayBpbnRlcmZhY2VJdGVtLm5hbWUpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmctZ3JheS01MCBwLTYgcm91bmRlZC1sZ1wiPlxuICAgICAgICAgICAgPGg0IGNsYXNzPVwidGV4dC1sZyBmb250LXNlbWlib2xkIHRleHQtZ3JheS03MDAgbWItM1wiPnt7IGludGVyZmFjZUl0ZW0ubmFtZSB9fTwvaDQ+XG4gICAgICAgICAgICA8cHJlXG4gICAgICAgICAgICAgIGNsYXNzPVwiYmctZ3JheS0xMDAgcC00IHJvdW5kZWQtbGcgb3ZlcmZsb3cteC1hdXRvIHRleHQtc20gbWItM1wiPjxjb2RlPnt7IGludGVyZmFjZUl0ZW0uY29kZSB9fTwvY29kZT48L3ByZT5cbiAgICAgICAgICAgIDxwIGNsYXNzPVwidGV4dC1ncmF5LTYwMFwiPnt7IGludGVyZmFjZUl0ZW0uZGVzY3JpcHRpb24gfX08L3A+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuICAgIDwvc2VjdGlvbj5cblxuICAgIDxzZWN0aW9uIGNsYXNzPVwiYmctd2hpdGUgcm91bmRlZC1sZyBwLTggbWItOCBzaGFkb3ctc21cIj5cbiAgICAgIDxoMiBjbGFzcz1cInRleHQtMnhsIGZvbnQtYm9sZCB0ZXh0LWdyYXktODAwIG1iLTUgcGItMyBib3JkZXItYiBib3JkZXItZ3JheS0yMDBcIj5Uw61uaCBuxINuZzwvaDI+XG4gICAgICA8dWwgY2xhc3M9XCJzcGFjZS15LTZcIj5cbiAgICAgICAgQGZvciAoZmVhdHVyZSBvZiBmZWF0dXJlczsgdHJhY2sgZmVhdHVyZS5pZCkge1xuICAgICAgICAgIDxsaSBjbGFzcz1cImZsZXggaXRlbXMtc3RhcnRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwidGV4dC0yeGwgdGV4dC1ibHVlLTUwMFwiPnt7IGZlYXR1cmUuaWNvbiB9fTwvc3Bhbj5cbiAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgIDxoMyBjbGFzcz1cInRleHQtbGcgZm9udC1zZW1pYm9sZCB0ZXh0LWdyYXktNzAwIG1iLTFcIj57eyBmZWF0dXJlLnRpdGxlIH19PC9oMz5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJ0ZXh0LWdyYXktNjAwXCI+e3sgZmVhdHVyZS5kZXNjcmlwdGlvbiB9fTwvcD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvbGk+XG4gICAgICAgIH1cbiAgICAgIDwvdWw+XG4gICAgPC9zZWN0aW9uPlxuICA8L21haW4+XG48L2Rpdj5cbiJdfQ==
|