vg-coder-cli 2.0.20 → 2.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.vg/tree-state.json +9 -0
  2. package/package.json +5 -2
  3. package/scripts/build.js +49 -6
  4. package/src/index.js +4 -4
  5. package/src/server/api-server.js +83 -5
  6. package/src/server/views/css/structure.css +4 -1
  7. package/src/server/views/dashboard.css +51 -6
  8. package/src/server/views/dashboard.html +11 -3
  9. package/src/server/views/js/api.js +24 -0
  10. package/src/server/views/js/features/iframe-manager.js +2 -1
  11. package/src/server/views/js/features/resize.js +57 -0
  12. package/src/server/views/js/features/structure.js +109 -16
  13. package/src/server/views/js/main.js +36 -4
  14. package/src/server/views/vg-coder/background.js +48201 -2
  15. package/src/server/views/vg-coder/controller.js +496 -1
  16. package/src/server/views/vg-coder/manifest.json +13 -5
  17. package/src/server/views/vg-coder/{options.css → sidepanel.css} +34 -32
  18. package/src/server/views/vg-coder/{options.html → sidepanel.html} +2 -2
  19. package/src/server/views/vg-coder/sidepanel.js +347 -0
  20. package/vetgo-auto/README.md +3 -0
  21. package/vetgo-auto/chrome/CSP_IMPROVEMENTS.md +147 -0
  22. package/vetgo-auto/chrome/MANIFEST_V3_MIGRATION.md +123 -0
  23. package/vetgo-auto/chrome/assets/icon128.png +0 -0
  24. package/vetgo-auto/chrome/assets/icon16.png +0 -0
  25. package/vetgo-auto/chrome/assets/icon48.png +0 -0
  26. package/vetgo-auto/chrome/environments/environment.ts +13 -0
  27. package/vetgo-auto/chrome/manifest.json +66 -0
  28. package/vetgo-auto/chrome/rules.json +23 -0
  29. package/vetgo-auto/chrome/src/background.ts +200 -0
  30. package/vetgo-auto/chrome/src/controller.ts +98 -0
  31. package/vetgo-auto/chrome/src/controllers/common.firebase.ts +31 -0
  32. package/vetgo-auto/chrome/src/controllers/firebase-crud.ts +147 -0
  33. package/vetgo-auto/chrome/src/controllers/load-common-fuc.controller.ts +24 -0
  34. package/vetgo-auto/chrome/src/controllers/load-script.controller.ts +23 -0
  35. package/vetgo-auto/chrome/src/script-injector.ts +305 -0
  36. package/vetgo-auto/chrome/src/sidepanel.css +166 -0
  37. package/vetgo-auto/chrome/src/sidepanel.html +48 -0
  38. package/vetgo-auto/chrome/src/sidepanel.ts +127 -0
  39. package/vetgo-auto/chrome/src/utils/db-utils.ts +2 -0
  40. package/vetgo-auto/chrome/src/utils/environment-storage.service.ts +85 -0
  41. package/vetgo-auto/chrome/webpack.config.js +53 -0
  42. package/vetgo-auto/chrome/webpack.config.prod.js +54 -0
  43. package/vetgo-auto/package.json +30 -0
  44. package/vetgo-auto/tsconfig.json +27 -0
  45. package/vg-coder-cli-2.0.23.tgz +0 -0
  46. package/src/server/views/vg-coder/background.js.LICENSE.txt +0 -118
  47. package/src/server/views/vg-coder/options.js +0 -1
  48. package/vg-coder-cli-2.0.20.tgz +0 -0
  49. package/vg-coder-cli-2.0.21.tgz +0 -0
  50. package/vg-coder.zip +0 -0
@@ -9,51 +9,51 @@ body {
9
9
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10
10
  min-height: 100vh;
11
11
  display: flex;
12
- align-items: center;
12
+ align-items: flex-start;
13
13
  justify-content: center;
14
- padding: 20px;
14
+ padding: 0;
15
15
  }
16
16
 
17
17
  .container {
18
18
  background: white;
19
- border-radius: 16px;
20
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
21
- padding: 40px;
22
- max-width: 500px;
19
+ border-radius: 0;
20
+ box-shadow: none;
21
+ padding: 24px;
23
22
  width: 100%;
23
+ min-height: 100vh;
24
24
  }
25
25
 
26
26
  h1 {
27
27
  color: #333;
28
- font-size: 28px;
29
- margin-bottom: 10px;
28
+ font-size: 24px;
29
+ margin-bottom: 8px;
30
30
  font-weight: 600;
31
31
  }
32
32
 
33
33
  .subtitle {
34
34
  color: #666;
35
- font-size: 14px;
36
- margin-bottom: 30px;
35
+ font-size: 13px;
36
+ margin-bottom: 24px;
37
37
  }
38
38
 
39
39
  .form-group {
40
- margin-bottom: 24px;
40
+ margin-bottom: 20px;
41
41
  }
42
42
 
43
43
  label {
44
44
  display: block;
45
45
  color: #444;
46
- font-size: 14px;
46
+ font-size: 13px;
47
47
  font-weight: 500;
48
- margin-bottom: 8px;
48
+ margin-bottom: 6px;
49
49
  }
50
50
 
51
51
  input[type="text"] {
52
52
  width: 100%;
53
- padding: 12px 16px;
53
+ padding: 10px 12px;
54
54
  border: 2px solid #e0e0e0;
55
- border-radius: 8px;
56
- font-size: 15px;
55
+ border-radius: 6px;
56
+ font-size: 14px;
57
57
  transition: all 0.3s ease;
58
58
  outline: none;
59
59
  }
@@ -65,23 +65,23 @@ input[type="text"]:focus {
65
65
 
66
66
  .hint {
67
67
  color: #888;
68
- font-size: 12px;
69
- margin-top: 6px;
68
+ font-size: 11px;
69
+ margin-top: 4px;
70
70
  font-style: italic;
71
71
  }
72
72
 
73
73
  .button-group {
74
74
  display: flex;
75
- gap: 12px;
76
- margin-top: 30px;
75
+ gap: 10px;
76
+ margin-top: 24px;
77
77
  }
78
78
 
79
79
  button {
80
80
  flex: 1;
81
- padding: 12px 24px;
81
+ padding: 10px 20px;
82
82
  border: none;
83
- border-radius: 8px;
84
- font-size: 15px;
83
+ border-radius: 6px;
84
+ font-size: 14px;
85
85
  font-weight: 600;
86
86
  cursor: pointer;
87
87
  transition: all 0.3s ease;
@@ -94,8 +94,8 @@ button {
94
94
  }
95
95
 
96
96
  .btn-primary:hover {
97
- transform: translateY(-2px);
98
- box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
97
+ transform: translateY(-1px);
98
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
99
99
  }
100
100
 
101
101
  .btn-primary:active {
@@ -112,10 +112,10 @@ button {
112
112
  }
113
113
 
114
114
  .message {
115
- padding: 12px 16px;
116
- border-radius: 8px;
117
- margin-bottom: 20px;
118
- font-size: 14px;
115
+ padding: 10px 14px;
116
+ border-radius: 6px;
117
+ margin-bottom: 16px;
118
+ font-size: 13px;
119
119
  display: none;
120
120
  animation: slideIn 0.3s ease;
121
121
  }
@@ -147,18 +147,20 @@ button {
147
147
 
148
148
  .current-value {
149
149
  background: #f8f9fa;
150
- padding: 12px 16px;
151
- border-radius: 8px;
152
- margin-bottom: 20px;
150
+ padding: 10px 14px;
151
+ border-radius: 6px;
152
+ margin-bottom: 16px;
153
153
  border-left: 4px solid #667eea;
154
154
  }
155
155
 
156
156
  .current-value strong {
157
157
  color: #667eea;
158
158
  font-weight: 600;
159
+ font-size: 13px;
159
160
  }
160
161
 
161
162
  .current-value span {
162
163
  color: #333;
163
164
  font-family: 'Courier New', monospace;
165
+ font-size: 13px;
164
166
  }
@@ -5,7 +5,7 @@
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>VetGo Pro - Cấu hình</title>
8
- <link rel="stylesheet" href="options.css">
8
+ <link rel="stylesheet" href="sidepanel.css">
9
9
  </head>
10
10
 
11
11
  <body>
@@ -42,7 +42,7 @@
42
42
  </form>
43
43
  </div>
44
44
 
45
- <script src="options.js"></script>
45
+ <script src="sidepanel.js"></script>
46
46
  </body>
47
47
 
48
48
  </html>
@@ -0,0 +1,347 @@
1
+ /******/ (() => { // webpackBootstrap
2
+ /******/ "use strict";
3
+ /******/ var __webpack_modules__ = ({
4
+
5
+ /***/ "./chrome/environments/environment.ts":
6
+ /*!********************************************!*\
7
+ !*** ./chrome/environments/environment.ts ***!
8
+ \********************************************/
9
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
10
+
11
+ __webpack_require__.r(__webpack_exports__);
12
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
13
+ /* harmony export */ environment: () => (/* binding */ environment)
14
+ /* harmony export */ });
15
+ const environment = {
16
+ production: false,
17
+ environmentName: 'VGCODER',
18
+ firebaseConfig: {
19
+ apiKey: "AIzaSyDrpNMso-DXeN7c4vwbpV0idpxnV2vtXhQ",
20
+ authDomain: "vetgo-chrome.firebaseapp.com",
21
+ databaseURL: "https://vetgo-chrome-default-rtdb.asia-southeast1.firebasedatabase.app",
22
+ projectId: "vetgo-chrome",
23
+ storageBucket: "vetgo-chrome.appspot.com",
24
+ messagingSenderId: "211178224097",
25
+ appId: "1:211178224097:web:f73bf5a81c2f4c32fc7aa0"
26
+ }
27
+ };
28
+
29
+
30
+ /***/ }),
31
+
32
+ /***/ "./chrome/src/utils/environment-storage.service.ts":
33
+ /*!*********************************************************!*\
34
+ !*** ./chrome/src/utils/environment-storage.service.ts ***!
35
+ \*********************************************************/
36
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
37
+
38
+ __webpack_require__.r(__webpack_exports__);
39
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
40
+ /* harmony export */ EnvironmentStorageService: () => (/* binding */ EnvironmentStorageService)
41
+ /* harmony export */ });
42
+ /* harmony import */ var _environments_environment__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../environments/environment */ "./chrome/environments/environment.ts");
43
+ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
44
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
45
+ return new (P || (P = Promise))(function (resolve, reject) {
46
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
47
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
48
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
49
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
50
+ });
51
+ };
52
+
53
+ const STORAGE_KEY = 'environmentName';
54
+ const FIREBASE_CONFIG_KEY = 'firebaseConfig';
55
+ const DEFAULT_ENVIRONMENT = _environments_environment__WEBPACK_IMPORTED_MODULE_0__.environment.environmentName;
56
+ class EnvironmentStorageService {
57
+ /**
58
+ * Lấy environment name từ chrome.storage
59
+ */
60
+ static getEnvironmentName() {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ return new Promise((resolve) => {
63
+ chrome.storage.sync.get([STORAGE_KEY], (result) => {
64
+ const envName = result[STORAGE_KEY] || DEFAULT_ENVIRONMENT;
65
+ resolve(envName);
66
+ });
67
+ });
68
+ });
69
+ }
70
+ /**
71
+ * Lưu environment name vào chrome.storage
72
+ */
73
+ static setEnvironmentName(name) {
74
+ return __awaiter(this, void 0, void 0, function* () {
75
+ return new Promise((resolve, reject) => {
76
+ if (!name || name.trim() === '') {
77
+ reject(new Error('Environment name cannot be empty'));
78
+ return;
79
+ }
80
+ chrome.storage.sync.set({ [STORAGE_KEY]: name.trim() }, () => {
81
+ if (chrome.runtime.lastError) {
82
+ reject(chrome.runtime.lastError);
83
+ }
84
+ else {
85
+ resolve();
86
+ }
87
+ });
88
+ });
89
+ });
90
+ }
91
+ /**
92
+ * Lấy cấu hình Firebase. Ưu tiên storage, fallback về environment mặc định
93
+ */
94
+ static getFirebaseConfig() {
95
+ return __awaiter(this, void 0, void 0, function* () {
96
+ return new Promise((resolve) => {
97
+ chrome.storage.sync.get([FIREBASE_CONFIG_KEY], (result) => {
98
+ const customConfig = result[FIREBASE_CONFIG_KEY];
99
+ if (customConfig && Object.keys(customConfig).length > 0) {
100
+ resolve(customConfig);
101
+ }
102
+ else {
103
+ resolve(_environments_environment__WEBPACK_IMPORTED_MODULE_0__.environment.firebaseConfig);
104
+ }
105
+ });
106
+ });
107
+ });
108
+ }
109
+ /**
110
+ * Lưu cấu hình Firebase tùy chỉnh
111
+ */
112
+ static setFirebaseConfig(config) {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ return new Promise((resolve, reject) => {
115
+ chrome.storage.sync.set({ [FIREBASE_CONFIG_KEY]: config }, () => {
116
+ if (chrome.runtime.lastError) {
117
+ reject(chrome.runtime.lastError);
118
+ }
119
+ else {
120
+ resolve();
121
+ }
122
+ });
123
+ });
124
+ });
125
+ }
126
+ /**
127
+ * Reset về giá trị mặc định
128
+ */
129
+ static resetToDefault() {
130
+ return __awaiter(this, void 0, void 0, function* () {
131
+ try {
132
+ yield this.setEnvironmentName(DEFAULT_ENVIRONMENT);
133
+ // Xóa config firebase custom để dùng mặc định
134
+ yield new Promise((resolve) => {
135
+ chrome.storage.sync.remove(FIREBASE_CONFIG_KEY, () => resolve());
136
+ });
137
+ }
138
+ catch (e) {
139
+ throw e;
140
+ }
141
+ });
142
+ }
143
+ }
144
+
145
+
146
+ /***/ })
147
+
148
+ /******/ });
149
+ /************************************************************************/
150
+ /******/ // The module cache
151
+ /******/ var __webpack_module_cache__ = {};
152
+ /******/
153
+ /******/ // The require function
154
+ /******/ function __webpack_require__(moduleId) {
155
+ /******/ // Check if module is in cache
156
+ /******/ var cachedModule = __webpack_module_cache__[moduleId];
157
+ /******/ if (cachedModule !== undefined) {
158
+ /******/ return cachedModule.exports;
159
+ /******/ }
160
+ /******/ // Create a new module (and put it into the cache)
161
+ /******/ var module = __webpack_module_cache__[moduleId] = {
162
+ /******/ // no module.id needed
163
+ /******/ // no module.loaded needed
164
+ /******/ exports: {}
165
+ /******/ };
166
+ /******/
167
+ /******/ // Execute the module function
168
+ /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
169
+ /******/
170
+ /******/ // Return the exports of the module
171
+ /******/ return module.exports;
172
+ /******/ }
173
+ /******/
174
+ /************************************************************************/
175
+ /******/ /* webpack/runtime/define property getters */
176
+ /******/ (() => {
177
+ /******/ // define getter functions for harmony exports
178
+ /******/ __webpack_require__.d = (exports, definition) => {
179
+ /******/ for(var key in definition) {
180
+ /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
181
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
182
+ /******/ }
183
+ /******/ }
184
+ /******/ };
185
+ /******/ })();
186
+ /******/
187
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
188
+ /******/ (() => {
189
+ /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
190
+ /******/ })();
191
+ /******/
192
+ /******/ /* webpack/runtime/make namespace object */
193
+ /******/ (() => {
194
+ /******/ // define __esModule on exports
195
+ /******/ __webpack_require__.r = (exports) => {
196
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
197
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
198
+ /******/ }
199
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
200
+ /******/ };
201
+ /******/ })();
202
+ /******/
203
+ /************************************************************************/
204
+ var __webpack_exports__ = {};
205
+ // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
206
+ (() => {
207
+ /*!*********************************!*\
208
+ !*** ./chrome/src/sidepanel.ts ***!
209
+ \*********************************/
210
+ __webpack_require__.r(__webpack_exports__);
211
+ /* harmony import */ var _utils_environment_storage_service__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/environment-storage.service */ "./chrome/src/utils/environment-storage.service.ts");
212
+ /* harmony import */ var _environments_environment__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../environments/environment */ "./chrome/environments/environment.ts");
213
+ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
214
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
215
+ return new (P || (P = Promise))(function (resolve, reject) {
216
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
217
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
218
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
219
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
220
+ });
221
+ };
222
+
223
+
224
+ // DOM Elements
225
+ const form = document.getElementById('configForm');
226
+ const environmentInput = document.getElementById('environmentName');
227
+ const firebaseConfigInput = document.getElementById('firebaseConfig');
228
+ const resetBtn = document.getElementById('resetBtn');
229
+ const messageDiv = document.getElementById('message');
230
+ const currentEnvSpan = document.getElementById('currentEnv');
231
+ /**
232
+ * Hiển thị thông báo cho người dùng
233
+ */
234
+ function showMessage(text, type) {
235
+ messageDiv.textContent = text;
236
+ messageDiv.className = `message ${type}`;
237
+ // Tự động ẩn thông báo sau 3 giây
238
+ setTimeout(() => {
239
+ messageDiv.className = 'message';
240
+ }, 3000);
241
+ }
242
+ /**
243
+ * Load và hiển thị giá trị hiện tại
244
+ */
245
+ function loadCurrentConfig() {
246
+ return __awaiter(this, void 0, void 0, function* () {
247
+ try {
248
+ // Load Env Name
249
+ const envName = yield _utils_environment_storage_service__WEBPACK_IMPORTED_MODULE_0__.EnvironmentStorageService.getEnvironmentName();
250
+ currentEnvSpan.textContent = envName;
251
+ environmentInput.value = envName;
252
+ // Load Firebase Config
253
+ const fbConfig = yield _utils_environment_storage_service__WEBPACK_IMPORTED_MODULE_0__.EnvironmentStorageService.getFirebaseConfig();
254
+ // Kiểm tra xem có phải config mặc định không
255
+ const isDefault = JSON.stringify(fbConfig) === JSON.stringify(_environments_environment__WEBPACK_IMPORTED_MODULE_1__.environment.firebaseConfig);
256
+ if (!isDefault) {
257
+ firebaseConfigInput.value = JSON.stringify(fbConfig, null, 2);
258
+ }
259
+ else {
260
+ firebaseConfigInput.value = ''; // Để trống nếu đang dùng default
261
+ firebaseConfigInput.placeholder = `Đang sử dụng mặc định:\n${JSON.stringify(_environments_environment__WEBPACK_IMPORTED_MODULE_1__.environment.firebaseConfig, null, 2)}`;
262
+ }
263
+ }
264
+ catch (error) {
265
+ console.error('Error loading config:', error);
266
+ currentEnvSpan.textContent = 'Lỗi khi tải cấu hình';
267
+ showMessage('Không thể tải cấu hình hiện tại', 'error');
268
+ }
269
+ });
270
+ }
271
+ /**
272
+ * Xử lý sự kiện submit form
273
+ */
274
+ function handleSubmit(event) {
275
+ return __awaiter(this, void 0, void 0, function* () {
276
+ event.preventDefault();
277
+ const newEnvName = environmentInput.value.trim();
278
+ const firebaseConfigStr = firebaseConfigInput.value.trim();
279
+ if (!newEnvName) {
280
+ showMessage('Vui lòng nhập tên môi trường', 'error');
281
+ return;
282
+ }
283
+ try {
284
+ // 1. Lưu Environment Name
285
+ yield _utils_environment_storage_service__WEBPACK_IMPORTED_MODULE_0__.EnvironmentStorageService.setEnvironmentName(newEnvName);
286
+ currentEnvSpan.textContent = newEnvName;
287
+ // 2. Lưu Firebase Config
288
+ if (firebaseConfigStr) {
289
+ try {
290
+ const configObj = JSON.parse(firebaseConfigStr);
291
+ // Validate sơ bộ
292
+ if (!configObj.apiKey || !configObj.databaseURL) {
293
+ throw new Error("Config thiếu apiKey hoặc databaseURL");
294
+ }
295
+ yield _utils_environment_storage_service__WEBPACK_IMPORTED_MODULE_0__.EnvironmentStorageService.setFirebaseConfig(configObj);
296
+ }
297
+ catch (e) {
298
+ showMessage('❌ JSON Firebase Config không hợp lệ: ' + e.message, 'error');
299
+ return;
300
+ }
301
+ }
302
+ else {
303
+ // Nếu để trống, xóa custom config để dùng default
304
+ yield new Promise((resolve) => {
305
+ chrome.storage.sync.remove('firebaseConfig', () => resolve());
306
+ });
307
+ }
308
+ showMessage('✅ Lưu cấu hình thành công!', 'success');
309
+ // Reload lại hiển thị để update placeholder/value
310
+ loadCurrentConfig();
311
+ }
312
+ catch (error) {
313
+ console.error('Error saving settings:', error);
314
+ showMessage('❌ Lỗi khi lưu cấu hình: ' + error.message, 'error');
315
+ }
316
+ });
317
+ }
318
+ /**
319
+ * Xử lý sự kiện reset về mặc định
320
+ */
321
+ function handleReset() {
322
+ return __awaiter(this, void 0, void 0, function* () {
323
+ if (!confirm('Bạn có chắc muốn đặt lại tất cả về mặc định?')) {
324
+ return;
325
+ }
326
+ try {
327
+ yield _utils_environment_storage_service__WEBPACK_IMPORTED_MODULE_0__.EnvironmentStorageService.resetToDefault();
328
+ yield loadCurrentConfig(); // Reload UI
329
+ showMessage('✅ Đã đặt lại về cấu hình mặc định!', 'success');
330
+ }
331
+ catch (error) {
332
+ console.error('Error resetting environment:', error);
333
+ showMessage('❌ Lỗi khi đặt lại cấu hình', 'error');
334
+ }
335
+ });
336
+ }
337
+ // Event Listeners
338
+ form.addEventListener('submit', handleSubmit);
339
+ resetBtn.addEventListener('click', handleReset);
340
+ // Load giá trị hiện tại khi trang được mở
341
+ loadCurrentConfig();
342
+
343
+ })();
344
+
345
+ /******/ })()
346
+ ;
347
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,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Qy9FO0lBQ0wsQ0FBQztDQUFBO0FBRUQ7O0dBRUc7QUFDSCxTQUFlLFdBQVc7O1FBQ3RCLElBQUksQ0FBQyxPQUFPLENBQUMsOENBQThDLENBQUMsRUFBRTtZQUMxRCxPQUFPO1NBQ1Y7UUFFRCxJQUFJO1lBQ0EsTUFBTSx5RkFBeUIsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNqRCxNQUFNLGlCQUFpQixFQUFFLENBQUMsQ0FBQyxZQUFZO1lBQ3ZDLFdBQVcsQ0FBQyxvQ0FBb0MsRUFBRSxTQUFTLENBQUMsQ0FBQztTQUNoRTtRQUFDLE9BQU8sS0FBSyxFQUFFO1lBQ1osT0FBTyxDQUFDLEtBQUssQ0FBQyw4QkFBOEIsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNyRCxXQUFXLENBQUMsNEJBQTRCLEVBQUUsT0FBTyxDQUFDLENBQUM7U0FDdEQ7SUFDTCxDQUFDO0NBQUE7QUFFRCxrQkFBa0I7QUFDbEIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUM5QyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBRWhELDBDQUEwQztBQUMxQyxpQkFBaUIsRUFBRSxDQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdmctY29kZXIvLi9jaHJvbWUvZW52aXJvbm1lbnRzL2Vudmlyb25tZW50LnRzIiwid2VicGFjazovL3ZnLWNvZGVyLy4vY2hyb21lL3NyYy91dGlscy9lbnZpcm9ubWVudC1zdG9yYWdlLnNlcnZpY2UudHMiLCJ3ZWJwYWNrOi8vdmctY29kZXIvd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vdmctY29kZXIvd2VicGFjay9ydW50aW1lL2RlZmluZSBwcm9wZXJ0eSBnZXR0ZXJzIiwid2VicGFjazovL3ZnLWNvZGVyL3dlYnBhY2svcnVudGltZS9oYXNPd25Qcm9wZXJ0eSBzaG9ydGhhbmQiLCJ3ZWJwYWNrOi8vdmctY29kZXIvd2VicGFjay9ydW50aW1lL21ha2UgbmFtZXNwYWNlIG9iamVjdCIsIndlYnBhY2s6Ly92Zy1jb2Rlci8uL2Nocm9tZS9zcmMvc2lkZXBhbmVsLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCBlbnZpcm9ubWVudCA9IHtcbiAgcHJvZHVjdGlvbjogZmFsc2UsXG4gIGVudmlyb25tZW50TmFtZTogJ1ZHQ09ERVInLFxuICBmaXJlYmFzZUNvbmZpZzoge1xuICAgIGFwaUtleTogXCJBSXphU3lEcnBOTXNvLURYZU43YzR2d2JwVjBpZHB4blYydnRYaFFcIixcbiAgICBhdXRoRG9tYWluOiBcInZldGdvLWNocm9tZS5maXJlYmFzZWFwcC5jb21cIixcbiAgICBkYXRhYmFzZVVSTDogXCJodHRwczovL3ZldGdvLWNocm9tZS1kZWZhdWx0LXJ0ZGIuYXNpYS1zb3V0aGVhc3QxLmZpcmViYXNlZGF0YWJhc2UuYXBwXCIsXG4gICAgcHJvamVjdElkOiBcInZldGdvLWNocm9tZVwiLFxuICAgIHN0b3JhZ2VCdWNrZXQ6IFwidmV0Z28tY2hyb21lLmFwcHNwb3QuY29tXCIsXG4gICAgbWVzc2FnaW5nU2VuZGVySWQ6IFwiMjExMTc4MjI0MDk3XCIsXG4gICAgYXBwSWQ6IFwiMToyMTExNzgyMjQwOTc6d2ViOmY3M2JmNWE4MWMyZjRjMzJmYzdhYTBcIlxuICB9XG59O1xuIiwiaW1wb3J0IHsgZW52aXJvbm1lbnQgfSBmcm9tIFwiLi4vLi4vZW52aXJvbm1lbnRzL2Vudmlyb25tZW50XCI7XG5cbmNvbnN0IFNUT1JBR0VfS0VZID0gJ2Vudmlyb25tZW50TmFtZSc7XG5jb25zdCBGSVJFQkFTRV9DT05GSUdfS0VZID0gJ2ZpcmViYXNlQ29uZmlnJztcbmNvbnN0IERFRkFVTFRfRU5WSVJPTk1FTlQgPSBlbnZpcm9ubWVudC5lbnZpcm9ubWVudE5hbWU7XG5cbmV4cG9ydCBjbGFzcyBFbnZpcm9ubWVudFN0b3JhZ2VTZXJ2aWNlIHtcbiAgICAvKipcbiAgICAgKiBM4bqleSBlbnZpcm9ubWVudCBuYW1lIHThu6sgY2hyb21lLnN0b3JhZ2VcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgZ2V0RW52aXJvbm1lbnROYW1lKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICAgICAgY2hyb21lLnN0b3JhZ2Uuc3luYy5nZXQoW1NUT1JBR0VfS0VZXSwgKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGVudk5hbWUgPSByZXN1bHRbU1RPUkFHRV9LRVldIHx8IERFRkFVTFRfRU5WSVJPTk1FTlQ7XG4gICAgICAgICAgICAgICAgcmVzb2x2ZShlbnZOYW1lKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMxrB1IGVudmlyb25tZW50IG5hbWUgdsOgbyBjaHJvbWUuc3RvcmFnZVxuICAgICAqL1xuICAgIHN0YXRpYyBhc3luYyBzZXRFbnZpcm9ubWVudE5hbWUobmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIW5hbWUgfHwgbmFtZS50cmltKCkgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcignRW52aXJvbm1lbnQgbmFtZSBjYW5ub3QgYmUgZW1wdHknKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjaHJvbWUuc3RvcmFnZS5zeW5jLnNldCh7IFtTVE9SQUdFX0tFWV06IG5hbWUudHJpbSgpIH0sICgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoY2hyb21lLnJ1bnRpbWUubGFzdEVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlamVjdChjaHJvbWUucnVudGltZS5sYXN0RXJyb3IpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTOG6pXkgY+G6pXUgaMOsbmggRmlyZWJhc2UuIMavdSB0acOqbiBzdG9yYWdlLCBmYWxsYmFjayB24buBIGVudmlyb25tZW50IG3hurdjIMSR4buLbmhcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgZ2V0RmlyZWJhc2VDb25maWcoKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgICBjaHJvbWUuc3RvcmFnZS5zeW5jLmdldChbRklSRUJBU0VfQ09ORklHX0tFWV0sIChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjdXN0b21Db25maWcgPSByZXN1bHRbRklSRUJBU0VfQ09ORklHX0tFWV07XG4gICAgICAgICAgICAgICAgaWYgKGN1c3RvbUNvbmZpZyAmJiBPYmplY3Qua2V5cyhjdXN0b21Db25maWcpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShjdXN0b21Db25maWcpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoZW52aXJvbm1lbnQuZmlyZWJhc2VDb25maWcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMxrB1IGPhuqV1IGjDrG5oIEZpcmViYXNlIHTDuXkgY2jhu4luaFxuICAgICAqL1xuICAgIHN0YXRpYyBhc3luYyBzZXRGaXJlYmFzZUNvbmZpZyhjb25maWc6IGFueSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgY2hyb21lLnN0b3JhZ2Uuc3luYy5zZXQoeyBbRklSRUJBU0VfQ09ORklHX0tFWV06IGNvbmZpZyB9LCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGNocm9tZS5ydW50aW1lLmxhc3RFcnJvcikge1xuICAgICAgICAgICAgICAgICAgICByZWplY3QoY2hyb21lLnJ1bnRpbWUubGFzdEVycm9yKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlc2V0IHbhu4EgZ2nDoSB0cuG7iyBt4bq3YyDEkeG7i25oXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIHJlc2V0VG9EZWZhdWx0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5zZXRFbnZpcm9ubWVudE5hbWUoREVGQVVMVF9FTlZJUk9OTUVOVCk7XG4gICAgICAgICAgICAvLyBYw7NhIGNvbmZpZyBmaXJlYmFzZSBjdXN0b20gxJHhu4MgZMO5bmcgbeG6t2MgxJHhu4tuaFxuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgICAgICAgICAgICBjaHJvbWUuc3RvcmFnZS5zeW5jLnJlbW92ZShGSVJFQkFTRV9DT05GSUdfS0VZLCAoKSA9PiByZXNvbHZlKCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCIvLyBUaGUgbW9kdWxlIGNhY2hlXG52YXIgX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fID0ge307XG5cbi8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG5mdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuXHR2YXIgY2FjaGVkTW9kdWxlID0gX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fW21vZHVsZUlkXTtcblx0aWYgKGNhY2hlZE1vZHVsZSAhPT0gdW5kZWZpbmVkKSB7XG5cdFx0cmV0dXJuIGNhY2hlZE1vZHVsZS5leHBvcnRzO1xuXHR9XG5cdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG5cdHZhciBtb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdID0ge1xuXHRcdC8vIG5vIG1vZHVsZS5pZCBuZWVkZWRcblx0XHQvLyBubyBtb2R1bGUubG9hZGVkIG5lZWRlZFxuXHRcdGV4cG9ydHM6IHt9XG5cdH07XG5cblx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG5cdF9fd2VicGFja19tb2R1bGVzX19bbW9kdWxlSWRdKG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG5cdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG5cdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbn1cblxuIiwiLy8gZGVmaW5lIGdldHRlciBmdW5jdGlvbnMgZm9yIGhhcm1vbnkgZXhwb3J0c1xuX193ZWJwYWNrX3JlcXVpcmVfXy5kID0gKGV4cG9ydHMsIGRlZmluaXRpb24pID0+IHtcblx0Zm9yKHZhciBrZXkgaW4gZGVmaW5pdGlvbikge1xuXHRcdGlmKF9fd2VicGFja19yZXF1aXJlX18ubyhkZWZpbml0aW9uLCBrZXkpICYmICFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywga2V5KSkge1xuXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIGtleSwgeyBlbnVtZXJhYmxlOiB0cnVlLCBnZXQ6IGRlZmluaXRpb25ba2V5XSB9KTtcblx0XHR9XG5cdH1cbn07IiwiX193ZWJwYWNrX3JlcXVpcmVfXy5vID0gKG9iaiwgcHJvcCkgPT4gKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIHByb3ApKSIsIi8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uciA9IChleHBvcnRzKSA9PiB7XG5cdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuXHR9XG5cdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG59OyIsImltcG9ydCB7IEVudmlyb25tZW50U3RvcmFnZVNlcnZpY2UgfSBmcm9tICcuL3V0aWxzL2Vudmlyb25tZW50LXN0b3JhZ2Uuc2VydmljZSc7XG5pbXBvcnQgeyBlbnZpcm9ubWVudCB9IGZyb20gJy4uL2Vudmlyb25tZW50cy9lbnZpcm9ubWVudCc7XG5cbi8vIERPTSBFbGVtZW50c1xuY29uc3QgZm9ybSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjb25maWdGb3JtJykgYXMgSFRNTEZvcm1FbGVtZW50O1xuY29uc3QgZW52aXJvbm1lbnRJbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdlbnZpcm9ubWVudE5hbWUnKSBhcyBIVE1MSW5wdXRFbGVtZW50O1xuY29uc3QgZmlyZWJhc2VDb25maWdJbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdmaXJlYmFzZUNvbmZpZycpIGFzIEhUTUxUZXh0QXJlYUVsZW1lbnQ7XG5jb25zdCByZXNldEJ0biA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyZXNldEJ0bicpIGFzIEhUTUxCdXR0b25FbGVtZW50O1xuY29uc3QgbWVzc2FnZURpdiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtZXNzYWdlJykgYXMgSFRNTERpdkVsZW1lbnQ7XG5jb25zdCBjdXJyZW50RW52U3BhbiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjdXJyZW50RW52JykgYXMgSFRNTFNwYW5FbGVtZW50O1xuXG4vKipcbiAqIEhp4buDbiB0aOG7iyB0aMO0bmcgYsOhbyBjaG8gbmfGsOG7nWkgZMO5bmdcbiAqL1xuZnVuY3Rpb24gc2hvd01lc3NhZ2UodGV4dDogc3RyaW5nLCB0eXBlOiAnc3VjY2VzcycgfCAnZXJyb3InKSB7XG4gICAgbWVzc2FnZURpdi50ZXh0Q29udGVudCA9IHRleHQ7XG4gICAgbWVzc2FnZURpdi5jbGFzc05hbWUgPSBgbWVzc2FnZSAke3R5cGV9YDtcblxuICAgIC8vIFThu7EgxJHhu5luZyDhuqluIHRow7RuZyBiw6FvIHNhdSAzIGdpw6J5XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIG1lc3NhZ2VEaXYuY2xhc3NOYW1lID0gJ21lc3NhZ2UnO1xuICAgIH0sIDMwMDApO1xufVxuXG4vKipcbiAqIExvYWQgdsOgIGhp4buDbiB0aOG7iyBnacOhIHRy4buLIGhp4buHbiB04bqhaVxuICovXG5hc3luYyBmdW5jdGlvbiBsb2FkQ3VycmVudENvbmZpZygpIHtcbiAgICB0cnkge1xuICAgICAgICAvLyBMb2FkIEVudiBOYW1lXG4gICAgICAgIGNvbnN0IGVudk5hbWUgPSBhd2FpdCBFbnZpcm9ubWVudFN0b3JhZ2VTZXJ2aWNlLmdldEVudmlyb25tZW50TmFtZSgpO1xuICAgICAgICBjdXJyZW50RW52U3Bhbi50ZXh0Q29udGVudCA9IGVudk5hbWU7XG4gICAgICAgIGVudmlyb25tZW50SW5wdXQudmFsdWUgPSBlbnZOYW1lO1xuXG4gICAgICAgIC8vIExvYWQgRmlyZWJhc2UgQ29uZmlnXG4gICAgICAgIGNvbnN0IGZiQ29uZmlnID0gYXdhaXQgRW52aXJvbm1lbnRTdG9yYWdlU2VydmljZS5nZXRGaXJlYmFzZUNvbmZpZygpO1xuICAgICAgICBcbiAgICAgICAgLy8gS2nhu4NtIHRyYSB4ZW0gY8OzIHBo4bqjaSBjb25maWcgbeG6t2MgxJHhu4tuaCBraMO0bmdcbiAgICAgICAgY29uc3QgaXNEZWZhdWx0ID0gSlNPTi5zdHJpbmdpZnkoZmJDb25maWcpID09PSBKU09OLnN0cmluZ2lmeShlbnZpcm9ubWVudC5maXJlYmFzZUNvbmZpZyk7XG4gICAgICAgIFxuICAgICAgICBpZiAoIWlzRGVmYXVsdCkge1xuICAgICAgICAgICAgZmlyZWJhc2VDb25maWdJbnB1dC52YWx1ZSA9IEpTT04uc3RyaW5naWZ5KGZiQ29uZmlnLCBudWxsLCAyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGZpcmViYXNlQ29uZmlnSW5wdXQudmFsdWUgPSAnJzsgLy8gxJDhu4MgdHLhu5FuZyBu4bq/dSDEkWFuZyBkw7luZyBkZWZhdWx0XG4gICAgICAgICAgICBmaXJlYmFzZUNvbmZpZ0lucHV0LnBsYWNlaG9sZGVyID0gYMSQYW5nIHPhu60gZOG7pW5nIG3hurdjIMSR4buLbmg6XFxuJHtKU09OLnN0cmluZ2lmeShlbnZpcm9ubWVudC5maXJlYmFzZUNvbmZpZywgbnVsbCwgMil9YDtcbiAgICAgICAgfVxuXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgbG9hZGluZyBjb25maWc6JywgZXJyb3IpO1xuICAgICAgICBjdXJyZW50RW52U3Bhbi50ZXh0Q29udGVudCA9ICdM4buXaSBraGkgdOG6o2kgY+G6pXUgaMOsbmgnO1xuICAgICAgICBzaG93TWVzc2FnZSgnS2jDtG5nIHRo4buDIHThuqNpIGPhuqV1IGjDrG5oIGhp4buHbiB04bqhaScsICdlcnJvcicpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBY4butIGzDvSBz4buxIGtp4buHbiBzdWJtaXQgZm9ybVxuICovXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVTdWJtaXQoZXZlbnQ6IEV2ZW50KSB7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgIGNvbnN0IG5ld0Vudk5hbWUgPSBlbnZpcm9ubWVudElucHV0LnZhbHVlLnRyaW0oKTtcbiAgICBjb25zdCBmaXJlYmFzZUNvbmZpZ1N0ciA9IGZpcmViYXNlQ29uZmlnSW5wdXQudmFsdWUudHJpbSgpO1xuXG4gICAgaWYgKCFuZXdFbnZOYW1lKSB7XG4gICAgICAgIHNob3dNZXNzYWdlKCdWdWkgbMOybmcgbmjhuq1wIHTDqm4gbcO0aSB0csaw4budbmcnLCAnZXJyb3InKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAgIC8vIDEuIEzGsHUgRW52aXJvbm1lbnQgTmFtZVxuICAgICAgICBhd2FpdCBFbnZpcm9ubWVudFN0b3JhZ2VTZXJ2aWNlLnNldEVudmlyb25tZW50TmFtZShuZXdFbnZOYW1lKTtcbiAgICAgICAgY3VycmVudEVudlNwYW4udGV4dENvbnRlbnQgPSBuZXdFbnZOYW1lO1xuXG4gICAgICAgIC8vIDIuIEzGsHUgRmlyZWJhc2UgQ29uZmlnXG4gICAgICAgIGlmIChmaXJlYmFzZUNvbmZpZ1N0cikge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb25maWdPYmogPSBKU09OLnBhcnNlKGZpcmViYXNlQ29uZmlnU3RyKTtcbiAgICAgICAgICAgICAgICAvLyBWYWxpZGF0ZSBzxqEgYuG7mVxuICAgICAgICAgICAgICAgIGlmICghY29uZmlnT2JqLmFwaUtleSB8fCAhY29uZmlnT2JqLmRhdGFiYXNlVVJMKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvbmZpZyB0aGnhur91IGFwaUtleSBob+G6t2MgZGF0YWJhc2VVUkxcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGF3YWl0IEVudmlyb25tZW50U3RvcmFnZVNlcnZpY2Uuc2V0RmlyZWJhc2VDb25maWcoY29uZmlnT2JqKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBzaG93TWVzc2FnZSgn4p2MIEpTT04gRmlyZWJhc2UgQ29uZmlnIGtow7RuZyBo4bujcCBs4buHOiAnICsgKGUgYXMgRXJyb3IpLm1lc3NhZ2UsICdlcnJvcicpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIE7hur91IMSR4buDIHRy4buRbmcsIHjDs2EgY3VzdG9tIGNvbmZpZyDEkeG7gyBkw7luZyBkZWZhdWx0XG4gICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgICAgICAgICAgICBjaHJvbWUuc3RvcmFnZS5zeW5jLnJlbW92ZSgnZmlyZWJhc2VDb25maWcnLCAoKSA9PiByZXNvbHZlKCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBzaG93TWVzc2FnZSgn4pyFIEzGsHUgY+G6pXUgaMOsbmggdGjDoG5oIGPDtG5nIScsICdzdWNjZXNzJyk7XG4gICAgICAgIC8vIFJlbG9hZCBs4bqhaSBoaeG7g24gdGjhu4sgxJHhu4MgdXBkYXRlIHBsYWNlaG9sZGVyL3ZhbHVlXG4gICAgICAgIGxvYWRDdXJyZW50Q29uZmlnKCk7XG4gICAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHNhdmluZyBzZXR0aW5nczonLCBlcnJvcik7XG4gICAgICAgIHNob3dNZXNzYWdlKCfinYwgTOG7l2kga2hpIGzGsHUgY+G6pXUgaMOsbmg6ICcgKyAoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2UsICdlcnJvcicpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBY4butIGzDvSBz4buxIGtp4buHbiByZXNldCB24buBIG3hurdjIMSR4buLbmhcbiAqL1xuYXN5bmMgZnVuY3Rpb24gaGFuZGxlUmVzZXQoKSB7XG4gICAgaWYgKCFjb25maXJtKCdC4bqhbiBjw7MgY2jhuq9jIG114buRbiDEkeG6t3QgbOG6oWkgdOG6pXQgY+G6oyB24buBIG3hurdjIMSR4buLbmg/JykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IEVudmlyb25tZW50U3RvcmFnZVNlcnZpY2UucmVzZXRUb0RlZmF1bHQoKTtcbiAgICAgICAgYXdhaXQgbG9hZEN1cnJlbnRDb25maWcoKTsgLy8gUmVsb2FkIFVJXG4gICAgICAgIHNob3dNZXNzYWdlKCfinIUgxJDDoyDEkeG6t3QgbOG6oWkgduG7gSBj4bqldSBow6xuaCBt4bq3YyDEkeG7i25oIScsICdzdWNjZXNzJyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgcmVzZXR0aW5nIGVudmlyb25tZW50OicsIGVycm9yKTtcbiAgICAgICAgc2hvd01lc3NhZ2UoJ+KdjCBM4buXaSBraGkgxJHhurd0IGzhuqFpIGPhuqV1IGjDrG5oJywgJ2Vycm9yJyk7XG4gICAgfVxufVxuXG4vLyBFdmVudCBMaXN0ZW5lcnNcbmZvcm0uYWRkRXZlbnRMaXN0ZW5lcignc3VibWl0JywgaGFuZGxlU3VibWl0KTtcbnJlc2V0QnRuLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgaGFuZGxlUmVzZXQpO1xuXG4vLyBMb2FkIGdpw6EgdHLhu4sgaGnhu4duIHThuqFpIGtoaSB0cmFuZyDEkcaw4bujYyBt4bufXG5sb2FkQ3VycmVudENvbmZpZygpO1xuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6W10sInNvdXJjZVJvb3QiOiIifQ==
@@ -0,0 +1,3 @@
1
+ npm install --force
2
+
3
+ node 16.13.2