-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbootstrap.py
More file actions
744 lines (616 loc) · 198 KB
/
bootstrap.py
File metadata and controls
744 lines (616 loc) · 198 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
import os
import re
import requests
import subprocess
import sys
import shutil
import textwrap
import time
import logging
import ctypes
import json # Import json
from pathlib import Path
from dotenv import load_dotenv
from playwright.sync_api import sync_playwright
import webbrowser # Import webbrowser module
import asyncio # Import asyncio
import pyttsx3 # For text-to-speech
import base64
# import psutil
# import tkinter as tk
# from tkinter import messagebox
# --- Configuration ---
load_dotenv() # Load environment variables from .env file if it exists
username = os.getenv("USERNAME")
CHROME_PATH = os.getenv("CHROME_PATH", r"C:\Program Files\Google\Chrome\Application\chrome.exe")
DEFAULT_USER_DATA_DIR = os.getenv("DEFAULT_USER_DATA_DIR", fr"C:\Users\{username}\AppData\Local\Google\Chrome\User Data")
NEW_PROFILE_NAME = os.getenv("NEW_PROFILE_NAME", "ChromeAutomationProfile")
NEW_PROFILE_DIR = Path.home() / NEW_PROFILE_NAME
VENV_DIR = Path(os.getenv("VENV_DIR", Path.home() / "AutoPyBot_venv"))
WEB_UI_REPO_URL = os.getenv("WEB_UI_REPO_URL", "https://github.com/browser-use/web-ui.git")
# WEB_UI_DIR = Path(os.getenv("WEB_UI_DIR", Path.cwd() / "web-ui"))
WEB_UI_DIR = Path(os.getenv("WEB_UI_DIR", Path.cwd() / "web-ui")) # Ensure WEB_UI_DIR is a Path object
UI_PORT = int(os.getenv("UI_PORT", 7788))
UI_URL = f"http://127.0.0.1:{UI_PORT}"
REMOTE_DEBUGGING_PORT = int(os.getenv("REMOTE_DEBUGGING_PORT", 9222))
LOG_DIR = Path(os.getenv("LOG_DIR", "logs")) # Directory for logs, default 'logs' subdir
LOG_FILE_NAME = os.getenv("LOG_FILE_NAME", "AutoPyBOT.log")
LOG_FILE_PATH = LOG_DIR / LOG_FILE_NAME
# --- Log Directory (Improved) ---
# 1. User's Documents Directory (Recommended):
LOG_DIR = Path.home() / "Documents" / "AutoPyBOT" / "logs"
# 2. Application's Directory (Alternative):
# if getattr(sys, 'frozen', False): # Check if running as a bundled executable
# exe_dir = Path(sys.executable).parent
# else:
# exe_dir = Path.cwd()
# LOG_DIR = exe_dir / "logs"
# LOG_FILE_NAME = os.getenv("LOG_FILE_NAME", "AutoPyBOT.log")
# LOG_FILE_PATH = LOG_DIR / LOG_FILE_NAME
# Ensure Log Directory Exists
LOG_DIR.mkdir(parents=True, exist_ok=True) # Create the directory
WEBUI_PY_ORIGINAL_EMBEDDED = "<BASE64_ENCODED_webui.py.original_CONTENT>"
WEBUI_PY_TEMPLATE_EMBEDDED = "<BASE64_ENCODED_webui.py.template_CONTENT>"
WEBUI_PY_INITIAL_EMBEDDED = "<BASE64_ENCODED_INITIAL_webui.py_CONTENT>" # Embed initial webui.py as well
webui_py_original_path = WEB_UI_DIR / "webui.py.original"
webui_py_template_path = WEB_UI_DIR / "webui.py.template"
webui_py_path = WEB_UI_DIR / "webui.py"
webui_py_original_abs = str(webui_py_original_path.resolve()) # Get absolute path
webui_py_template_abs = str(webui_py_template_path.resolve()) # Get absolute path
webui_py_abs = str(webui_py_path.resolve()) # Get absolute path
# print(f"webui_py_original_abs: {webui_py_original_abs}") # Print for verification
# print(f"webui_py_template_abs: {webui_py_template_abs}") # Print for verification
# print(f"webui_py_abs: {webui_py_abs}") # Print for verification
# --- Requirements ---
# Ideally, these would be in a separate requirements.txt file.
# For a single-file script, we keep them here for programmatic installation.
REQUIREMENTS = [
"browser-use",
"gradio",
"json-repair",
"langchain-mistralai",
"playwright",
"uv",
"python-dotenv",
"psutil",
"requests"
]
# --- Logging Configuration ---
LOG_DIR.mkdir(parents=True, exist_ok=True) # Ensure log directory exists
logging.basicConfig(filename=LOG_FILE_PATH, level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logging.info(f"Log file path: {LOG_FILE_PATH}")
print(f"Log file path: {LOG_FILE_PATH}")
# --- Helper Functions ---
def is_admin():
"""Check if the current process has administrator privileges."""
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except Exception as e:
logging.error(f"Admin check failed: {e}")
return False
def ask_close_chrome():
"""Use Tkinter to show a pop-up confirmation for closing Chrome instances."""
root = tk.Tk()
root.withdraw() # Hide the main window
response = messagebox.askyesno("Close Chrome?", "Do you want to close all running Chrome instances?")
root.destroy()
return response
def close_running_chrome_instances():
"""Detect and close all running Chrome instances after user confirmation via GUI."""
try:
chrome_processes = [p for p in psutil.process_iter(attrs=['pid', 'name']) if 'chrome' in p.info['name'].lower()]
if not chrome_processes:
logging.info("✅ No running Chrome instances detected.")
return
# ✅ Use GUI pop-up instead of command-line input
user_choice = ask_close_chrome()
if user_choice: # If user clicks "Yes"
logging.info("🔴 Closing all running Chrome instances...")
for proc in chrome_processes:
try:
proc.terminate()
proc.wait(timeout=5)
logging.info(f"✅ Successfully terminated Chrome process {proc.info['pid']}")
except psutil.NoSuchProcess:
logging.warning(f"⚠️ Process {proc.info['pid']} already closed.")
except psutil.TimeoutExpired:
logging.warning(f"⚠️ Process {proc.info['pid']} did not terminate in time.")
logging.info("✅ All Chrome instances have been closed successfully.")
else:
logging.info("⚠️ User declined to close running Chrome instances.")
print("Skipping termination. Automation may not work as expected!")
except Exception as e:
logging.error(f"❌ Error closing running Chrome instances: {e}")
def check_git_installed():
"""Ensure that Git is installed on the system."""
try:
subprocess.check_call(["git", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
logging.info("Git is installed.")
except FileNotFoundError:
logging.error("Git is not installed. Please install Git and try again.")
sys.exit(1)
except Exception as e:
logging.error(f"Git check failed with an unexpected error: {e}")
sys.exit(1)
def clone_web_ui():
"""Clone the web-ui repository. ONLY CLONES, NO MODIFICATIONS HERE."""
try:
if not WEB_UI_DIR.exists():
logging.info(f"Cloning web-ui repository from {WEB_UI_REPO_URL}...")
subprocess.check_call(["git", "clone", WEB_UI_REPO_URL, str(WEB_UI_DIR)])
logging.info("Web-ui repository cloned successfully.")
else:
logging.info("Web-ui repository already exists.")
webui_py_path = WEB_UI_DIR / "webui.py"
# Decode and write embedded original file
webui_original_content = base64.b64decode("aW1wb3J0IHBkYgppbXBvcnQgbG9nZ2luZwoKZnJvbSBkb3RlbnYgaW1wb3J0IGxvYWRfZG90ZW52Cgpsb2FkX2RvdGVudigpCmltcG9ydCBvcwppbXBvcnQgZ2xvYgppbXBvcnQgYXN5bmNpbwppbXBvcnQgYXJncGFyc2UKaW1wb3J0IG9zCgpsb2dnZXIgPSBsb2dnaW5nLmdldExvZ2dlcihfX25hbWVfXykKCmltcG9ydCBncmFkaW8gYXMgZ3IKCmZyb20gYnJvd3Nlcl91c2UuYWdlbnQuc2VydmljZSBpbXBvcnQgQWdlbnQKZnJvbSBwbGF5d3JpZ2h0LmFzeW5jX2FwaSBpbXBvcnQgYXN5bmNfcGxheXdyaWdodApmcm9tIGJyb3dzZXJfdXNlLmJyb3dzZXIuYnJvd3NlciBpbXBvcnQgQnJvd3NlciwgQnJvd3NlckNvbmZpZwpmcm9tIGJyb3dzZXJfdXNlLmJyb3dzZXIuY29udGV4dCBpbXBvcnQgKAogICAgQnJvd3NlckNvbnRleHRDb25maWcsCiAgICBCcm93c2VyQ29udGV4dFdpbmRvd1NpemUsCikKZnJvbSBsYW5nY2hhaW5fb2xsYW1hIGltcG9ydCBDaGF0T2xsYW1hCmZyb20gcGxheXdyaWdodC5hc3luY19hcGkgaW1wb3J0IGFzeW5jX3BsYXl3cmlnaHQKZnJvbSBzcmMudXRpbHMuYWdlbnRfc3RhdGUgaW1wb3J0IEFnZW50U3RhdGUKCmZyb20gc3JjLnV0aWxzIGltcG9ydCB1dGlscwpmcm9tIHNyYy5hZ2VudC5jdXN0b21fYWdlbnQgaW1wb3J0IEN1c3RvbUFnZW50CmZyb20gc3JjLmJyb3dzZXIuY3VzdG9tX2Jyb3dzZXIgaW1wb3J0IEN1c3RvbUJyb3dzZXIKZnJvbSBzcmMuYWdlbnQuY3VzdG9tX3Byb21wdHMgaW1wb3J0IEN1c3RvbVN5c3RlbVByb21wdCwgQ3VzdG9tQWdlbnRNZXNzYWdlUHJvbXB0CmZyb20gc3JjLmJyb3dzZXIuY3VzdG9tX2NvbnRleHQgaW1wb3J0IEJyb3dzZXJDb250ZXh0Q29uZmlnLCBDdXN0b21Ccm93c2VyQ29udGV4dApmcm9tIHNyYy5jb250cm9sbGVyLmN1c3RvbV9jb250cm9sbGVyIGltcG9ydCBDdXN0b21Db250cm9sbGVyCmZyb20gZ3JhZGlvLnRoZW1lcyBpbXBvcnQgQ2l0cnVzLCBEZWZhdWx0LCBHbGFzcywgTW9ub2Nocm9tZSwgT2NlYW4sIE9yaWdpbiwgU29mdCwgQmFzZQpmcm9tIHNyYy51dGlscy5kZWZhdWx0X2NvbmZpZ19zZXR0aW5ncyBpbXBvcnQgZGVmYXVsdF9jb25maWcsIGxvYWRfY29uZmlnX2Zyb21fZmlsZSwgc2F2ZV9jb25maWdfdG9fZmlsZSwgc2F2ZV9jdXJyZW50X2NvbmZpZywgdXBkYXRlX3VpX2Zyb21fY29uZmlnCmZyb20gc3JjLnV0aWxzLnV0aWxzIGltcG9ydCB1cGRhdGVfbW9kZWxfZHJvcGRvd24sIGdldF9sYXRlc3RfZmlsZXMsIGNhcHR1cmVfc2NyZWVuc2hvdAoKCiMgR2xvYmFsIHZhcmlhYmxlcyBmb3IgcGVyc2lzdGVuY2UKX2dsb2JhbF9icm93c2VyID0gTm9uZQpfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCA9IE5vbmUKCiMgQ3JlYXRlIHRoZSBnbG9iYWwgYWdlbnQgc3RhdGUgaW5zdGFuY2UKX2dsb2JhbF9hZ2VudF9zdGF0ZSA9IEFnZW50U3RhdGUoKQoKYXN5bmMgZGVmIHN0b3BfYWdlbnQoKToKICAgICIiIlJlcXVlc3QgdGhlIGFnZW50IHRvIHN0b3AgYW5kIHVwZGF0ZSBVSSB3aXRoIGVuaGFuY2VkIGZlZWRiYWNrIiIiCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQsIF9nbG9iYWxfYnJvd3NlcgoKICAgIHRyeToKICAgICAgICAjIFJlcXVlc3Qgc3RvcAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUucmVxdWVzdF9zdG9wKCkKCiAgICAgICAgIyBVcGRhdGUgVUkgaW1tZWRpYXRlbHkKICAgICAgICBtZXNzYWdlID0gIlN0b3AgcmVxdWVzdGVkIC0gdGhlIGFnZW50IHdpbGwgaGFsdCBhdCB0aGUgbmV4dCBzYWZlIHBvaW50IgogICAgICAgIGxvZ2dlci5pbmZvKGYi8J+bkSB7bWVzc2FnZX0iKQoKICAgICAgICAjIFJldHVybiBVSSB1cGRhdGVzCiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgbWVzc2FnZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBlcnJvcnNfb3V0cHV0CiAgICAgICAgICAgIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcHBpbmcuLi4iLCBpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHN0b3BfYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1GYWxzZSksICAgICAgICAgICAgICAgICAgICAgICMgcnVuX2J1dHRvbgogICAgICAgICkKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBlcnJvcl9tc2cgPSBmIkVycm9yIGR1cmluZyBzdG9wOiB7c3RyKGUpfSIKICAgICAgICBsb2dnZXIuZXJyb3IoZXJyb3JfbXNnKQogICAgICAgIHJldHVybiAoCiAgICAgICAgICAgIGVycm9yX21zZywKICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKQogICAgICAgICkKICAgICAgICAKYXN5bmMgZGVmIHN0b3BfcmVzZWFyY2hfYWdlbnQoKToKICAgICIiIlJlcXVlc3QgdGhlIGFnZW50IHRvIHN0b3AgYW5kIHVwZGF0ZSBVSSB3aXRoIGVuaGFuY2VkIGZlZWRiYWNrIiIiCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQsIF9nbG9iYWxfYnJvd3NlcgoKICAgIHRyeToKICAgICAgICAjIFJlcXVlc3Qgc3RvcAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUucmVxdWVzdF9zdG9wKCkKCiAgICAgICAgIyBVcGRhdGUgVUkgaW1tZWRpYXRlbHkKICAgICAgICBtZXNzYWdlID0gIlN0b3AgcmVxdWVzdGVkIC0gdGhlIGFnZW50IHdpbGwgaGFsdCBhdCB0aGUgbmV4dCBzYWZlIHBvaW50IgogICAgICAgIGxvZ2dlci5pbmZvKGYi8J+bkSB7bWVzc2FnZX0iKQoKICAgICAgICAjIFJldHVybiBVSSB1cGRhdGVzCiAgICAgICAgcmV0dXJuICggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZXJyb3JzX291dHB1dAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3BwaW5nLi4uIiwgaW50ZXJhY3RpdmU9RmFsc2UpLCAgIyBzdG9wX2J1dHRvbgogICAgICAgICAgICBnci51cGRhdGUoaW50ZXJhY3RpdmU9RmFsc2UpLCAgICAgICAgICAgICAgICAgICAgICAjIHJ1bl9idXR0b24KICAgICAgICApCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgZXJyb3JfbXNnID0gZiJFcnJvciBkdXJpbmcgc3RvcDoge3N0cihlKX0iCiAgICAgICAgbG9nZ2VyLmVycm9yKGVycm9yX21zZykKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwKICAgICAgICAgICAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpCiAgICAgICAgKQoKYXN5bmMgZGVmIHJ1bl9icm93c2VyX2FnZW50KAogICAgICAgIGFnZW50X3R5cGUsCiAgICAgICAgbGxtX3Byb3ZpZGVyLAogICAgICAgIGxsbV9tb2RlbF9uYW1lLAogICAgICAgIGxsbV90ZW1wZXJhdHVyZSwKICAgICAgICBsbG1fYmFzZV91cmwsCiAgICAgICAgbGxtX2FwaV9rZXksCiAgICAgICAgdXNlX293bl9icm93c2VyLAogICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgIGhlYWRsZXNzLAogICAgICAgIGRpc2FibGVfc2VjdXJpdHksCiAgICAgICAgd2luZG93X3csCiAgICAgICAgd2luZG93X2gsCiAgICAgICAgc2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgICAgICBzYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgZW5hYmxlX3JlY29yZGluZywKICAgICAgICB0YXNrLAogICAgICAgIGFkZF9pbmZvcywKICAgICAgICBtYXhfc3RlcHMsCiAgICAgICAgdXNlX3Zpc2lvbiwKICAgICAgICBtYXhfYWN0aW9uc19wZXJfc3RlcCwKICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kCik6CiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZQogICAgX2dsb2JhbF9hZ2VudF9zdGF0ZS5jbGVhcl9zdG9wKCkgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdHMKCiAgICB0cnk6CiAgICAgICAgIyBEaXNhYmxlIHJlY29yZGluZyBpZiB0aGUgY2hlY2tib3ggaXMgdW5jaGVja2VkCiAgICAgICAgaWYgbm90IGVuYWJsZV9yZWNvcmRpbmc6CiAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGggPSBOb25lCgogICAgICAgICMgRW5zdXJlIHRoZSByZWNvcmRpbmcgZGlyZWN0b3J5IGV4aXN0cyBpZiByZWNvcmRpbmcgaXMgZW5hYmxlZAogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIG9zLm1ha2VkaXJzKHNhdmVfcmVjb3JkaW5nX3BhdGgsIGV4aXN0X29rPVRydWUpCgogICAgICAgICMgR2V0IHRoZSBsaXN0IG9mIGV4aXN0aW5nIHZpZGVvcyBiZWZvcmUgdGhlIGFnZW50IHJ1bnMKICAgICAgICBleGlzdGluZ192aWRlb3MgPSBzZXQoKQogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIGV4aXN0aW5nX3ZpZGVvcyA9IHNldCgKICAgICAgICAgICAgICAgIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW21NXVtwUF00IikpCiAgICAgICAgICAgICAgICArIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW3dXXVtlRV1bYkJdW21NXSIpKQogICAgICAgICAgICApCgogICAgICAgICMgUnVuIHRoZSBhZ2VudAogICAgICAgIGxsbSA9IHV0aWxzLmdldF9sbG1fbW9kZWwoCiAgICAgICAgICAgIHByb3ZpZGVyPWxsbV9wcm92aWRlciwKICAgICAgICAgICAgbW9kZWxfbmFtZT1sbG1fbW9kZWxfbmFtZSwKICAgICAgICAgICAgdGVtcGVyYXR1cmU9bGxtX3RlbXBlcmF0dXJlLAogICAgICAgICAgICBiYXNlX3VybD1sbG1fYmFzZV91cmwsCiAgICAgICAgICAgIGFwaV9rZXk9bGxtX2FwaV9rZXksCiAgICAgICAgKQogICAgICAgIGlmIGFnZW50X3R5cGUgPT0gIm9yZyI6CiAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwgZXJyb3JzLCBtb2RlbF9hY3Rpb25zLCBtb2RlbF90aG91Z2h0cywgdHJhY2VfZmlsZSwgaGlzdG9yeV9maWxlID0gYXdhaXQgcnVuX29yZ19hZ2VudCgKICAgICAgICAgICAgICAgIGxsbT1sbG0sCiAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXI9dXNlX293bl9icm93c2VyLAogICAgICAgICAgICAgICAga2VlcF9icm93c2VyX29wZW49a2VlcF9icm93c2VyX29wZW4sCiAgICAgICAgICAgICAgICBoZWFkbGVzcz1oZWFkbGVzcywKICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgIHdpbmRvd193PXdpbmRvd193LAogICAgICAgICAgICAgICAgd2luZG93X2g9d2luZG93X2gsCiAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aD1zYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgICAgICAgICAgICAgIHNhdmVfdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgICAgICAgICB0YXNrPXRhc2ssCiAgICAgICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgKQogICAgICAgIGVsaWYgYWdlbnRfdHlwZSA9PSAiY3VzdG9tIjoKICAgICAgICAgICAgZmluYWxfcmVzdWx0LCBlcnJvcnMsIG1vZGVsX2FjdGlvbnMsIG1vZGVsX3Rob3VnaHRzLCB0cmFjZV9maWxlLCBoaXN0b3J5X2ZpbGUgPSBhd2FpdCBydW5fY3VzdG9tX2FnZW50KAogICAgICAgICAgICAgICAgbGxtPWxsbSwKICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAgICAgICAgICBrZWVwX2Jyb3dzZXJfb3Blbj1rZWVwX2Jyb3dzZXJfb3BlbiwKICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICAgICAgd2luZG93X3c9d2luZG93X3csCiAgICAgICAgICAgICAgICB3aW5kb3dfaD13aW5kb3dfaCwKICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICAgICAgICAgIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoPXNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgICAgICAgICAgc2F2ZV90cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCwKICAgICAgICAgICAgICAgIHRhc2s9dGFzaywKICAgICAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoZiJJbnZhbGlkIGFnZW50IHR5cGU6IHthZ2VudF90eXBlfSIpCgogICAgICAgICMgR2V0IHRoZSBsaXN0IG9mIHZpZGVvcyBhZnRlciB0aGUgYWdlbnQgcnVucyAoaWYgcmVjb3JkaW5nIGlzIGVuYWJsZWQpCiAgICAgICAgbGF0ZXN0X3ZpZGVvID0gTm9uZQogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIG5ld192aWRlb3MgPSBzZXQoCiAgICAgICAgICAgICAgICBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlttTV1bcFBdNCIpKQogICAgICAgICAgICAgICAgKyBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlt3V11bZUVdW2JCXVttTV0iKSkKICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBuZXdfdmlkZW9zIC0gZXhpc3RpbmdfdmlkZW9zOgogICAgICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvID0gbGlzdChuZXdfdmlkZW9zIC0gZXhpc3RpbmdfdmlkZW9zKVswXSAgIyBHZXQgdGhlIGZpcnN0IG5ldyB2aWRlbwoKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICBmaW5hbF9yZXN1bHQsCiAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgbW9kZWxfYWN0aW9ucywKICAgICAgICAgICAgbW9kZWxfdGhvdWdodHMsCiAgICAgICAgICAgIGxhdGVzdF92aWRlbywKICAgICAgICAgICAgdHJhY2VfZmlsZSwKICAgICAgICAgICAgaGlzdG9yeV9maWxlLAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwgICMgUmUtZW5hYmxlIHN0b3AgYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKSAgICAjIFJlLWVuYWJsZSBydW4gYnV0dG9uCiAgICAgICAgKQoKICAgIGV4Y2VwdCBnci5FcnJvcjoKICAgICAgICByYWlzZQoKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBpbXBvcnQgdHJhY2ViYWNrCiAgICAgICAgdHJhY2ViYWNrLnByaW50X2V4YygpCiAgICAgICAgZXJyb3JzID0gc3RyKGUpICsgIlxuIiArIHRyYWNlYmFjay5mb3JtYXRfZXhjKCkKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAnJywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmluYWxfcmVzdWx0CiAgICAgICAgICAgIGVycm9ycywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBlcnJvcnMKICAgICAgICAgICAgJycsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1vZGVsX2FjdGlvbnMKICAgICAgICAgICAgJycsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1vZGVsX3Rob3VnaHRzCiAgICAgICAgICAgIE5vbmUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBsYXRlc3RfdmlkZW8KICAgICAgICAgICAgTm9uZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGhpc3RvcnlfZmlsZQogICAgICAgICAgICBOb25lLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdHJhY2VfZmlsZQogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwgICMgUmUtZW5hYmxlIHN0b3AgYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKSAgICAjIFJlLWVuYWJsZSBydW4gYnV0dG9uCiAgICAgICAgKQoKCmFzeW5jIGRlZiBydW5fb3JnX2FnZW50KAogICAgICAgIGxsbSwKICAgICAgICB1c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAga2VlcF9icm93c2VyX29wZW4sCiAgICAgICAgaGVhZGxlc3MsCiAgICAgICAgZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICB3aW5kb3dfdywKICAgICAgICB3aW5kb3dfaCwKICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoLAogICAgICAgIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgIHNhdmVfdHJhY2VfcGF0aCwKICAgICAgICB0YXNrLAogICAgICAgIG1heF9zdGVwcywKICAgICAgICB1c2VfdmlzaW9uLAogICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2QKKToKICAgIHRyeToKICAgICAgICBnbG9iYWwgX2dsb2JhbF9icm93c2VyLCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwgX2dsb2JhbF9hZ2VudF9zdGF0ZQogICAgICAgIAogICAgICAgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUuY2xlYXJfc3RvcCgpCgogICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3MgPSBbZiItLXdpbmRvdy1zaXplPXt3aW5kb3dfd30se3dpbmRvd19ofSJdCiAgICAgICAgaWYgdXNlX293bl9icm93c2VyOgogICAgICAgICAgICBjaHJvbWVfcGF0aCA9IG9zLmdldGVudigiQ0hST01FX1BBVEgiLCBOb25lKQogICAgICAgICAgICBpZiBjaHJvbWVfcGF0aCA9PSAiIjoKICAgICAgICAgICAgICAgIGNocm9tZV9wYXRoID0gTm9uZQogICAgICAgICAgICBjaHJvbWVfdXNlcl9kYXRhID0gb3MuZ2V0ZW52KCJDSFJPTUVfVVNFUl9EQVRBIiwgTm9uZSkKICAgICAgICAgICAgaWYgY2hyb21lX3VzZXJfZGF0YToKICAgICAgICAgICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3MgKz0gW2YiLS11c2VyLWRhdGEtZGlyPXtjaHJvbWVfdXNlcl9kYXRhfSJdCiAgICAgICAgZWxzZToKICAgICAgICAgICAgY2hyb21lX3BhdGggPSBOb25lCiAgICAgICAgICAgIAogICAgICAgIGlmIF9nbG9iYWxfYnJvd3NlciBpcyBOb25lOgogICAgICAgICAgICBfZ2xvYmFsX2Jyb3dzZXIgPSBCcm93c2VyKAogICAgICAgICAgICAgICAgY29uZmlnPUJyb3dzZXJDb25maWcoCiAgICAgICAgICAgICAgICAgICAgaGVhZGxlc3M9aGVhZGxlc3MsCiAgICAgICAgICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICAgICAgICAgIGNocm9tZV9pbnN0YW5jZV9wYXRoPWNocm9tZV9wYXRoLAogICAgICAgICAgICAgICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3M9ZXh0cmFfY2hyb21pdW1fYXJncywKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgKQoKICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCBpcyBOb25lOgogICAgICAgICAgICBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCA9IGF3YWl0IF9nbG9iYWxfYnJvd3Nlci5uZXdfY29udGV4dCgKICAgICAgICAgICAgICAgIGNvbmZpZz1Ccm93c2VyQ29udGV4dENvbmZpZygKICAgICAgICAgICAgICAgICAgICB0cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCBpZiBzYXZlX3RyYWNlX3BhdGggZWxzZSBOb25lLAogICAgICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCBpZiBzYXZlX3JlY29yZGluZ19wYXRoIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICBub192aWV3cG9ydD1GYWxzZSwKICAgICAgICAgICAgICAgICAgICBicm93c2VyX3dpbmRvd19zaXplPUJyb3dzZXJDb250ZXh0V2luZG93U2l6ZSgKICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9d2luZG93X3csIGhlaWdodD13aW5kb3dfaAogICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgYWdlbnQgPSBBZ2VudCgKICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICBsbG09bGxtLAogICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgIGJyb3dzZXI9X2dsb2JhbF9icm93c2VyLAogICAgICAgICAgICBicm93c2VyX2NvbnRleHQ9X2dsb2JhbF9icm93c2VyX2NvbnRleHQsCiAgICAgICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwPW1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICApCiAgICAgICAgaGlzdG9yeSA9IGF3YWl0IGFnZW50LnJ1bihtYXhfc3RlcHM9bWF4X3N0ZXBzKQoKICAgICAgICBoaXN0b3J5X2ZpbGUgPSBvcy5wYXRoLmpvaW4oc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsIGYie2FnZW50LmFnZW50X2lkfS5qc29uIikKICAgICAgICBhZ2VudC5zYXZlX2hpc3RvcnkoaGlzdG9yeV9maWxlKQoKICAgICAgICBmaW5hbF9yZXN1bHQgPSBoaXN0b3J5LmZpbmFsX3Jlc3VsdCgpCiAgICAgICAgZXJyb3JzID0gaGlzdG9yeS5lcnJvcnMoKQogICAgICAgIG1vZGVsX2FjdGlvbnMgPSBoaXN0b3J5Lm1vZGVsX2FjdGlvbnMoKQogICAgICAgIG1vZGVsX3Rob3VnaHRzID0gaGlzdG9yeS5tb2RlbF90aG91Z2h0cygpCgogICAgICAgIHRyYWNlX2ZpbGUgPSBnZXRfbGF0ZXN0X2ZpbGVzKHNhdmVfdHJhY2VfcGF0aCkKCiAgICAgICAgcmV0dXJuIGZpbmFsX3Jlc3VsdCwgZXJyb3JzLCBtb2RlbF9hY3Rpb25zLCBtb2RlbF90aG91Z2h0cywgdHJhY2VfZmlsZS5nZXQoJy56aXAnKSwgaGlzdG9yeV9maWxlCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgaW1wb3J0IHRyYWNlYmFjawogICAgICAgIHRyYWNlYmFjay5wcmludF9leGMoKQogICAgICAgIGVycm9ycyA9IHN0cihlKSArICJcbiIgKyB0cmFjZWJhY2suZm9ybWF0X2V4YygpCiAgICAgICAgcmV0dXJuICcnLCBlcnJvcnMsICcnLCAnJywgTm9uZSwgTm9uZQogICAgZmluYWxseToKICAgICAgICAjIEhhbmRsZSBjbGVhbnVwIGJhc2VkIG9uIHBlcnNpc3RlbmNlIGNvbmZpZ3VyYXRpb24KICAgICAgICBpZiBub3Qga2VlcF9icm93c2VyX29wZW46CiAgICAgICAgICAgIGlmIF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0OgogICAgICAgICAgICAgICAgYXdhaXQgX2dsb2JhbF9icm93c2VyX2NvbnRleHQuY2xvc2UoKQogICAgICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBOb25lCgogICAgICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXI6CiAgICAgICAgICAgICAgICBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXIuY2xvc2UoKQogICAgICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyID0gTm9uZQoKYXN5bmMgZGVmIHJ1bl9jdXN0b21fYWdlbnQoCiAgICAgICAgbGxtLAogICAgICAgIHVzZV9vd25fYnJvd3NlciwKICAgICAgICBrZWVwX2Jyb3dzZXJfb3BlbiwKICAgICAgICBoZWFkbGVzcywKICAgICAgICBkaXNhYmxlX3NlY3VyaXR5LAogICAgICAgIHdpbmRvd193LAogICAgICAgIHdpbmRvd19oLAogICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgc2F2ZV90cmFjZV9wYXRoLAogICAgICAgIHRhc2ssCiAgICAgICAgYWRkX2luZm9zLAogICAgICAgIG1heF9zdGVwcywKICAgICAgICB1c2VfdmlzaW9uLAogICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2QKKToKICAgIHRyeToKICAgICAgICBnbG9iYWwgX2dsb2JhbF9icm93c2VyLCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwgX2dsb2JhbF9hZ2VudF9zdGF0ZQoKICAgICAgICAjIENsZWFyIGFueSBwcmV2aW91cyBzdG9wIHJlcXVlc3QKICAgICAgICBfZ2xvYmFsX2FnZW50X3N0YXRlLmNsZWFyX3N0b3AoKQoKICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzID0gW2YiLS13aW5kb3ctc2l6ZT17d2luZG93X3d9LHt3aW5kb3dfaH0iXQogICAgICAgIGlmIHVzZV9vd25fYnJvd3NlcjoKICAgICAgICAgICAgY2hyb21lX3BhdGggPSBvcy5nZXRlbnYoIkNIUk9NRV9QQVRIIiwgTm9uZSkKICAgICAgICAgICAgaWYgY2hyb21lX3BhdGggPT0gIiI6CiAgICAgICAgICAgICAgICBjaHJvbWVfcGF0aCA9IE5vbmUKICAgICAgICAgICAgY2hyb21lX3VzZXJfZGF0YSA9IG9zLmdldGVudigiQ0hST01FX1VTRVJfREFUQSIsIE5vbmUpCiAgICAgICAgICAgIGlmIGNocm9tZV91c2VyX2RhdGE6CiAgICAgICAgICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzICs9IFtmIi0tdXNlci1kYXRhLWRpcj17Y2hyb21lX3VzZXJfZGF0YX0iXQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGNocm9tZV9wYXRoID0gTm9uZQoKICAgICAgICBjb250cm9sbGVyID0gQ3VzdG9tQ29udHJvbGxlcigpCgogICAgICAgICMgSW5pdGlhbGl6ZSBnbG9iYWwgYnJvd3NlciBpZiBuZWVkZWQKICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXIgaXMgTm9uZToKICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyID0gQ3VzdG9tQnJvd3NlcigKICAgICAgICAgICAgICAgIGNvbmZpZz1Ccm93c2VyQ29uZmlnKAogICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgICAgICBjaHJvbWVfaW5zdGFuY2VfcGF0aD1jaHJvbWVfcGF0aCwKICAgICAgICAgICAgICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzPWV4dHJhX2Nocm9taXVtX2FyZ3MsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKCiAgICAgICAgaWYgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgaXMgTm9uZToKICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXIubmV3X2NvbnRleHQoCiAgICAgICAgICAgICAgICBjb25maWc9QnJvd3NlckNvbnRleHRDb25maWcoCiAgICAgICAgICAgICAgICAgICAgdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGggaWYgc2F2ZV90cmFjZV9wYXRoIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGggaWYgc2F2ZV9yZWNvcmRpbmdfcGF0aCBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgbm9fdmlld3BvcnQ9RmFsc2UsCiAgICAgICAgICAgICAgICAgICAgYnJvd3Nlcl93aW5kb3dfc2l6ZT1Ccm93c2VyQ29udGV4dFdpbmRvd1NpemUoCiAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPXdpbmRvd193LCBoZWlnaHQ9d2luZG93X2gKICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICApCiAgICAgICAgICAgIAogICAgICAgICMgQ3JlYXRlIGFuZCBydW4gYWdlbnQKICAgICAgICBhZ2VudCA9IEN1c3RvbUFnZW50KAogICAgICAgICAgICB0YXNrPXRhc2ssCiAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgIHVzZV92aXNpb249dXNlX3Zpc2lvbiwKICAgICAgICAgICAgbGxtPWxsbSwKICAgICAgICAgICAgYnJvd3Nlcj1fZ2xvYmFsX2Jyb3dzZXIsCiAgICAgICAgICAgIGJyb3dzZXJfY29udGV4dD1fZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwKICAgICAgICAgICAgY29udHJvbGxlcj1jb250cm9sbGVyLAogICAgICAgICAgICBzeXN0ZW1fcHJvbXB0X2NsYXNzPUN1c3RvbVN5c3RlbVByb21wdCwKICAgICAgICAgICAgYWdlbnRfcHJvbXB0X2NsYXNzPUN1c3RvbUFnZW50TWVzc2FnZVByb21wdCwKICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgIGFnZW50X3N0YXRlPV9nbG9iYWxfYWdlbnRfc3RhdGUsCiAgICAgICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2Q9dG9vbF9jYWxsaW5nX21ldGhvZAogICAgICAgICkKICAgICAgICBoaXN0b3J5ID0gYXdhaXQgYWdlbnQucnVuKG1heF9zdGVwcz1tYXhfc3RlcHMpCgogICAgICAgIGhpc3RvcnlfZmlsZSA9IG9zLnBhdGguam9pbihzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwgZiJ7YWdlbnQuYWdlbnRfaWR9Lmpzb24iKQogICAgICAgIGFnZW50LnNhdmVfaGlzdG9yeShoaXN0b3J5X2ZpbGUpCgogICAgICAgIGZpbmFsX3Jlc3VsdCA9IGhpc3RvcnkuZmluYWxfcmVzdWx0KCkKICAgICAgICBlcnJvcnMgPSBoaXN0b3J5LmVycm9ycygpCiAgICAgICAgbW9kZWxfYWN0aW9ucyA9IGhpc3RvcnkubW9kZWxfYWN0aW9ucygpCiAgICAgICAgbW9kZWxfdGhvdWdodHMgPSBoaXN0b3J5Lm1vZGVsX3Rob3VnaHRzKCkKCiAgICAgICAgdHJhY2VfZmlsZSA9IGdldF9sYXRlc3RfZmlsZXMoc2F2ZV90cmFjZV9wYXRoKSAgICAgICAgCgogICAgICAgIHJldHVybiBmaW5hbF9yZXN1bHQsIGVycm9ycywgbW9kZWxfYWN0aW9ucywgbW9kZWxfdGhvdWdodHMsIHRyYWNlX2ZpbGUuZ2V0KCcuemlwJyksIGhpc3RvcnlfZmlsZQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgIGltcG9ydCB0cmFjZWJhY2sKICAgICAgICB0cmFjZWJhY2sucHJpbnRfZXhjKCkKICAgICAgICBlcnJvcnMgPSBzdHIoZSkgKyAiXG4iICsgdHJhY2ViYWNrLmZvcm1hdF9leGMoKQogICAgICAgIHJldHVybiAnJywgZXJyb3JzLCAnJywgJycsIE5vbmUsIE5vbmUKICAgIGZpbmFsbHk6CiAgICAgICAgIyBIYW5kbGUgY2xlYW51cCBiYXNlZCBvbiBwZXJzaXN0ZW5jZSBjb25maWd1cmF0aW9uCiAgICAgICAgaWYgbm90IGtlZXBfYnJvd3Nlcl9vcGVuOgogICAgICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dDoKICAgICAgICAgICAgICAgIGF3YWl0IF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0LmNsb3NlKCkKICAgICAgICAgICAgICAgIF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0ID0gTm9uZQoKICAgICAgICAgICAgaWYgX2dsb2JhbF9icm93c2VyOgogICAgICAgICAgICAgICAgYXdhaXQgX2dsb2JhbF9icm93c2VyLmNsb3NlKCkKICAgICAgICAgICAgICAgIF9nbG9iYWxfYnJvd3NlciA9IE5vbmUKCmFzeW5jIGRlZiBydW5fd2l0aF9zdHJlYW0oCiAgICBhZ2VudF90eXBlLAogICAgbGxtX3Byb3ZpZGVyLAogICAgbGxtX21vZGVsX25hbWUsCiAgICBsbG1fdGVtcGVyYXR1cmUsCiAgICBsbG1fYmFzZV91cmwsCiAgICBsbG1fYXBpX2tleSwKICAgIHVzZV9vd25fYnJvd3NlciwKICAgIGtlZXBfYnJvd3Nlcl9vcGVuLAogICAgaGVhZGxlc3MsCiAgICBkaXNhYmxlX3NlY3VyaXR5LAogICAgd2luZG93X3csCiAgICB3aW5kb3dfaCwKICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgIHNhdmVfdHJhY2VfcGF0aCwKICAgIGVuYWJsZV9yZWNvcmRpbmcsCiAgICB0YXNrLAogICAgYWRkX2luZm9zLAogICAgbWF4X3N0ZXBzLAogICAgdXNlX3Zpc2lvbiwKICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgdG9vbF9jYWxsaW5nX21ldGhvZAopOgogICAgZ2xvYmFsIF9nbG9iYWxfYWdlbnRfc3RhdGUKICAgIHN0cmVhbV92dyA9IDgwCiAgICBzdHJlYW1fdmggPSBpbnQoODAgKiB3aW5kb3dfaCAvLyB3aW5kb3dfdykKICAgIGlmIG5vdCBoZWFkbGVzczoKICAgICAgICByZXN1bHQgPSBhd2FpdCBydW5fYnJvd3Nlcl9hZ2VudCgKICAgICAgICAgICAgYWdlbnRfdHlwZT1hZ2VudF90eXBlLAogICAgICAgICAgICBsbG1fcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICBsbG1fbW9kZWxfbmFtZT1sbG1fbW9kZWxfbmFtZSwKICAgICAgICAgICAgbGxtX3RlbXBlcmF0dXJlPWxsbV90ZW1wZXJhdHVyZSwKICAgICAgICAgICAgbGxtX2Jhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgbGxtX2FwaV9rZXk9bGxtX2FwaV9rZXksCiAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuPWtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgICAgICBoZWFkbGVzcz1oZWFkbGVzcywKICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICB3aW5kb3dfdz13aW5kb3dfdywKICAgICAgICAgICAgd2luZG93X2g9d2luZG93X2gsCiAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGg9c2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgICAgIHNhdmVfdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgICAgIGVuYWJsZV9yZWNvcmRpbmc9ZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICBhZGRfaW5mb3M9YWRkX2luZm9zLAogICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwPW1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICApCiAgICAgICAgIyBBZGQgSFRNTCBjb250ZW50IGF0IHRoZSBzdGFydCBvZiB0aGUgcmVzdWx0IGFycmF5CiAgICAgICAgaHRtbF9jb250ZW50ID0gZiI8aDEgc3R5bGU9J3dpZHRoOntzdHJlYW1fdnd9dnc7IGhlaWdodDp7c3RyZWFtX3ZofXZoJz5Vc2luZyBicm93c2VyLi4uPC9oMT4iCiAgICAgICAgeWllbGQgW2h0bWxfY29udGVudF0gKyBsaXN0KHJlc3VsdCkKICAgIGVsc2U6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBfZ2xvYmFsX2FnZW50X3N0YXRlLmNsZWFyX3N0b3AoKQogICAgICAgICAgICAjIFJ1biB0aGUgYnJvd3NlciBhZ2VudCBpbiB0aGUgYmFja2dyb3VuZAogICAgICAgICAgICBhZ2VudF90YXNrID0gYXN5bmNpby5jcmVhdGVfdGFzaygKICAgICAgICAgICAgICAgIHJ1bl9icm93c2VyX2FnZW50KAogICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGU9YWdlbnRfdHlwZSwKICAgICAgICAgICAgICAgICAgICBsbG1fcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICAgICAgICAgIGxsbV9tb2RlbF9uYW1lPWxsbV9tb2RlbF9uYW1lLAogICAgICAgICAgICAgICAgICAgIGxsbV90ZW1wZXJhdHVyZT1sbG1fdGVtcGVyYXR1cmUsCiAgICAgICAgICAgICAgICAgICAgbGxtX2Jhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgICAgICAgICBsbG1fYXBpX2tleT1sbG1fYXBpX2tleSwKICAgICAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXI9dXNlX293bl9icm93c2VyLAogICAgICAgICAgICAgICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuPWtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgICAgICB3aW5kb3dfdz13aW5kb3dfdywKICAgICAgICAgICAgICAgICAgICB3aW5kb3dfaD13aW5kb3dfaCwKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGg9c2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgc2F2ZV90cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCwKICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nPWVuYWJsZV9yZWNvcmRpbmcsCiAgICAgICAgICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgICAgICAgICAgbWF4X3N0ZXBzPW1heF9zdGVwcywKICAgICAgICAgICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICAgICAgdG9vbF9jYWxsaW5nX21ldGhvZD10b29sX2NhbGxpbmdfbWV0aG9kCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKCiAgICAgICAgICAgICMgSW5pdGlhbGl6ZSB2YWx1ZXMgZm9yIHN0cmVhbWluZwogICAgICAgICAgICBodG1sX2NvbnRlbnQgPSBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPlVzaW5nIGJyb3dzZXIuLi48L2gxPiIKICAgICAgICAgICAgZmluYWxfcmVzdWx0ID0gZXJyb3JzID0gbW9kZWxfYWN0aW9ucyA9IG1vZGVsX3Rob3VnaHRzID0gIiIKICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvcyA9IHRyYWNlID0gaGlzdG9yeV9maWxlID0gTm9uZQoKCiAgICAgICAgICAgICMgUGVyaW9kaWNhbGx5IHVwZGF0ZSB0aGUgc3RyZWFtIHdoaWxlIHRoZSBhZ2VudCB0YXNrIGlzIHJ1bm5pbmcKICAgICAgICAgICAgd2hpbGUgbm90IGFnZW50X3Rhc2suZG9uZSgpOgogICAgICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgICAgIGVuY29kZWRfc2NyZWVuc2hvdCA9IGF3YWl0IGNhcHR1cmVfc2NyZWVuc2hvdChfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCkKICAgICAgICAgICAgICAgICAgICBpZiBlbmNvZGVkX3NjcmVlbnNob3QgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCA9IGYnPGltZyBzcmM9ImRhdGE6aW1hZ2UvanBlZztiYXNlNjQse2VuY29kZWRfc2NyZWVuc2hvdH0iIHN0eWxlPSJ3aWR0aDp7c3RyZWFtX3Z3fXZ3OyBoZWlnaHQ6e3N0cmVhbV92aH12aCA7IGJvcmRlcjoxcHggc29saWQgI2NjYzsiPicKICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICBodG1sX2NvbnRlbnQgPSBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPldhaXRpbmcgZm9yIGJyb3dzZXIgc2Vzc2lvbi4uLjwvaDE+IgogICAgICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCA9IGYiPGgxIHN0eWxlPSd3aWR0aDp7c3RyZWFtX3Z3fXZ3OyBoZWlnaHQ6e3N0cmVhbV92aH12aCc+V2FpdGluZyBmb3IgYnJvd3NlciBzZXNzaW9uLi4uPC9oMT4iCgogICAgICAgICAgICAgICAgaWYgX2dsb2JhbF9hZ2VudF9zdGF0ZSBhbmQgX2dsb2JhbF9hZ2VudF9zdGF0ZS5pc19zdG9wX3JlcXVlc3RlZCgpOgogICAgICAgICAgICAgICAgICAgIHlpZWxkIFsKICAgICAgICAgICAgICAgICAgICAgICAgaHRtbF9jb250ZW50LAogICAgICAgICAgICAgICAgICAgICAgICBmaW5hbF9yZXN1bHQsCiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfdGhvdWdodHMsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhdGVzdF92aWRlb3MsCiAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlLAogICAgICAgICAgICAgICAgICAgICAgICBoaXN0b3J5X2ZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcHBpbmcuLi4iLCBpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHN0b3BfYnV0dG9uCiAgICAgICAgICAgICAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHJ1bl9idXR0b24KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgeWllbGQgWwogICAgICAgICAgICAgICAgICAgICAgICBodG1sX2NvbnRlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JzLAogICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9hY3Rpb25zLAogICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cywKICAgICAgICAgICAgICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvcywKICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UsCiAgICAgICAgICAgICAgICAgICAgICAgIGhpc3RvcnlfZmlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksICAjIFJlLWVuYWJsZSBzdG9wIGJ1dHRvbgogICAgICAgICAgICAgICAgICAgICAgICBnci51cGRhdGUoaW50ZXJhY3RpdmU9VHJ1ZSkgICMgUmUtZW5hYmxlIHJ1biBidXR0b24KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICBhd2FpdCBhc3luY2lvLnNsZWVwKDAuMDUpCgogICAgICAgICAgICAjIE9uY2UgdGhlIGFnZW50IHRhc2sgY29tcGxldGVzLCBnZXQgdGhlIHJlc3VsdHMKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgcmVzdWx0ID0gYXdhaXQgYWdlbnRfdGFzawogICAgICAgICAgICAgICAgZmluYWxfcmVzdWx0LCBlcnJvcnMsIG1vZGVsX2FjdGlvbnMsIG1vZGVsX3Rob3VnaHRzLCBsYXRlc3RfdmlkZW9zLCB0cmFjZSwgaGlzdG9yeV9maWxlLCBzdG9wX2J1dHRvbiwgcnVuX2J1dHRvbiA9IHJlc3VsdAogICAgICAgICAgICBleGNlcHQgZ3IuRXJyb3I6CiAgICAgICAgICAgICAgICBmaW5hbF9yZXN1bHQgPSAiIgogICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9ucyA9ICIiCiAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cyA9ICIiCiAgICAgICAgICAgICAgICBsYXRlc3RfdmlkZW9zID0gdHJhY2UgPSBoaXN0b3J5X2ZpbGUgPSBOb25lCgogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgICAgICBlcnJvcnMgPSBmIkFnZW50IGVycm9yOiB7c3RyKGUpfSIKCiAgICAgICAgICAgIHlpZWxkIFsKICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCwKICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwKICAgICAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgICAgIG1vZGVsX2FjdGlvbnMsCiAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cywKICAgICAgICAgICAgICAgIGxhdGVzdF92aWRlb3MsCiAgICAgICAgICAgICAgICB0cmFjZSwKICAgICAgICAgICAgICAgIGhpc3RvcnlfZmlsZSwKICAgICAgICAgICAgICAgIHN0b3BfYnV0dG9uLAogICAgICAgICAgICAgICAgcnVuX2J1dHRvbgogICAgICAgICAgICBdCgogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgaW1wb3J0IHRyYWNlYmFjawogICAgICAgICAgICB5aWVsZCBbCiAgICAgICAgICAgICAgICBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPldhaXRpbmcgZm9yIGJyb3dzZXIgc2Vzc2lvbi4uLjwvaDE+IiwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgZiJFcnJvcjoge3N0cihlKX1cbnt0cmFjZWJhY2suZm9ybWF0X2V4YygpfSIsCiAgICAgICAgICAgICAgICAiIiwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgTm9uZSwKICAgICAgICAgICAgICAgIE5vbmUsCiAgICAgICAgICAgICAgICBOb25lLAogICAgICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksICAjIFJlLWVuYWJsZSBzdG9wIGJ1dHRvbgogICAgICAgICAgICAgICAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpICAgICMgUmUtZW5hYmxlIHJ1biBidXR0b24KICAgICAgICAgICAgXQoKIyBEZWZpbmUgdGhlIHRoZW1lIG1hcCBnbG9iYWxseQp0aGVtZV9tYXAgPSB7CiAgICAiRGVmYXVsdCI6IERlZmF1bHQoKSwKICAgICJTb2Z0IjogU29mdCgpLAogICAgIk1vbm9jaHJvbWUiOiBNb25vY2hyb21lKCksCiAgICAiR2xhc3MiOiBHbGFzcygpLAogICAgIk9yaWdpbiI6IE9yaWdpbigpLAogICAgIkNpdHJ1cyI6IENpdHJ1cygpLAogICAgIk9jZWFuIjogT2NlYW4oKSwKICAgICJCYXNlIjogQmFzZSgpCn0KCmFzeW5jIGRlZiBjbG9zZV9nbG9iYWxfYnJvd3NlcigpOgogICAgZ2xvYmFsIF9nbG9iYWxfYnJvd3NlciwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQKCiAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dDoKICAgICAgICBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dC5jbG9zZSgpCiAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBOb25lCgogICAgaWYgX2dsb2JhbF9icm93c2VyOgogICAgICAgIGF3YWl0IF9nbG9iYWxfYnJvd3Nlci5jbG9zZSgpCiAgICAgICAgX2dsb2JhbF9icm93c2VyID0gTm9uZQogICAgICAgIAphc3luYyBkZWYgcnVuX2RlZXBfc2VhcmNoKHJlc2VhcmNoX3Rhc2ssIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0LCBtYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwgdXNlX3Zpc2lvbiwgdXNlX293bl9icm93c2VyLCBoZWFkbGVzcyk6CiAgICBmcm9tIHNyYy51dGlscy5kZWVwX3Jlc2VhcmNoIGltcG9ydCBkZWVwX3Jlc2VhcmNoCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZQoKICAgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdAogICAgX2dsb2JhbF9hZ2VudF9zdGF0ZS5jbGVhcl9zdG9wKCkKICAgIAogICAgbGxtID0gdXRpbHMuZ2V0X2xsbV9tb2RlbCgKICAgICAgICAgICAgcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICBtb2RlbF9uYW1lPWxsbV9tb2RlbF9uYW1lLAogICAgICAgICAgICB0ZW1wZXJhdHVyZT1sbG1fdGVtcGVyYXR1cmUsCiAgICAgICAgICAgIGJhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgYXBpX2tleT1sbG1fYXBpX2tleSwKICAgICAgICApCiAgICBtYXJrZG93bl9jb250ZW50LCBmaWxlX3BhdGggPSBhd2FpdCBkZWVwX3Jlc2VhcmNoKHJlc2VhcmNoX3Rhc2ssIGxsbSwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhfc2VhcmNoX2l0ZXJhdGlvbnM9bWF4X3NlYXJjaF9pdGVyYXRpb25faW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3F1ZXJ5X251bT1tYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAKICAgIHJldHVybiBtYXJrZG93bl9jb250ZW50LCBmaWxlX3BhdGgsIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcCIsIGludGVyYWN0aXZlPVRydWUpLCAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpIAogICAgCgpkZWYgY3JlYXRlX3VpKGNvbmZpZywgdGhlbWVfbmFtZT0iT2NlYW4iKToKICAgIGNzcyA9ICIiIgogICAgLmdyYWRpby1jb250YWluZXIgewogICAgICAgIG1heC13aWR0aDogMTIwMHB4ICFpbXBvcnRhbnQ7CiAgICAgICAgbWFyZ2luOiBhdXRvICFpbXBvcnRhbnQ7CiAgICAgICAgcGFkZGluZy10b3A6IDIwcHggIWltcG9ydGFudDsKICAgIH0KICAgIC5oZWFkZXItdGV4dCB7CiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgICAgIG1hcmdpbi1ib3R0b206IDMwcHg7CiAgICB9CiAgICAudGhlbWUtc2VjdGlvbiB7CiAgICAgICAgbWFyZ2luLWJvdHRvbTogMjBweDsKICAgICAgICBwYWRkaW5nOiAxNXB4OwogICAgICAgIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgICB9CiAgICAiIiIKCiAgICB3aXRoIGdyLkJsb2NrcygKICAgICAgICAgICAgdGl0bGU9IkJyb3dzZXIgVXNlIFdlYlVJIiwgdGhlbWU9dGhlbWVfbWFwW3RoZW1lX25hbWVdLCBjc3M9Y3NzCiAgICApIGFzIGRlbW86CiAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgZ3IuTWFya2Rvd24oCiAgICAgICAgICAgICAgICAiIiIKICAgICAgICAgICAgICAgICMg8J+MkCBCcm93c2VyIFVzZSBXZWJVSQogICAgICAgICAgICAgICAgIyMjIENvbnRyb2wgeW91ciBicm93c2VyIHdpdGggQUkgYXNzaXN0YW5jZQogICAgICAgICAgICAgICAgIiIiLAogICAgICAgICAgICAgICAgZWxlbV9jbGFzc2VzPVsiaGVhZGVyLXRleHQiXSwKICAgICAgICAgICAgKQoKICAgICAgICB3aXRoIGdyLlRhYnMoKSBhcyB0YWJzOgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIuKame+4jyBBZ2VudCBTZXR0aW5ncyIsIGlkPTEpOgogICAgICAgICAgICAgICAgd2l0aCBnci5Hcm91cCgpOgogICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGUgPSBnci5SYWRpbygKICAgICAgICAgICAgICAgICAgICAgICAgWyJvcmciLCAiY3VzdG9tIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBZ2VudCBUeXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydhZ2VudF90eXBlJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IlNlbGVjdCB0aGUgdHlwZSBvZiBhZ2VudCB0byB1c2UiLAogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLkNvbHVtbigpOgogICAgICAgICAgICAgICAgICAgICAgICBtYXhfc3RlcHMgPSBnci5TbGlkZXIoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhpbXVtPTIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snbWF4X3N0ZXBzJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTWF4IFJ1biBTdGVwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJNYXhpbXVtIG51bWJlciBvZiBzdGVwcyB0aGUgYWdlbnQgd2lsbCB0YWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBtYXhfYWN0aW9uc19wZXJfc3RlcCA9IGdyLlNsaWRlcigKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW09MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGltdW09MjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ21heF9hY3Rpb25zX3Blcl9zdGVwJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTWF4IEFjdGlvbnMgcGVyIFN0ZXAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iTWF4aW11bSBudW1iZXIgb2YgYWN0aW9ucyB0aGUgYWdlbnQgd2lsbCB0YWtlIHBlciBzdGVwIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuQ29sdW1uKCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHVzZV92aXNpb24gPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJVc2UgVmlzaW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1sndXNlX3Zpc2lvbiddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iRW5hYmxlIHZpc3VhbCBwcm9jZXNzaW5nIGNhcGFiaWxpdGllcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgdG9vbF9jYWxsaW5nX21ldGhvZCA9IGdyLkRyb3Bkb3duKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlRvb2wgQ2FsbGluZyBNZXRob2QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd0b29sX2NhbGxpbmdfbWV0aG9kJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZT1UcnVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dfY3VzdG9tX3ZhbHVlPVRydWUsICAjIEFsbG93IHVzZXJzIHRvIGlucHV0IGN1c3RvbSBtb2RlbCBuYW1lcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hvaWNlcz1bImF1dG8iLCAianNvbl9zY2hlbWEiLCAiZnVuY3Rpb25fY2FsbGluZyJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iVG9vbCBDYWxscyBGdW50aW9uIE5hbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZT1GYWxzZQogICAgICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCflKcgTExNIENvbmZpZ3VyYXRpb24iLCBpZD0yKToKICAgICAgICAgICAgICAgIHdpdGggZ3IuR3JvdXAoKToKICAgICAgICAgICAgICAgICAgICBsbG1fcHJvdmlkZXIgPSBnci5Ecm9wZG93bigKICAgICAgICAgICAgICAgICAgICAgICAgY2hvaWNlcz1bcHJvdmlkZXIgZm9yIHByb3ZpZGVyLG1vZGVsIGluIHV0aWxzLm1vZGVsX25hbWVzLml0ZW1zKCldLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTExNIFByb3ZpZGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydsbG1fcHJvdmlkZXInXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU2VsZWN0IHlvdXIgcHJlZmVycmVkIGxhbmd1YWdlIG1vZGVsIHByb3ZpZGVyIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBsbG1fbW9kZWxfbmFtZSA9IGdyLkRyb3Bkb3duKAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTW9kZWwgTmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGNob2ljZXM9dXRpbHMubW9kZWxfbmFtZXNbJ29wZW5haSddLAogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2xsbV9tb2RlbF9uYW1lJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93X2N1c3RvbV92YWx1ZT1UcnVlLCAgIyBBbGxvdyB1c2VycyB0byBpbnB1dCBjdXN0b20gbW9kZWwgbmFtZXMKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU2VsZWN0IGEgbW9kZWwgZnJvbSB0aGUgZHJvcGRvd24gb3IgdHlwZSBhIGN1c3RvbSBtb2RlbCBuYW1lIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBsbG1fdGVtcGVyYXR1cmUgPSBnci5TbGlkZXIoCiAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW09MC4wLAogICAgICAgICAgICAgICAgICAgICAgICBtYXhpbXVtPTIuMCwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydsbG1fdGVtcGVyYXR1cmUnXSwKICAgICAgICAgICAgICAgICAgICAgICAgc3RlcD0wLjEsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJUZW1wZXJhdHVyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IkNvbnRyb2xzIHJhbmRvbW5lc3MgaW4gbW9kZWwgb3V0cHV0cyIKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICAgICAgbGxtX2Jhc2VfdXJsID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJCYXNlIFVSTCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2xsbV9iYXNlX3VybCddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQVBJIGVuZHBvaW50IFVSTCAoaWYgcmVxdWlyZWQpIgogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIGxsbV9hcGlfa2V5ID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBUEkgS2V5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9InBhc3N3b3JkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snbGxtX2FwaV9rZXknXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IllvdXIgQVBJIGtleSAobGVhdmUgYmxhbmsgdG8gdXNlIC5lbnYpIgogICAgICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCfjJAgQnJvd3NlciBTZXR0aW5ncyIsIGlkPTMpOgogICAgICAgICAgICAgICAgd2l0aCBnci5Hcm91cCgpOgogICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuUm93KCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3NlciA9IGdyLkNoZWNrYm94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlVzZSBPd24gQnJvd3NlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ3VzZV9vd25fYnJvd3NlciddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iVXNlIHlvdXIgZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAga2VlcF9icm93c2VyX29wZW4gPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJLZWVwIEJyb3dzZXIgT3BlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2tlZXBfYnJvd3Nlcl9vcGVuJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJLZWVwIEJyb3dzZXIgT3BlbiBiZXR3ZWVuIFRhc2tzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBoZWFkbGVzcyA9IGdyLkNoZWNrYm94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IkhlYWRsZXNzIE1vZGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydoZWFkbGVzcyddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iUnVuIGJyb3dzZXIgd2l0aG91dCBHVUkiLAogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHkgPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJEaXNhYmxlIFNlY3VyaXR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snZGlzYWJsZV9zZWN1cml0eSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iRGlzYWJsZSBicm93c2VyIHNlY3VyaXR5IGZlYXR1cmVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nID0gZ3IuQ2hlY2tib3goCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iRW5hYmxlIFJlY29yZGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2VuYWJsZV9yZWNvcmRpbmcnXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IkVuYWJsZSBzYXZpbmcgYnJvd3NlciByZWNvcmRpbmdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3dfdyA9IGdyLk51bWJlcigKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJXaW5kb3cgV2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd3aW5kb3dfdyddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQnJvd3NlciB3aW5kb3cgd2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvd19oID0gZ3IuTnVtYmVyKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IldpbmRvdyBIZWlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd3aW5kb3dfaCddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQnJvd3NlciB3aW5kb3cgaGVpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlJlY29yZGluZyBQYXRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9ImUuZy4gLi90bXAvcmVjb3JkX3ZpZGVvcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV9yZWNvcmRpbmdfcGF0aCddLAogICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJQYXRoIHRvIHNhdmUgYnJvd3NlciByZWNvcmRpbmdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU9VHJ1ZSwgICMgQWxsb3cgZWRpdGluZyBvbmx5IGlmIHJlY29yZGluZyBpcyBlbmFibGVkCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICBzYXZlX3RyYWNlX3BhdGggPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iVHJhY2UgUGF0aCIsCiAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPSJlLmcuIC4vdG1wL3RyYWNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV90cmFjZV9wYXRoJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IlBhdGggdG8gc2F2ZSBBZ2VudCB0cmFjZXMiLAogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZT1UcnVlLAogICAgICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGggPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iQWdlbnQgSGlzdG9yeSBTYXZlIFBhdGgiLAogICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj0iZS5nLiwgLi90bXAvYWdlbnRfaGlzdG9yeSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgnXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU3BlY2lmeSB0aGUgZGlyZWN0b3J5IHdoZXJlIGFnZW50IGhpc3Rvcnkgc2hvdWxkIGJlIHNhdmVkLiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUsCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgd2l0aCBnci5UYWJJdGVtKCLwn6SWIFJ1biBBZ2VudCIsIGlkPTQpOgogICAgICAgICAgICAgICAgdGFzayA9IGdyLlRleHRib3goCiAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlRhc2sgRGVzY3JpcHRpb24iLAogICAgICAgICAgICAgICAgICAgIGxpbmVzPTQsCiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9IkVudGVyIHlvdXIgdGFzayBoZXJlLi4uIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ3Rhc2snXSwKICAgICAgICAgICAgICAgICAgICBpbmZvPSJEZXNjcmliZSB3aGF0IHlvdSB3YW50IHRoZSBhZ2VudCB0byBkbyIsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBhZGRfaW5mb3MgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBZGRpdGlvbmFsIEluZm9ybWF0aW9uIiwKICAgICAgICAgICAgICAgICAgICBsaW5lcz0zLAogICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPSJBZGQgYW55IGhlbHBmdWwgY29udGV4dCBvciBpbnN0cnVjdGlvbnMuLi4iLAogICAgICAgICAgICAgICAgICAgIGluZm89Ik9wdGlvbmFsIGhpbnRzIHRvIGhlbHAgdGhlIExMTSBjb21wbGV0ZSB0aGUgdGFzayIsCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICBydW5fYnV0dG9uID0gZ3IuQnV0dG9uKCLilrbvuI8gUnVuIEFnZW50IiwgdmFyaWFudD0icHJpbWFyeSIsIHNjYWxlPTIpCiAgICAgICAgICAgICAgICAgICAgc3RvcF9idXR0b24gPSBnci5CdXR0b24oIuKPue+4jyBTdG9wIiwgdmFyaWFudD0ic3RvcCIsIHNjYWxlPTEpCiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgIGJyb3dzZXJfdmlldyA9IGdyLkhUTUwoCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPSI8aDEgc3R5bGU9J3dpZHRoOjgwdnc7IGhlaWdodDo1MHZoJz5XYWl0aW5nIGZvciBicm93c2VyIHNlc3Npb24uLi48L2gxPiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJMaXZlIEJyb3dzZXIgVmlldyIsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIAogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCfp5AgRGVlcCBSZXNlYXJjaCIsIGlkPTUpOgogICAgICAgICAgICAgICAgcmVzZWFyY2hfdGFza19pbnB1dCA9IGdyLlRleHRib3gobGFiZWw9IlJlc2VhcmNoIFRhc2siLCBsaW5lcz01LCB2YWx1ZT0iQ29tcG9zZSBhIHJlcG9ydCBvbiB0aGUgdXNlIG9mIFJlaW5mb3JjZW1lbnQgTGVhcm5pbmcgZm9yIHRyYWluaW5nIExhcmdlIExhbmd1YWdlIE1vZGVscywgZW5jb21wYXNzaW5nIGl0cyBvcmlnaW5zLCBjdXJyZW50IGFkdmFuY2VtZW50cywgYW5kIGZ1dHVyZSBwcm9zcGVjdHMsIHN1YnN0YW50aWF0ZWQgd2l0aCBleGFtcGxlcyBvZiByZWxldmFudCBtb2RlbHMgYW5kIHRlY2huaXF1ZXMuIFRoZSByZXBvcnQgc2hvdWxkIHJlZmxlY3Qgb3JpZ2luYWwgaW5zaWdodHMgYW5kIGFuYWx5c2lzLCBtb3ZpbmcgYmV5b25kIG1lcmUgc3VtbWFyaXphdGlvbiBvZiBleGlzdGluZyBsaXRlcmF0dXJlLiIpCiAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0ID0gZ3IuTnVtYmVyKGxhYmVsPSJNYXggU2VhcmNoIEl0ZXJhdGlvbiIsIHZhbHVlPTMsIHByZWNpc2lvbj0wKSAjIHByZWNpc2lvbj0wIOehruS/neaYr+aVtOaVsAogICAgICAgICAgICAgICAgICAgIG1heF9xdWVyeV9wZXJfaXRlcl9pbnB1dCA9IGdyLk51bWJlcihsYWJlbD0iTWF4IFF1ZXJ5IHBlciBJdGVyYXRpb24iLCB2YWx1ZT0xLCBwcmVjaXNpb249MCkgIyBwcmVjaXNpb249MCDnoa7kv53mmK/mlbTmlbAKICAgICAgICAgICAgICAgIHdpdGggZ3IuUm93KCk6CiAgICAgICAgICAgICAgICAgICAgcmVzZWFyY2hfYnV0dG9uID0gZ3IuQnV0dG9uKCLilrbvuI8gUnVuIERlZXAgUmVzZWFyY2giLCB2YXJpYW50PSJwcmltYXJ5Iiwgc2NhbGU9MikKICAgICAgICAgICAgICAgICAgICBzdG9wX3Jlc2VhcmNoX2J1dHRvbiA9IGdyLkJ1dHRvbigi4o+577iPIFN0b3AiLCB2YXJpYW50PSJzdG9wIiwgc2NhbGU9MSkKICAgICAgICAgICAgICAgIG1hcmtkb3duX291dHB1dF9kaXNwbGF5ID0gZ3IuTWFya2Rvd24obGFiZWw9IlJlc2VhcmNoIFJlcG9ydCIpCiAgICAgICAgICAgICAgICBtYXJrZG93bl9kb3dubG9hZCA9IGdyLkZpbGUobGFiZWw9IkRvd25sb2FkIFJlc2VhcmNoIFJlcG9ydCIpCgoKICAgICAgICAgICAgd2l0aCBnci5UYWJJdGVtKCLwn5OKIFJlc3VsdHMiLCBpZD02KToKICAgICAgICAgICAgICAgIHdpdGggZ3IuR3JvdXAoKToKCiAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5nX2Rpc3BsYXkgPSBnci5WaWRlbyhsYWJlbD0iTGF0ZXN0IFJlY29yZGluZyIpCgogICAgICAgICAgICAgICAgICAgIGdyLk1hcmtkb3duKCIjIyMgUmVzdWx0cyIpCiAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Db2x1bW4oKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdF9vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJGaW5hbCBSZXN1bHQiLCBsaW5lcz0zLCBzaG93X2xhYmVsPVRydWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Db2x1bW4oKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yc19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJFcnJvcnMiLCBsaW5lcz0zLCBzaG93X2xhYmVsPVRydWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLkNvbHVtbigpOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9uc19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJNb2RlbCBBY3Rpb25zIiwgbGluZXM9Mywgc2hvd19sYWJlbD1UcnVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuQ29sdW1uKCk6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0c19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJNb2RlbCBUaG91Z2h0cyIsIGxpbmVzPTMsIHNob3dfbGFiZWw9VHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICB0cmFjZV9maWxlID0gZ3IuRmlsZShsYWJlbD0iVHJhY2UgRmlsZSIpCgogICAgICAgICAgICAgICAgICAgIGFnZW50X2hpc3RvcnlfZmlsZSA9IGdyLkZpbGUobGFiZWw9IkFnZW50IEhpc3RvcnkiKQoKICAgICAgICAgICAgICAgICMgQmluZCB0aGUgc3RvcCBidXR0b24gY2xpY2sgZXZlbnQgYWZ0ZXIgZXJyb3JzX291dHB1dCBpcyBkZWZpbmVkCiAgICAgICAgICAgICAgICBzdG9wX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zdG9wX2FnZW50LAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVtlcnJvcnNfb3V0cHV0LCBzdG9wX2J1dHRvbiwgcnVuX2J1dHRvbl0sCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgIyBSdW4gYnV0dG9uIGNsaWNrIGhhbmRsZXIKICAgICAgICAgICAgICAgIHJ1bl9idXR0b24uY2xpY2soCiAgICAgICAgICAgICAgICAgICAgZm49cnVuX3dpdGhfc3RyZWFtLAogICAgICAgICAgICAgICAgICAgICAgICBpbnB1dHM9WwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlbnRfdHlwZSwgbGxtX3Byb3ZpZGVyLCBsbG1fbW9kZWxfbmFtZSwgbGxtX3RlbXBlcmF0dXJlLCBsbG1fYmFzZV91cmwsIGxsbV9hcGlfa2V5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX293bl9icm93c2VyLCBrZWVwX2Jyb3dzZXJfb3BlbiwgaGVhZGxlc3MsIGRpc2FibGVfc2VjdXJpdHksIHdpbmRvd193LCB3aW5kb3dfaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLCBzYXZlX3RyYWNlX3BhdGgsICAjIEluY2x1ZGUgdGhlIG5ldyBwYXRoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nLCB0YXNrLCBhZGRfaW5mb3MsIG1heF9zdGVwcywgdXNlX3Zpc2lvbiwgbWF4X2FjdGlvbnNfcGVyX3N0ZXAsIHRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVsKICAgICAgICAgICAgICAgICAgICAgICAgYnJvd3Nlcl92aWV3LCAgICAgICAgICAgIyBCcm93c2VyIHZpZXcKICAgICAgICAgICAgICAgICAgICAgICAgZmluYWxfcmVzdWx0X291dHB1dCwgICAgIyBGaW5hbCByZXN1bHQKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JzX291dHB1dCwgICAgICAgICAgIyBFcnJvcnMKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9uc19vdXRwdXQsICAgIyBNb2RlbCBhY3Rpb25zCiAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3Rob3VnaHRzX291dHB1dCwgICMgTW9kZWwgdGhvdWdodHMKICAgICAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5nX2Rpc3BsYXksICAgICAgIyBMYXRlc3QgcmVjb3JkaW5nCiAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlX2ZpbGUsICAgICAgICAgICAgICMgVHJhY2UgZmlsZQogICAgICAgICAgICAgICAgICAgICAgICBhZ2VudF9oaXN0b3J5X2ZpbGUsICAgICAjIEFnZW50IGhpc3RvcnkgZmlsZQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wX2J1dHRvbiwgICAgICAgICAgICAjIFN0b3AgYnV0dG9uCiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bl9idXR0b24gICAgICAgICAgICAgICMgUnVuIGJ1dHRvbgogICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICMgUnVuIERlZXAgUmVzZWFyY2gKICAgICAgICAgICAgICAgIHJlc2VhcmNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICAgICAgZm49cnVuX2RlZXBfc2VhcmNoLAogICAgICAgICAgICAgICAgICAgICAgICBpbnB1dHM9W3Jlc2VhcmNoX3Rhc2tfaW5wdXQsIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0LCBtYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwgdXNlX3Zpc2lvbiwgdXNlX293bl9icm93c2VyLCBoZWFkbGVzc10sCiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHM9W21hcmtkb3duX291dHB1dF9kaXNwbGF5LCBtYXJrZG93bl9kb3dubG9hZCwgc3RvcF9yZXNlYXJjaF9idXR0b24sIHJlc2VhcmNoX2J1dHRvbl0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICMgQmluZCB0aGUgc3RvcCBidXR0b24gY2xpY2sgZXZlbnQgYWZ0ZXIgZXJyb3JzX291dHB1dCBpcyBkZWZpbmVkCiAgICAgICAgICAgICAgICBzdG9wX3Jlc2VhcmNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zdG9wX3Jlc2VhcmNoX2FnZW50LAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVtzdG9wX3Jlc2VhcmNoX2J1dHRvbiwgcmVzZWFyY2hfYnV0dG9uXSwKICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgIHdpdGggZ3IuVGFiSXRlbSgi8J+OpSBSZWNvcmRpbmdzIiwgaWQ9Nyk6CiAgICAgICAgICAgICAgICBkZWYgbGlzdF9yZWNvcmRpbmdzKHNhdmVfcmVjb3JkaW5nX3BhdGgpOgogICAgICAgICAgICAgICAgICAgIGlmIG5vdCBvcy5wYXRoLmV4aXN0cyhzYXZlX3JlY29yZGluZ19wYXRoKToKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdCgogICAgICAgICAgICAgICAgICAgICMgR2V0IGFsbCB2aWRlbyBmaWxlcwogICAgICAgICAgICAgICAgICAgIHJlY29yZGluZ3MgPSBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlttTV1bcFBdNCIpKSArIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW3dXXVtlRV1bYkJdW21NXSIpKQoKICAgICAgICAgICAgICAgICAgICAjIFNvcnQgcmVjb3JkaW5ncyBieSBjcmVhdGlvbiB0aW1lIChvbGRlc3QgZmlyc3QpCiAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5ncy5zb3J0KGtleT1vcy5wYXRoLmdldGN0aW1lKQoKICAgICAgICAgICAgICAgICAgICAjIEFkZCBudW1iZXJpbmcgdG8gdGhlIHJlY29yZGluZ3MKICAgICAgICAgICAgICAgICAgICBudW1iZXJlZF9yZWNvcmRpbmdzID0gW10KICAgICAgICAgICAgICAgICAgICBmb3IgaWR4LCByZWNvcmRpbmcgaW4gZW51bWVyYXRlKHJlY29yZGluZ3MsIHN0YXJ0PTEpOgogICAgICAgICAgICAgICAgICAgICAgICBmaWxlbmFtZSA9IG9zLnBhdGguYmFzZW5hbWUocmVjb3JkaW5nKQogICAgICAgICAgICAgICAgICAgICAgICBudW1iZXJlZF9yZWNvcmRpbmdzLmFwcGVuZCgocmVjb3JkaW5nLCBmIntpZHh9LiB7ZmlsZW5hbWV9IikpCgogICAgICAgICAgICAgICAgICAgIHJldHVybiBudW1iZXJlZF9yZWNvcmRpbmdzCgogICAgICAgICAgICAgICAgcmVjb3JkaW5nc19nYWxsZXJ5ID0gZ3IuR2FsbGVyeSgKICAgICAgICAgICAgICAgICAgICBsYWJlbD0iUmVjb3JkaW5ncyIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWU9bGlzdF9yZWNvcmRpbmdzKGNvbmZpZ1snc2F2ZV9yZWNvcmRpbmdfcGF0aCddKSwKICAgICAgICAgICAgICAgICAgICBjb2x1bW5zPTMsCiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PSJhdXRvIiwKICAgICAgICAgICAgICAgICAgICBvYmplY3RfZml0PSJjb250YWluIgogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIHJlZnJlc2hfYnV0dG9uID0gZ3IuQnV0dG9uKCLwn5SEIFJlZnJlc2ggUmVjb3JkaW5ncyIsIHZhcmlhbnQ9InNlY29uZGFyeSIpCiAgICAgICAgICAgICAgICByZWZyZXNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1saXN0X3JlY29yZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgaW5wdXRzPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgb3V0cHV0cz1yZWNvcmRpbmdzX2dhbGxlcnkKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgICAgIHdpdGggZ3IuVGFiSXRlbSgi8J+TgSBDb25maWd1cmF0aW9uIiwgaWQ9OCk6CiAgICAgICAgICAgICAgICB3aXRoIGdyLkdyb3VwKCk6CiAgICAgICAgICAgICAgICAgICAgY29uZmlnX2ZpbGVfaW5wdXQgPSBnci5GaWxlKAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTG9hZCBDb25maWcgRmlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfdHlwZXM9WyIucGtsIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUKICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgICAgIGxvYWRfY29uZmlnX2J1dHRvbiA9IGdyLkJ1dHRvbigiTG9hZCBFeGlzdGluZyBDb25maWcgRnJvbSBGaWxlIiwgdmFyaWFudD0icHJpbWFyeSIpCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9jb25maWdfYnV0dG9uID0gZ3IuQnV0dG9uKCJTYXZlIEN1cnJlbnQgQ29uZmlnIiwgdmFyaWFudD0icHJpbWFyeSIpCgogICAgICAgICAgICAgICAgICAgIGNvbmZpZ19zdGF0dXMgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iU3RhdHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXM9MiwKICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU9RmFsc2UKICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgbG9hZF9jb25maWdfYnV0dG9uLmNsaWNrKAogICAgICAgICAgICAgICAgICAgIGZuPXVwZGF0ZV91aV9mcm9tX2NvbmZpZywKICAgICAgICAgICAgICAgICAgICBpbnB1dHM9W2NvbmZpZ19maWxlX2lucHV0XSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVsKICAgICAgICAgICAgICAgICAgICAgICAgYWdlbnRfdHlwZSwgbWF4X3N0ZXBzLCBtYXhfYWN0aW9uc19wZXJfc3RlcCwgdXNlX3Zpc2lvbiwgdG9vbF9jYWxsaW5nX21ldGhvZCwKICAgICAgICAgICAgICAgICAgICAgICAgbGxtX3Byb3ZpZGVyLCBsbG1fbW9kZWxfbmFtZSwgbGxtX3RlbXBlcmF0dXJlLCBsbG1fYmFzZV91cmwsIGxsbV9hcGlfa2V5LAogICAgICAgICAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXIsIGtlZXBfYnJvd3Nlcl9vcGVuLCBoZWFkbGVzcywgZGlzYWJsZV9zZWN1cml0eSwgZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93X3csIHdpbmRvd19oLCBzYXZlX3JlY29yZGluZ19wYXRoLCBzYXZlX3RyYWNlX3BhdGgsIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICB0YXNrLCBjb25maWdfc3RhdHVzCiAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIHNhdmVfY29uZmlnX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zYXZlX2N1cnJlbnRfY29uZmlnLAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bCiAgICAgICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGUsIG1heF9zdGVwcywgbWF4X2FjdGlvbnNfcGVyX3N0ZXAsIHVzZV92aXNpb24sIHRvb2xfY2FsbGluZ19tZXRob2QsCiAgICAgICAgICAgICAgICAgICAgICAgIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwKICAgICAgICAgICAgICAgICAgICAgICAgdXNlX293bl9icm93c2VyLCBrZWVwX2Jyb3dzZXJfb3BlbiwgaGVhZGxlc3MsIGRpc2FibGVfc2VjdXJpdHksCiAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZV9yZWNvcmRpbmcsIHdpbmRvd193LCB3aW5kb3dfaCwgc2F2ZV9yZWNvcmRpbmdfcGF0aCwgc2F2ZV90cmFjZV9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwgdGFzaywKICAgICAgICAgICAgICAgICAgICBdLCAgCiAgICAgICAgICAgICAgICAgICAgb3V0cHV0cz1bY29uZmlnX3N0YXR1c10KICAgICAgICAgICAgICAgICkKCgogICAgICAgICMgQXR0YWNoIHRoZSBjYWxsYmFjayB0byB0aGUgTExNIHByb3ZpZGVyIGRyb3Bkb3duCiAgICAgICAgbGxtX3Byb3ZpZGVyLmNoYW5nZSgKICAgICAgICAgICAgbGFtYmRhIHByb3ZpZGVyLCBhcGlfa2V5LCBiYXNlX3VybDogdXBkYXRlX21vZGVsX2Ryb3Bkb3duKHByb3ZpZGVyLCBhcGlfa2V5LCBiYXNlX3VybCksCiAgICAgICAgICAgIGlucHV0cz1bbGxtX3Byb3ZpZGVyLCBsbG1fYXBpX2tleSwgbGxtX2Jhc2VfdXJsXSwKICAgICAgICAgICAgb3V0cHV0cz1sbG1fbW9kZWxfbmFtZQogICAgICAgICkKCiAgICAgICAgIyBBZGQgdGhpcyBhZnRlciBkZWZpbmluZyB0aGUgY29tcG9uZW50cwogICAgICAgIGVuYWJsZV9yZWNvcmRpbmcuY2hhbmdlKAogICAgICAgICAgICBsYW1iZGEgZW5hYmxlZDogZ3IudXBkYXRlKGludGVyYWN0aXZlPWVuYWJsZWQpLAogICAgICAgICAgICBpbnB1dHM9ZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgb3V0cHV0cz1zYXZlX3JlY29yZGluZ19wYXRoCiAgICAgICAgKQoKICAgICAgICB1c2Vfb3duX2Jyb3dzZXIuY2hhbmdlKGZuPWNsb3NlX2dsb2JhbF9icm93c2VyKQogICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuLmNoYW5nZShmbj1jbG9zZV9nbG9iYWxfYnJvd3NlcikKCiAgICByZXR1cm4gZGVtbwoKZGVmIG1haW4oKToKICAgIHBhcnNlciA9IGFyZ3BhcnNlLkFyZ3VtZW50UGFyc2VyKGRlc2NyaXB0aW9uPSJHcmFkaW8gVUkgZm9yIEJyb3dzZXIgQWdlbnQiKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1pcCIsIHR5cGU9c3RyLCBkZWZhdWx0PSIxMjcuMC4wLjEiLCBoZWxwPSJJUCBhZGRyZXNzIHRvIGJpbmQgdG8iKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1wb3J0IiwgdHlwZT1pbnQsIGRlZmF1bHQ9Nzc4OCwgaGVscD0iUG9ydCB0byBsaXN0ZW4gb24iKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS10aGVtZSIsIHR5cGU9c3RyLCBkZWZhdWx0PSJPY2VhbiIsIGNob2ljZXM9dGhlbWVfbWFwLmtleXMoKSwgaGVscD0iVGhlbWUgdG8gdXNlIGZvciB0aGUgVUkiKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1kYXJrLW1vZGUiLCBhY3Rpb249InN0b3JlX3RydWUiLCBoZWxwPSJFbmFibGUgZGFyayBtb2RlIikKICAgIGFyZ3MgPSBwYXJzZXIucGFyc2VfYXJncygpCgogICAgY29uZmlnX2RpY3QgPSBkZWZhdWx0X2NvbmZpZygpCgogICAgZGVtbyA9IGNyZWF0ZV91aShjb25maWdfZGljdCwgdGhlbWVfbmFtZT1hcmdzLnRoZW1lKQogICAgZGVtby5sYXVuY2goc2VydmVyX25hbWU9YXJncy5pcCwgc2VydmVyX3BvcnQ9YXJncy5wb3J0KQoKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIG1haW4oKQo=").decode("utf-8")
with open(WEB_UI_DIR / "webui.py.original", "w", encoding="utf-8") as f:
f.write(webui_original_content)
logging.info("Decoded and wrote embedded webui.py.original")
# Decode and write embedded template file
webui_template_content = base64.b64decode("aW1wb3J0IHBkYgppbXBvcnQgbG9nZ2luZwoKZnJvbSBkb3RlbnYgaW1wb3J0IGxvYWRfZG90ZW52Cgpsb2FkX2RvdGVudigpCmltcG9ydCBvcwppbXBvcnQgZ2xvYgppbXBvcnQgYXN5bmNpbwppbXBvcnQgYXJncGFyc2UKaW1wb3J0IG9zCgpsb2dnZXIgPSBsb2dnaW5nLmdldExvZ2dlcihfX25hbWVfXykKCmltcG9ydCBncmFkaW8gYXMgZ3IKCmZyb20gYnJvd3Nlcl91c2UuYWdlbnQuc2VydmljZSBpbXBvcnQgQWdlbnQKZnJvbSBwbGF5d3JpZ2h0LmFzeW5jX2FwaSBpbXBvcnQgYXN5bmNfcGxheXdyaWdodApmcm9tIGJyb3dzZXJfdXNlLmJyb3dzZXIuYnJvd3NlciBpbXBvcnQgQnJvd3NlciwgQnJvd3NlckNvbmZpZwpmcm9tIGJyb3dzZXJfdXNlLmJyb3dzZXIuY29udGV4dCBpbXBvcnQgKAogICAgQnJvd3NlckNvbnRleHRDb25maWcsCiAgICBCcm93c2VyQ29udGV4dFdpbmRvd1NpemUsCikKZnJvbSBsYW5nY2hhaW5fb2xsYW1hIGltcG9ydCBDaGF0T2xsYW1hCmZyb20gcGxheXdyaWdodC5hc3luY19hcGkgaW1wb3J0IGFzeW5jX3BsYXl3cmlnaHQKZnJvbSBzcmMudXRpbHMuYWdlbnRfc3RhdGUgaW1wb3J0IEFnZW50U3RhdGUKCmZyb20gc3JjLnV0aWxzIGltcG9ydCB1dGlscwpmcm9tIHNyYy5hZ2VudC5jdXN0b21fYWdlbnQgaW1wb3J0IEN1c3RvbUFnZW50CmZyb20gc3JjLmJyb3dzZXIuY3VzdG9tX2Jyb3dzZXIgaW1wb3J0IEN1c3RvbUJyb3dzZXIKZnJvbSBzcmMuYWdlbnQuY3VzdG9tX3Byb21wdHMgaW1wb3J0IEN1c3RvbVN5c3RlbVByb21wdCwgQ3VzdG9tQWdlbnRNZXNzYWdlUHJvbXB0CmZyb20gc3JjLmJyb3dzZXIuY3VzdG9tX2NvbnRleHQgaW1wb3J0IEJyb3dzZXJDb250ZXh0Q29uZmlnLCBDdXN0b21Ccm93c2VyQ29udGV4dApmcm9tIHNyYy5jb250cm9sbGVyLmN1c3RvbV9jb250cm9sbGVyIGltcG9ydCBDdXN0b21Db250cm9sbGVyCmZyb20gZ3JhZGlvLnRoZW1lcyBpbXBvcnQgQ2l0cnVzLCBEZWZhdWx0LCBHbGFzcywgTW9ub2Nocm9tZSwgT2NlYW4sIE9yaWdpbiwgU29mdCwgQmFzZQpmcm9tIHNyYy51dGlscy5kZWZhdWx0X2NvbmZpZ19zZXR0aW5ncyBpbXBvcnQgZGVmYXVsdF9jb25maWcsIGxvYWRfY29uZmlnX2Zyb21fZmlsZSwgc2F2ZV9jb25maWdfdG9fZmlsZSwgc2F2ZV9jdXJyZW50X2NvbmZpZywgdXBkYXRlX3VpX2Zyb21fY29uZmlnCmZyb20gc3JjLnV0aWxzLnV0aWxzIGltcG9ydCB1cGRhdGVfbW9kZWxfZHJvcGRvd24sIGdldF9sYXRlc3RfZmlsZXMsIGNhcHR1cmVfc2NyZWVuc2hvdAoKCiMgR2xvYmFsIHZhcmlhYmxlcyBmb3IgcGVyc2lzdGVuY2UKX2dsb2JhbF9icm93c2VyID0gTm9uZQpfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCA9IE5vbmUKCiMgQ3JlYXRlIHRoZSBnbG9iYWwgYWdlbnQgc3RhdGUgaW5zdGFuY2UKX2dsb2JhbF9hZ2VudF9zdGF0ZSA9IEFnZW50U3RhdGUoKQoKYXN5bmMgZGVmIHN0b3BfYWdlbnQoKToKICAgICIiIlJlcXVlc3QgdGhlIGFnZW50IHRvIHN0b3AgYW5kIHVwZGF0ZSBVSSB3aXRoIGVuaGFuY2VkIGZlZWRiYWNrIiIiCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQsIF9nbG9iYWxfYnJvd3NlcgoKICAgIHRyeToKICAgICAgICAjIFJlcXVlc3Qgc3RvcAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUucmVxdWVzdF9zdG9wKCkKCiAgICAgICAgIyBVcGRhdGUgVUkgaW1tZWRpYXRlbHkKICAgICAgICBtZXNzYWdlID0gIlN0b3AgcmVxdWVzdGVkIC0gdGhlIGFnZW50IHdpbGwgaGFsdCBhdCB0aGUgbmV4dCBzYWZlIHBvaW50IgogICAgICAgIGxvZ2dlci5pbmZvKGYi8J+bkSB7bWVzc2FnZX0iKQoKICAgICAgICAjIFJldHVybiBVSSB1cGRhdGVzCiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgbWVzc2FnZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBlcnJvcnNfb3V0cHV0CiAgICAgICAgICAgIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcHBpbmcuLi4iLCBpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHN0b3BfYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1GYWxzZSksICAgICAgICAgICAgICAgICAgICAgICMgcnVuX2J1dHRvbgogICAgICAgICkKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBlcnJvcl9tc2cgPSBmIkVycm9yIGR1cmluZyBzdG9wOiB7c3RyKGUpfSIKICAgICAgICBsb2dnZXIuZXJyb3IoZXJyb3JfbXNnKQogICAgICAgIHJldHVybiAoCiAgICAgICAgICAgIGVycm9yX21zZywKICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKQogICAgICAgICkKICAgICAgICAKYXN5bmMgZGVmIHN0b3BfcmVzZWFyY2hfYWdlbnQoKToKICAgICIiIlJlcXVlc3QgdGhlIGFnZW50IHRvIHN0b3AgYW5kIHVwZGF0ZSBVSSB3aXRoIGVuaGFuY2VkIGZlZWRiYWNrIiIiCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQsIF9nbG9iYWxfYnJvd3NlcgoKICAgIHRyeToKICAgICAgICAjIFJlcXVlc3Qgc3RvcAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUucmVxdWVzdF9zdG9wKCkKCiAgICAgICAgIyBVcGRhdGUgVUkgaW1tZWRpYXRlbHkKICAgICAgICBtZXNzYWdlID0gIlN0b3AgcmVxdWVzdGVkIC0gdGhlIGFnZW50IHdpbGwgaGFsdCBhdCB0aGUgbmV4dCBzYWZlIHBvaW50IgogICAgICAgIGxvZ2dlci5pbmZvKGYi8J+bkSB7bWVzc2FnZX0iKQoKICAgICAgICAjIFJldHVybiBVSSB1cGRhdGVzCiAgICAgICAgcmV0dXJuICggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZXJyb3JzX291dHB1dAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3BwaW5nLi4uIiwgaW50ZXJhY3RpdmU9RmFsc2UpLCAgIyBzdG9wX2J1dHRvbgogICAgICAgICAgICBnci51cGRhdGUoaW50ZXJhY3RpdmU9RmFsc2UpLCAgICAgICAgICAgICAgICAgICAgICAjIHJ1bl9idXR0b24KICAgICAgICApCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgZXJyb3JfbXNnID0gZiJFcnJvciBkdXJpbmcgc3RvcDoge3N0cihlKX0iCiAgICAgICAgbG9nZ2VyLmVycm9yKGVycm9yX21zZykKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwKICAgICAgICAgICAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpCiAgICAgICAgKQoKYXN5bmMgZGVmIHJ1bl9icm93c2VyX2FnZW50KAogICAgICAgIGFnZW50X3R5cGUsCiAgICAgICAgbGxtX3Byb3ZpZGVyLAogICAgICAgIGxsbV9tb2RlbF9uYW1lLAogICAgICAgIGxsbV90ZW1wZXJhdHVyZSwKICAgICAgICBsbG1fYmFzZV91cmwsCiAgICAgICAgbGxtX2FwaV9rZXksCiAgICAgICAgdXNlX293bl9icm93c2VyLAogICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgIGhlYWRsZXNzLAogICAgICAgIGRpc2FibGVfc2VjdXJpdHksCiAgICAgICAgd2luZG93X3csCiAgICAgICAgd2luZG93X2gsCiAgICAgICAgc2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgICAgICBzYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgZW5hYmxlX3JlY29yZGluZywKICAgICAgICB0YXNrLAogICAgICAgIGFkZF9pbmZvcywKICAgICAgICBtYXhfc3RlcHMsCiAgICAgICAgdXNlX3Zpc2lvbiwKICAgICAgICBtYXhfYWN0aW9uc19wZXJfc3RlcCwKICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kCik6CiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZQogICAgX2dsb2JhbF9hZ2VudF9zdGF0ZS5jbGVhcl9zdG9wKCkgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdHMKCiAgICB0cnk6CiAgICAgICAgIyBEaXNhYmxlIHJlY29yZGluZyBpZiB0aGUgY2hlY2tib3ggaXMgdW5jaGVja2VkCiAgICAgICAgaWYgbm90IGVuYWJsZV9yZWNvcmRpbmc6CiAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGggPSBOb25lCgogICAgICAgICMgRW5zdXJlIHRoZSByZWNvcmRpbmcgZGlyZWN0b3J5IGV4aXN0cyBpZiByZWNvcmRpbmcgaXMgZW5hYmxlZAogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIG9zLm1ha2VkaXJzKHNhdmVfcmVjb3JkaW5nX3BhdGgsIGV4aXN0X29rPVRydWUpCgogICAgICAgICMgR2V0IHRoZSBsaXN0IG9mIGV4aXN0aW5nIHZpZGVvcyBiZWZvcmUgdGhlIGFnZW50IHJ1bnMKICAgICAgICBleGlzdGluZ192aWRlb3MgPSBzZXQoKQogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIGV4aXN0aW5nX3ZpZGVvcyA9IHNldCgKICAgICAgICAgICAgICAgIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW21NXVtwUF00IikpCiAgICAgICAgICAgICAgICArIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW3dXXVtlRV1bYkJdW21NXSIpKQogICAgICAgICAgICApCgogICAgICAgICMgUnVuIHRoZSBhZ2VudAogICAgICAgIGxsbSA9IHV0aWxzLmdldF9sbG1fbW9kZWwoCiAgICAgICAgICAgIHByb3ZpZGVyPWxsbV9wcm92aWRlciwKICAgICAgICAgICAgbW9kZWxfbmFtZT1sbG1fbW9kZWxfbmFtZSwKICAgICAgICAgICAgdGVtcGVyYXR1cmU9bGxtX3RlbXBlcmF0dXJlLAogICAgICAgICAgICBiYXNlX3VybD1sbG1fYmFzZV91cmwsCiAgICAgICAgICAgIGFwaV9rZXk9bGxtX2FwaV9rZXksCiAgICAgICAgKQogICAgICAgIGlmIGFnZW50X3R5cGUgPT0gIm9yZyI6CiAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwgZXJyb3JzLCBtb2RlbF9hY3Rpb25zLCBtb2RlbF90aG91Z2h0cywgdHJhY2VfZmlsZSwgaGlzdG9yeV9maWxlID0gYXdhaXQgcnVuX29yZ19hZ2VudCgKICAgICAgICAgICAgICAgIGxsbT1sbG0sCiAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXI9dXNlX293bl9icm93c2VyLAogICAgICAgICAgICAgICAga2VlcF9icm93c2VyX29wZW49a2VlcF9icm93c2VyX29wZW4sCiAgICAgICAgICAgICAgICBoZWFkbGVzcz1oZWFkbGVzcywKICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgIHdpbmRvd193PXdpbmRvd193LAogICAgICAgICAgICAgICAgd2luZG93X2g9d2luZG93X2gsCiAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aD1zYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgICAgICAgICAgICAgIHNhdmVfdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgICAgICAgICB0YXNrPXRhc2ssCiAgICAgICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgKQogICAgICAgIGVsaWYgYWdlbnRfdHlwZSA9PSAiY3VzdG9tIjoKICAgICAgICAgICAgZmluYWxfcmVzdWx0LCBlcnJvcnMsIG1vZGVsX2FjdGlvbnMsIG1vZGVsX3Rob3VnaHRzLCB0cmFjZV9maWxlLCBoaXN0b3J5X2ZpbGUgPSBhd2FpdCBydW5fY3VzdG9tX2FnZW50KAogICAgICAgICAgICAgICAgbGxtPWxsbSwKICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAgICAgICAgICBrZWVwX2Jyb3dzZXJfb3Blbj1rZWVwX2Jyb3dzZXJfb3BlbiwKICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICAgICAgd2luZG93X3c9d2luZG93X3csCiAgICAgICAgICAgICAgICB3aW5kb3dfaD13aW5kb3dfaCwKICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICAgICAgICAgIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoPXNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgICAgICAgICAgc2F2ZV90cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCwKICAgICAgICAgICAgICAgIHRhc2s9dGFzaywKICAgICAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoZiJJbnZhbGlkIGFnZW50IHR5cGU6IHthZ2VudF90eXBlfSIpCgogICAgICAgICMgR2V0IHRoZSBsaXN0IG9mIHZpZGVvcyBhZnRlciB0aGUgYWdlbnQgcnVucyAoaWYgcmVjb3JkaW5nIGlzIGVuYWJsZWQpCiAgICAgICAgbGF0ZXN0X3ZpZGVvID0gTm9uZQogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIG5ld192aWRlb3MgPSBzZXQoCiAgICAgICAgICAgICAgICBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlttTV1bcFBdNCIpKQogICAgICAgICAgICAgICAgKyBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlt3V11bZUVdW2JCXVttTV0iKSkKICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBuZXdfdmlkZW9zIC0gZXhpc3RpbmdfdmlkZW9zOgogICAgICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvID0gbGlzdChuZXdfdmlkZW9zIC0gZXhpc3RpbmdfdmlkZW9zKVswXSAgIyBHZXQgdGhlIGZpcnN0IG5ldyB2aWRlbwoKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICBmaW5hbF9yZXN1bHQsCiAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgbW9kZWxfYWN0aW9ucywKICAgICAgICAgICAgbW9kZWxfdGhvdWdodHMsCiAgICAgICAgICAgIGxhdGVzdF92aWRlbywKICAgICAgICAgICAgdHJhY2VfZmlsZSwKICAgICAgICAgICAgaGlzdG9yeV9maWxlLAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwgICMgUmUtZW5hYmxlIHN0b3AgYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKSAgICAjIFJlLWVuYWJsZSBydW4gYnV0dG9uCiAgICAgICAgKQoKICAgIGV4Y2VwdCBnci5FcnJvcjoKICAgICAgICByYWlzZQoKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBpbXBvcnQgdHJhY2ViYWNrCiAgICAgICAgdHJhY2ViYWNrLnByaW50X2V4YygpCiAgICAgICAgZXJyb3JzID0gc3RyKGUpICsgIlxuIiArIHRyYWNlYmFjay5mb3JtYXRfZXhjKCkKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAnJywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmluYWxfcmVzdWx0CiAgICAgICAgICAgIGVycm9ycywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBlcnJvcnMKICAgICAgICAgICAgJycsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1vZGVsX2FjdGlvbnMKICAgICAgICAgICAgJycsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1vZGVsX3Rob3VnaHRzCiAgICAgICAgICAgIE5vbmUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBsYXRlc3RfdmlkZW8KICAgICAgICAgICAgTm9uZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGhpc3RvcnlfZmlsZQogICAgICAgICAgICBOb25lLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdHJhY2VfZmlsZQogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwgICMgUmUtZW5hYmxlIHN0b3AgYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKSAgICAjIFJlLWVuYWJsZSBydW4gYnV0dG9uCiAgICAgICAgKQoKCmFzeW5jIGRlZiBydW5fb3JnX2FnZW50KAogICAgICAgIGxsbSwKICAgICAgICB1c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAga2VlcF9icm93c2VyX29wZW4sCiAgICAgICAgaGVhZGxlc3MsCiAgICAgICAgZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICB3aW5kb3dfdywKICAgICAgICB3aW5kb3dfaCwKICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoLAogICAgICAgIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgIHNhdmVfdHJhY2VfcGF0aCwKICAgICAgICB0YXNrLAogICAgICAgIG1heF9zdGVwcywKICAgICAgICB1c2VfdmlzaW9uLAogICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2QKKToKICAgIHRyeToKICAgICAgICBnbG9iYWwgX2dsb2JhbF9icm93c2VyLCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwgX2dsb2JhbF9hZ2VudF9zdGF0ZQogICAgICAgIAogICAgICAgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUuY2xlYXJfc3RvcCgpCgogICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3MgPSBbZiItLXdpbmRvdy1zaXplPXt3aW5kb3dfd30se3dpbmRvd19ofSJdCiAgICAgICAgaWYgdXNlX293bl9icm93c2VyOgogICAgICAgICAgICBjaHJvbWVfcGF0aCA9IG9zLmdldGVudigiQ0hST01FX1BBVEgiLCBOb25lKQogICAgICAgICAgICBpZiBjaHJvbWVfcGF0aCA9PSAiIjoKICAgICAgICAgICAgICAgIGNocm9tZV9wYXRoID0gTm9uZQogICAgICAgICAgICBjaHJvbWVfdXNlcl9kYXRhID0gb3MuZ2V0ZW52KCJDSFJPTUVfVVNFUl9EQVRBIiwgTm9uZSkKICAgICAgICAgICAgaWYgY2hyb21lX3VzZXJfZGF0YToKICAgICAgICAgICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3MgKz0gW2YiLS11c2VyLWRhdGEtZGlyPXtjaHJvbWVfdXNlcl9kYXRhfSJdCiAgICAgICAgZWxzZToKICAgICAgICAgICAgY2hyb21lX3BhdGggPSBOb25lCiAgICAgICAgICAgIAogICAgICAgIGlmIF9nbG9iYWxfYnJvd3NlciBpcyBOb25lOgogICAgICAgICAgICBfZ2xvYmFsX2Jyb3dzZXIgPSBCcm93c2VyKAogICAgICAgICAgICAgICAgY29uZmlnPUJyb3dzZXJDb25maWcoCiAgICAgICAgICAgICAgICAgICAgaGVhZGxlc3M9aGVhZGxlc3MsCiAgICAgICAgICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICAgICAgICAgIGNocm9tZV9pbnN0YW5jZV9wYXRoPWNocm9tZV9wYXRoLAogICAgICAgICAgICAgICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3M9ZXh0cmFfY2hyb21pdW1fYXJncywKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgKQoKICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCBpcyBOb25lOgogICAgICAgICAgICBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCA9IGF3YWl0IF9nbG9iYWxfYnJvd3Nlci5uZXdfY29udGV4dCgKICAgICAgICAgICAgICAgIGNvbmZpZz1Ccm93c2VyQ29udGV4dENvbmZpZygKICAgICAgICAgICAgICAgICAgICB0cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCBpZiBzYXZlX3RyYWNlX3BhdGggZWxzZSBOb25lLAogICAgICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCBpZiBzYXZlX3JlY29yZGluZ19wYXRoIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICBub192aWV3cG9ydD1GYWxzZSwKICAgICAgICAgICAgICAgICAgICBicm93c2VyX3dpbmRvd19zaXplPUJyb3dzZXJDb250ZXh0V2luZG93U2l6ZSgKICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9d2luZG93X3csIGhlaWdodD13aW5kb3dfaAogICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgYWdlbnQgPSBBZ2VudCgKICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICBsbG09bGxtLAogICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgIGJyb3dzZXI9X2dsb2JhbF9icm93c2VyLAogICAgICAgICAgICBicm93c2VyX2NvbnRleHQ9X2dsb2JhbF9icm93c2VyX2NvbnRleHQsCiAgICAgICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwPW1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICApCiAgICAgICAgaGlzdG9yeSA9IGF3YWl0IGFnZW50LnJ1bihtYXhfc3RlcHM9bWF4X3N0ZXBzKQoKICAgICAgICBoaXN0b3J5X2ZpbGUgPSBvcy5wYXRoLmpvaW4oc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsIGYie2FnZW50LmFnZW50X2lkfS5qc29uIikKICAgICAgICBhZ2VudC5zYXZlX2hpc3RvcnkoaGlzdG9yeV9maWxlKQoKICAgICAgICBmaW5hbF9yZXN1bHQgPSBoaXN0b3J5LmZpbmFsX3Jlc3VsdCgpCiAgICAgICAgZXJyb3JzID0gaGlzdG9yeS5lcnJvcnMoKQogICAgICAgIG1vZGVsX2FjdGlvbnMgPSBoaXN0b3J5Lm1vZGVsX2FjdGlvbnMoKQogICAgICAgIG1vZGVsX3Rob3VnaHRzID0gaGlzdG9yeS5tb2RlbF90aG91Z2h0cygpCgogICAgICAgIHRyYWNlX2ZpbGUgPSBnZXRfbGF0ZXN0X2ZpbGVzKHNhdmVfdHJhY2VfcGF0aCkKCiAgICAgICAgcmV0dXJuIGZpbmFsX3Jlc3VsdCwgZXJyb3JzLCBtb2RlbF9hY3Rpb25zLCBtb2RlbF90aG91Z2h0cywgdHJhY2VfZmlsZS5nZXQoJy56aXAnKSwgaGlzdG9yeV9maWxlCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgaW1wb3J0IHRyYWNlYmFjawogICAgICAgIHRyYWNlYmFjay5wcmludF9leGMoKQogICAgICAgIGVycm9ycyA9IHN0cihlKSArICJcbiIgKyB0cmFjZWJhY2suZm9ybWF0X2V4YygpCiAgICAgICAgcmV0dXJuICcnLCBlcnJvcnMsICcnLCAnJywgTm9uZSwgTm9uZQogICAgZmluYWxseToKICAgICAgICAjIEhhbmRsZSBjbGVhbnVwIGJhc2VkIG9uIHBlcnNpc3RlbmNlIGNvbmZpZ3VyYXRpb24KICAgICAgICBpZiBub3Qga2VlcF9icm93c2VyX29wZW46CiAgICAgICAgICAgIGlmIF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0OgogICAgICAgICAgICAgICAgYXdhaXQgX2dsb2JhbF9icm93c2VyX2NvbnRleHQuY2xvc2UoKQogICAgICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBOb25lCgogICAgICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXI6CiAgICAgICAgICAgICAgICBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXIuY2xvc2UoKQogICAgICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyID0gTm9uZQoKYXN5bmMgZGVmIHJ1bl9jdXN0b21fYWdlbnQoCiAgICAgICAgbGxtLAogICAgICAgIHVzZV9vd25fYnJvd3NlciwKICAgICAgICBrZWVwX2Jyb3dzZXJfb3BlbiwKICAgICAgICBoZWFkbGVzcywKICAgICAgICBkaXNhYmxlX3NlY3VyaXR5LAogICAgICAgIHdpbmRvd193LAogICAgICAgIHdpbmRvd19oLAogICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgc2F2ZV90cmFjZV9wYXRoLAogICAgICAgIHRhc2ssCiAgICAgICAgYWRkX2luZm9zLAogICAgICAgIG1heF9zdGVwcywKICAgICAgICB1c2VfdmlzaW9uLAogICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2QKKToKICAgIHRyeToKICAgICAgICBnbG9iYWwgX2dsb2JhbF9icm93c2VyLCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwgX2dsb2JhbF9hZ2VudF9zdGF0ZQoKICAgICAgICAjIENsZWFyIGFueSBwcmV2aW91cyBzdG9wIHJlcXVlc3QKICAgICAgICBfZ2xvYmFsX2FnZW50X3N0YXRlLmNsZWFyX3N0b3AoKQoKICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzID0gW2YiLS13aW5kb3ctc2l6ZT17d2luZG93X3d9LHt3aW5kb3dfaH0iXQogICAgICAgIGlmIHVzZV9vd25fYnJvd3NlcjoKICAgICAgICAgICAgY2hyb21lX3BhdGggPSBvcy5nZXRlbnYoIkNIUk9NRV9QQVRIIiwgTm9uZSkKICAgICAgICAgICAgaWYgY2hyb21lX3BhdGggPT0gIiI6CiAgICAgICAgICAgICAgICBjaHJvbWVfcGF0aCA9IE5vbmUKICAgICAgICAgICAgY2hyb21lX3VzZXJfZGF0YSA9IG9zLmdldGVudigiQ0hST01FX1VTRVJfREFUQSIsIE5vbmUpCiAgICAgICAgICAgIGlmIGNocm9tZV91c2VyX2RhdGE6CiAgICAgICAgICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzICs9IFtmIi0tdXNlci1kYXRhLWRpcj17Y2hyb21lX3VzZXJfZGF0YX0iXQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGNocm9tZV9wYXRoID0gTm9uZQoKICAgICAgICBjb250cm9sbGVyID0gQ3VzdG9tQ29udHJvbGxlcigpCgogICAgICAgICMgSW5pdGlhbGl6ZSBnbG9iYWwgYnJvd3NlciBpZiBuZWVkZWQKICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXIgaXMgTm9uZToKICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyID0gQ3VzdG9tQnJvd3NlcigKICAgICAgICAgICAgICAgIGNvbmZpZz1Ccm93c2VyQ29uZmlnKAogICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgICAgICBjaHJvbWVfaW5zdGFuY2VfcGF0aD1jaHJvbWVfcGF0aCwKICAgICAgICAgICAgICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzPWV4dHJhX2Nocm9taXVtX2FyZ3MsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKCiAgICAgICAgaWYgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgaXMgTm9uZToKICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXIubmV3X2NvbnRleHQoCiAgICAgICAgICAgICAgICBjb25maWc9QnJvd3NlckNvbnRleHRDb25maWcoCiAgICAgICAgICAgICAgICAgICAgdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGggaWYgc2F2ZV90cmFjZV9wYXRoIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGggaWYgc2F2ZV9yZWNvcmRpbmdfcGF0aCBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgbm9fdmlld3BvcnQ9RmFsc2UsCiAgICAgICAgICAgICAgICAgICAgYnJvd3Nlcl93aW5kb3dfc2l6ZT1Ccm93c2VyQ29udGV4dFdpbmRvd1NpemUoCiAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPXdpbmRvd193LCBoZWlnaHQ9d2luZG93X2gKICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICApCiAgICAgICAgICAgIAogICAgICAgICMgQ3JlYXRlIGFuZCBydW4gYWdlbnQKICAgICAgICBhZ2VudCA9IEN1c3RvbUFnZW50KAogICAgICAgICAgICB0YXNrPXRhc2ssCiAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgIHVzZV92aXNpb249dXNlX3Zpc2lvbiwKICAgICAgICAgICAgbGxtPWxsbSwKICAgICAgICAgICAgYnJvd3Nlcj1fZ2xvYmFsX2Jyb3dzZXIsCiAgICAgICAgICAgIGJyb3dzZXJfY29udGV4dD1fZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwKICAgICAgICAgICAgY29udHJvbGxlcj1jb250cm9sbGVyLAogICAgICAgICAgICBzeXN0ZW1fcHJvbXB0X2NsYXNzPUN1c3RvbVN5c3RlbVByb21wdCwKICAgICAgICAgICAgYWdlbnRfcHJvbXB0X2NsYXNzPUN1c3RvbUFnZW50TWVzc2FnZVByb21wdCwKICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgIGFnZW50X3N0YXRlPV9nbG9iYWxfYWdlbnRfc3RhdGUsCiAgICAgICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2Q9dG9vbF9jYWxsaW5nX21ldGhvZAogICAgICAgICkKICAgICAgICBoaXN0b3J5ID0gYXdhaXQgYWdlbnQucnVuKG1heF9zdGVwcz1tYXhfc3RlcHMpCgogICAgICAgIGhpc3RvcnlfZmlsZSA9IG9zLnBhdGguam9pbihzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwgZiJ7YWdlbnQuYWdlbnRfaWR9Lmpzb24iKQogICAgICAgIGFnZW50LnNhdmVfaGlzdG9yeShoaXN0b3J5X2ZpbGUpCgogICAgICAgIGZpbmFsX3Jlc3VsdCA9IGhpc3RvcnkuZmluYWxfcmVzdWx0KCkKICAgICAgICBlcnJvcnMgPSBoaXN0b3J5LmVycm9ycygpCiAgICAgICAgbW9kZWxfYWN0aW9ucyA9IGhpc3RvcnkubW9kZWxfYWN0aW9ucygpCiAgICAgICAgbW9kZWxfdGhvdWdodHMgPSBoaXN0b3J5Lm1vZGVsX3Rob3VnaHRzKCkKCiAgICAgICAgdHJhY2VfZmlsZSA9IGdldF9sYXRlc3RfZmlsZXMoc2F2ZV90cmFjZV9wYXRoKSAgICAgICAgCgogICAgICAgIHJldHVybiBmaW5hbF9yZXN1bHQsIGVycm9ycywgbW9kZWxfYWN0aW9ucywgbW9kZWxfdGhvdWdodHMsIHRyYWNlX2ZpbGUuZ2V0KCcuemlwJyksIGhpc3RvcnlfZmlsZQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgIGltcG9ydCB0cmFjZWJhY2sKICAgICAgICB0cmFjZWJhY2sucHJpbnRfZXhjKCkKICAgICAgICBlcnJvcnMgPSBzdHIoZSkgKyAiXG4iICsgdHJhY2ViYWNrLmZvcm1hdF9leGMoKQogICAgICAgIHJldHVybiAnJywgZXJyb3JzLCAnJywgJycsIE5vbmUsIE5vbmUKICAgIGZpbmFsbHk6CiAgICAgICAgIyBIYW5kbGUgY2xlYW51cCBiYXNlZCBvbiBwZXJzaXN0ZW5jZSBjb25maWd1cmF0aW9uCiAgICAgICAgaWYgbm90IGtlZXBfYnJvd3Nlcl9vcGVuOgogICAgICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dDoKICAgICAgICAgICAgICAgIGF3YWl0IF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0LmNsb3NlKCkKICAgICAgICAgICAgICAgIF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0ID0gTm9uZQoKICAgICAgICAgICAgaWYgX2dsb2JhbF9icm93c2VyOgogICAgICAgICAgICAgICAgYXdhaXQgX2dsb2JhbF9icm93c2VyLmNsb3NlKCkKICAgICAgICAgICAgICAgIF9nbG9iYWxfYnJvd3NlciA9IE5vbmUKCmFzeW5jIGRlZiBydW5fd2l0aF9zdHJlYW0oCiAgICBhZ2VudF90eXBlLAogICAgbGxtX3Byb3ZpZGVyLAogICAgbGxtX21vZGVsX25hbWUsCiAgICBsbG1fdGVtcGVyYXR1cmUsCiAgICBsbG1fYmFzZV91cmwsCiAgICBsbG1fYXBpX2tleSwKICAgIHVzZV9vd25fYnJvd3NlciwKICAgIGtlZXBfYnJvd3Nlcl9vcGVuLAogICAgaGVhZGxlc3MsCiAgICBkaXNhYmxlX3NlY3VyaXR5LAogICAgd2luZG93X3csCiAgICB3aW5kb3dfaCwKICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgIHNhdmVfdHJhY2VfcGF0aCwKICAgIGVuYWJsZV9yZWNvcmRpbmcsCiAgICB0YXNrLAogICAgYWRkX2luZm9zLAogICAgbWF4X3N0ZXBzLAogICAgdXNlX3Zpc2lvbiwKICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgdG9vbF9jYWxsaW5nX21ldGhvZAopOgogICAgZ2xvYmFsIF9nbG9iYWxfYWdlbnRfc3RhdGUKICAgIHN0cmVhbV92dyA9IDgwCiAgICBzdHJlYW1fdmggPSBpbnQoODAgKiB3aW5kb3dfaCAvLyB3aW5kb3dfdykKICAgIGlmIG5vdCBoZWFkbGVzczoKICAgICAgICByZXN1bHQgPSBhd2FpdCBydW5fYnJvd3Nlcl9hZ2VudCgKICAgICAgICAgICAgYWdlbnRfdHlwZT1hZ2VudF90eXBlLAogICAgICAgICAgICBsbG1fcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICBsbG1fbW9kZWxfbmFtZT1sbG1fbW9kZWxfbmFtZSwKICAgICAgICAgICAgbGxtX3RlbXBlcmF0dXJlPWxsbV90ZW1wZXJhdHVyZSwKICAgICAgICAgICAgbGxtX2Jhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgbGxtX2FwaV9rZXk9bGxtX2FwaV9rZXksCiAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuPWtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgICAgICBoZWFkbGVzcz1oZWFkbGVzcywKICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICB3aW5kb3dfdz13aW5kb3dfdywKICAgICAgICAgICAgd2luZG93X2g9d2luZG93X2gsCiAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGg9c2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgICAgIHNhdmVfdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgICAgIGVuYWJsZV9yZWNvcmRpbmc9ZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICBhZGRfaW5mb3M9YWRkX2luZm9zLAogICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwPW1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICApCiAgICAgICAgIyBBZGQgSFRNTCBjb250ZW50IGF0IHRoZSBzdGFydCBvZiB0aGUgcmVzdWx0IGFycmF5CiAgICAgICAgaHRtbF9jb250ZW50ID0gZiI8aDEgc3R5bGU9J3dpZHRoOntzdHJlYW1fdnd9dnc7IGhlaWdodDp7c3RyZWFtX3ZofXZoJz5Vc2luZyBicm93c2VyLi4uPC9oMT4iCiAgICAgICAgeWllbGQgW2h0bWxfY29udGVudF0gKyBsaXN0KHJlc3VsdCkKICAgIGVsc2U6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBfZ2xvYmFsX2FnZW50X3N0YXRlLmNsZWFyX3N0b3AoKQogICAgICAgICAgICAjIFJ1biB0aGUgYnJvd3NlciBhZ2VudCBpbiB0aGUgYmFja2dyb3VuZAogICAgICAgICAgICBhZ2VudF90YXNrID0gYXN5bmNpby5jcmVhdGVfdGFzaygKICAgICAgICAgICAgICAgIHJ1bl9icm93c2VyX2FnZW50KAogICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGU9YWdlbnRfdHlwZSwKICAgICAgICAgICAgICAgICAgICBsbG1fcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICAgICAgICAgIGxsbV9tb2RlbF9uYW1lPWxsbV9tb2RlbF9uYW1lLAogICAgICAgICAgICAgICAgICAgIGxsbV90ZW1wZXJhdHVyZT1sbG1fdGVtcGVyYXR1cmUsCiAgICAgICAgICAgICAgICAgICAgbGxtX2Jhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgICAgICAgICBsbG1fYXBpX2tleT1sbG1fYXBpX2tleSwKICAgICAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXI9dXNlX293bl9icm93c2VyLAogICAgICAgICAgICAgICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuPWtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgICAgICB3aW5kb3dfdz13aW5kb3dfdywKICAgICAgICAgICAgICAgICAgICB3aW5kb3dfaD13aW5kb3dfaCwKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGg9c2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgc2F2ZV90cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCwKICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nPWVuYWJsZV9yZWNvcmRpbmcsCiAgICAgICAgICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgICAgICAgICAgbWF4X3N0ZXBzPW1heF9zdGVwcywKICAgICAgICAgICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICAgICAgdG9vbF9jYWxsaW5nX21ldGhvZD10b29sX2NhbGxpbmdfbWV0aG9kCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKCiAgICAgICAgICAgICMgSW5pdGlhbGl6ZSB2YWx1ZXMgZm9yIHN0cmVhbWluZwogICAgICAgICAgICBodG1sX2NvbnRlbnQgPSBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPlVzaW5nIGJyb3dzZXIuLi48L2gxPiIKICAgICAgICAgICAgZmluYWxfcmVzdWx0ID0gZXJyb3JzID0gbW9kZWxfYWN0aW9ucyA9IG1vZGVsX3Rob3VnaHRzID0gIiIKICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvcyA9IHRyYWNlID0gaGlzdG9yeV9maWxlID0gTm9uZQoKCiAgICAgICAgICAgICMgUGVyaW9kaWNhbGx5IHVwZGF0ZSB0aGUgc3RyZWFtIHdoaWxlIHRoZSBhZ2VudCB0YXNrIGlzIHJ1bm5pbmcKICAgICAgICAgICAgd2hpbGUgbm90IGFnZW50X3Rhc2suZG9uZSgpOgogICAgICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgICAgIGVuY29kZWRfc2NyZWVuc2hvdCA9IGF3YWl0IGNhcHR1cmVfc2NyZWVuc2hvdChfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCkKICAgICAgICAgICAgICAgICAgICBpZiBlbmNvZGVkX3NjcmVlbnNob3QgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCA9IGYnPGltZyBzcmM9ImRhdGE6aW1hZ2UvanBlZztiYXNlNjQse2VuY29kZWRfc2NyZWVuc2hvdH0iIHN0eWxlPSJ3aWR0aDp7c3RyZWFtX3Z3fXZ3OyBoZWlnaHQ6e3N0cmVhbV92aH12aCA7IGJvcmRlcjoxcHggc29saWQgI2NjYzsiPicKICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICBodG1sX2NvbnRlbnQgPSBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPldhaXRpbmcgZm9yIGJyb3dzZXIgc2Vzc2lvbi4uLjwvaDE+IgogICAgICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCA9IGYiPGgxIHN0eWxlPSd3aWR0aDp7c3RyZWFtX3Z3fXZ3OyBoZWlnaHQ6e3N0cmVhbV92aH12aCc+V2FpdGluZyBmb3IgYnJvd3NlciBzZXNzaW9uLi4uPC9oMT4iCgogICAgICAgICAgICAgICAgaWYgX2dsb2JhbF9hZ2VudF9zdGF0ZSBhbmQgX2dsb2JhbF9hZ2VudF9zdGF0ZS5pc19zdG9wX3JlcXVlc3RlZCgpOgogICAgICAgICAgICAgICAgICAgIHlpZWxkIFsKICAgICAgICAgICAgICAgICAgICAgICAgaHRtbF9jb250ZW50LAogICAgICAgICAgICAgICAgICAgICAgICBmaW5hbF9yZXN1bHQsCiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfdGhvdWdodHMsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhdGVzdF92aWRlb3MsCiAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlLAogICAgICAgICAgICAgICAgICAgICAgICBoaXN0b3J5X2ZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcHBpbmcuLi4iLCBpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHN0b3BfYnV0dG9uCiAgICAgICAgICAgICAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHJ1bl9idXR0b24KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgeWllbGQgWwogICAgICAgICAgICAgICAgICAgICAgICBodG1sX2NvbnRlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JzLAogICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9hY3Rpb25zLAogICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cywKICAgICAgICAgICAgICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvcywKICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UsCiAgICAgICAgICAgICAgICAgICAgICAgIGhpc3RvcnlfZmlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksICAjIFJlLWVuYWJsZSBzdG9wIGJ1dHRvbgogICAgICAgICAgICAgICAgICAgICAgICBnci51cGRhdGUoaW50ZXJhY3RpdmU9VHJ1ZSkgICMgUmUtZW5hYmxlIHJ1biBidXR0b24KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICBhd2FpdCBhc3luY2lvLnNsZWVwKDAuMDUpCgogICAgICAgICAgICAjIE9uY2UgdGhlIGFnZW50IHRhc2sgY29tcGxldGVzLCBnZXQgdGhlIHJlc3VsdHMKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgcmVzdWx0ID0gYXdhaXQgYWdlbnRfdGFzawogICAgICAgICAgICAgICAgZmluYWxfcmVzdWx0LCBlcnJvcnMsIG1vZGVsX2FjdGlvbnMsIG1vZGVsX3Rob3VnaHRzLCBsYXRlc3RfdmlkZW9zLCB0cmFjZSwgaGlzdG9yeV9maWxlLCBzdG9wX2J1dHRvbiwgcnVuX2J1dHRvbiA9IHJlc3VsdAogICAgICAgICAgICAgICAgIyBQTEFDRUhPTERFUl9UQVNLX0NPTVBMRVRFRF9TT1VORAogICAgICAgICAgICBleGNlcHQgZ3IuRXJyb3I6CiAgICAgICAgICAgICAgICBmaW5hbF9yZXN1bHQgPSAiIgogICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9ucyA9ICIiCiAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cyA9ICIiCiAgICAgICAgICAgICAgICBsYXRlc3RfdmlkZW9zID0gdHJhY2UgPSBoaXN0b3J5X2ZpbGUgPSBOb25lCgogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgICAgICBlcnJvcnMgPSBmIkFnZW50IGVycm9yOiB7c3RyKGUpfSIKCiAgICAgICAgICAgIHlpZWxkIFsKICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCwKICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwKICAgICAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgICAgIG1vZGVsX2FjdGlvbnMsCiAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cywKICAgICAgICAgICAgICAgIGxhdGVzdF92aWRlb3MsCiAgICAgICAgICAgICAgICB0cmFjZSwKICAgICAgICAgICAgICAgIGhpc3RvcnlfZmlsZSwKICAgICAgICAgICAgICAgIHN0b3BfYnV0dG9uLAogICAgICAgICAgICAgICAgcnVuX2J1dHRvbgogICAgICAgICAgICBdCgogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgaW1wb3J0IHRyYWNlYmFjawogICAgICAgICAgICB5aWVsZCBbCiAgICAgICAgICAgICAgICBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPldhaXRpbmcgZm9yIGJyb3dzZXIgc2Vzc2lvbi4uLjwvaDE+IiwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgZiJFcnJvcjoge3N0cihlKX1cbnt0cmFjZWJhY2suZm9ybWF0X2V4YygpfSIsCiAgICAgICAgICAgICAgICAiIiwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgTm9uZSwKICAgICAgICAgICAgICAgIE5vbmUsCiAgICAgICAgICAgICAgICBOb25lLAogICAgICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksICAjIFJlLWVuYWJsZSBzdG9wIGJ1dHRvbgogICAgICAgICAgICAgICAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpICAgICMgUmUtZW5hYmxlIHJ1biBidXR0b24KICAgICAgICAgICAgXQoKIyBEZWZpbmUgdGhlIHRoZW1lIG1hcCBnbG9iYWxseQp0aGVtZV9tYXAgPSB7CiAgICAiRGVmYXVsdCI6IERlZmF1bHQoKSwKICAgICJTb2Z0IjogU29mdCgpLAogICAgIk1vbm9jaHJvbWUiOiBNb25vY2hyb21lKCksCiAgICAiR2xhc3MiOiBHbGFzcygpLAogICAgIk9yaWdpbiI6IE9yaWdpbigpLAogICAgIkNpdHJ1cyI6IENpdHJ1cygpLAogICAgIk9jZWFuIjogT2NlYW4oKSwKICAgICJCYXNlIjogQmFzZSgpCn0KCmFzeW5jIGRlZiBjbG9zZV9nbG9iYWxfYnJvd3NlcigpOgogICAgZ2xvYmFsIF9nbG9iYWxfYnJvd3NlciwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQKCiAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dDoKICAgICAgICBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dC5jbG9zZSgpCiAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBOb25lCgogICAgaWYgX2dsb2JhbF9icm93c2VyOgogICAgICAgIGF3YWl0IF9nbG9iYWxfYnJvd3Nlci5jbG9zZSgpCiAgICAgICAgX2dsb2JhbF9icm93c2VyID0gTm9uZQogICAgICAgIAphc3luYyBkZWYgcnVuX2RlZXBfc2VhcmNoKHJlc2VhcmNoX3Rhc2ssIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0LCBtYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwgdXNlX3Zpc2lvbiwgdXNlX293bl9icm93c2VyLCBoZWFkbGVzcyk6CiAgICBmcm9tIHNyYy51dGlscy5kZWVwX3Jlc2VhcmNoIGltcG9ydCBkZWVwX3Jlc2VhcmNoCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZQoKICAgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdAogICAgX2dsb2JhbF9hZ2VudF9zdGF0ZS5jbGVhcl9zdG9wKCkKICAgIAogICAgbGxtID0gdXRpbHMuZ2V0X2xsbV9tb2RlbCgKICAgICAgICAgICAgcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICBtb2RlbF9uYW1lPWxsbV9tb2RlbF9uYW1lLAogICAgICAgICAgICB0ZW1wZXJhdHVyZT1sbG1fdGVtcGVyYXR1cmUsCiAgICAgICAgICAgIGJhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgYXBpX2tleT1sbG1fYXBpX2tleSwKICAgICAgICApCiAgICBtYXJrZG93bl9jb250ZW50LCBmaWxlX3BhdGggPSBhd2FpdCBkZWVwX3Jlc2VhcmNoKHJlc2VhcmNoX3Rhc2ssIGxsbSwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhfc2VhcmNoX2l0ZXJhdGlvbnM9bWF4X3NlYXJjaF9pdGVyYXRpb25faW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3F1ZXJ5X251bT1tYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAKICAgIHJldHVybiBtYXJrZG93bl9jb250ZW50LCBmaWxlX3BhdGgsIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcCIsIGludGVyYWN0aXZlPVRydWUpLCAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpIAogICAgCgpkZWYgY3JlYXRlX3VpKGNvbmZpZywgdGhlbWVfbmFtZT0iT2NlYW4iKToKICAgIGNzcyA9ICIiIgogICAgLmdyYWRpby1jb250YWluZXIgewogICAgICAgIG1heC13aWR0aDogMTIwMHB4ICFpbXBvcnRhbnQ7CiAgICAgICAgbWFyZ2luOiBhdXRvICFpbXBvcnRhbnQ7CiAgICAgICAgcGFkZGluZy10b3A6IDIwcHggIWltcG9ydGFudDsKICAgIH0KICAgIC5oZWFkZXItdGV4dCB7CiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgICAgIG1hcmdpbi1ib3R0b206IDMwcHg7CiAgICB9CiAgICAudGhlbWUtc2VjdGlvbiB7CiAgICAgICAgbWFyZ2luLWJvdHRvbTogMjBweDsKICAgICAgICBwYWRkaW5nOiAxNXB4OwogICAgICAgIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgICB9CiAgICAiIiIKCiAgICB3aXRoIGdyLkJsb2Nrcyh0aXRsZT0iUExBQ0VIT0xERVJfVElUTEUiLCB0aGVtZT10aGVtZV9tYXBbdGhlbWVfbmFtZV0sIGNzcz1jc3MpIGFzIGRlbW86CiAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgZ3IuTWFya2Rvd24oCiAgICAgICAgICAgICAgICAiIiIKICAgICAgICAgICAgICAgICMg8J+MkCBQTEFDRUhPTERFUl9IRUFERVJfVElUTEUKICAgICAgICAgICAgICAgICMjIyBDb250cm9sIHlvdXIgYnJvd3NlciB3aXRoIEFJIGFzc2lzdGFuY2UKICAgICAgICAgICAgICAgIFBMQUNFSE9MREVSX0FQSV9LRVlfTElOSwogICAgICAgICAgICAgICAgIiIiLAogICAgICAgICAgICAgICAgZWxlbV9jbGFzc2VzPVsiaGVhZGVyLXRleHQiXSwKICAgICAgICAgICAgKQoKICAgICAgICB3aXRoIGdyLlRhYnMoKSBhcyB0YWJzOgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIuKame+4jyBBZ2VudCBTZXR0aW5ncyIsIGlkPTEpOgogICAgICAgICAgICAgICAgd2l0aCBnci5Hcm91cCgpOgogICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGUgPSBnci5SYWRpbygKICAgICAgICAgICAgICAgICAgICAgICAgWyJvcmciLCAiY3VzdG9tIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBZ2VudCBUeXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydhZ2VudF90eXBlJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IlNlbGVjdCB0aGUgdHlwZSBvZiBhZ2VudCB0byB1c2UiLAogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLkNvbHVtbigpOgogICAgICAgICAgICAgICAgICAgICAgICBtYXhfc3RlcHMgPSBnci5TbGlkZXIoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhpbXVtPTIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snbWF4X3N0ZXBzJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTWF4IFJ1biBTdGVwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJNYXhpbXVtIG51bWJlciBvZiBzdGVwcyB0aGUgYWdlbnQgd2lsbCB0YWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBtYXhfYWN0aW9uc19wZXJfc3RlcCA9IGdyLlNsaWRlcigKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW09MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGltdW09MjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ21heF9hY3Rpb25zX3Blcl9zdGVwJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTWF4IEFjdGlvbnMgcGVyIFN0ZXAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iTWF4aW11bSBudW1iZXIgb2YgYWN0aW9ucyB0aGUgYWdlbnQgd2lsbCB0YWtlIHBlciBzdGVwIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuQ29sdW1uKCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHVzZV92aXNpb24gPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJVc2UgVmlzaW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1sndXNlX3Zpc2lvbiddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iRW5hYmxlIHZpc3VhbCBwcm9jZXNzaW5nIGNhcGFiaWxpdGllcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgdG9vbF9jYWxsaW5nX21ldGhvZCA9IGdyLkRyb3Bkb3duKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlRvb2wgQ2FsbGluZyBNZXRob2QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd0b29sX2NhbGxpbmdfbWV0aG9kJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZT1UcnVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dfY3VzdG9tX3ZhbHVlPVRydWUsICAjIEFsbG93IHVzZXJzIHRvIGlucHV0IGN1c3RvbSBtb2RlbCBuYW1lcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hvaWNlcz1bImF1dG8iLCAianNvbl9zY2hlbWEiLCAiZnVuY3Rpb25fY2FsbGluZyJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iVG9vbCBDYWxscyBGdW50aW9uIE5hbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZT1GYWxzZQogICAgICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCflKcgTExNIENvbmZpZ3VyYXRpb24iLCBpZD0yKToKICAgICAgICAgICAgICAgIHdpdGggZ3IuR3JvdXAoKToKICAgICAgICAgICAgICAgICAgICBsbG1fcHJvdmlkZXIgPSBnci5Ecm9wZG93bigKICAgICAgICAgICAgICAgICAgICAgICAgY2hvaWNlcz1bcHJvdmlkZXIgZm9yIHByb3ZpZGVyLG1vZGVsIGluIHV0aWxzLm1vZGVsX25hbWVzLml0ZW1zKCldLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTExNIFByb3ZpZGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydsbG1fcHJvdmlkZXInXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU2VsZWN0IHlvdXIgcHJlZmVycmVkIGxhbmd1YWdlIG1vZGVsIHByb3ZpZGVyIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBsbG1fbW9kZWxfbmFtZSA9IGdyLkRyb3Bkb3duKAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTW9kZWwgTmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGNob2ljZXM9dXRpbHMubW9kZWxfbmFtZXNbJ29wZW5haSddLAogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2xsbV9tb2RlbF9uYW1lJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93X2N1c3RvbV92YWx1ZT1UcnVlLCAgIyBBbGxvdyB1c2VycyB0byBpbnB1dCBjdXN0b20gbW9kZWwgbmFtZXMKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU2VsZWN0IGEgbW9kZWwgZnJvbSB0aGUgZHJvcGRvd24gb3IgdHlwZSBhIGN1c3RvbSBtb2RlbCBuYW1lIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBsbG1fdGVtcGVyYXR1cmUgPSBnci5TbGlkZXIoCiAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW09MC4wLAogICAgICAgICAgICAgICAgICAgICAgICBtYXhpbXVtPTIuMCwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydsbG1fdGVtcGVyYXR1cmUnXSwKICAgICAgICAgICAgICAgICAgICAgICAgc3RlcD0wLjEsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJUZW1wZXJhdHVyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IkNvbnRyb2xzIHJhbmRvbW5lc3MgaW4gbW9kZWwgb3V0cHV0cyIKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICAgICAgbGxtX2Jhc2VfdXJsID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJCYXNlIFVSTCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2xsbV9iYXNlX3VybCddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQVBJIGVuZHBvaW50IFVSTCAoaWYgcmVxdWlyZWQpIgogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIGxsbV9hcGlfa2V5ID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBUEkgS2V5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9InBhc3N3b3JkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snbGxtX2FwaV9rZXknXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IllvdXIgQVBJIGtleSAobGVhdmUgYmxhbmsgdG8gdXNlIC5lbnYpIgogICAgICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCfjJAgQnJvd3NlciBTZXR0aW5ncyIsIGlkPTMpOgogICAgICAgICAgICAgICAgd2l0aCBnci5Hcm91cCgpOgogICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuUm93KCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3NlciA9IGdyLkNoZWNrYm94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlVzZSBPd24gQnJvd3NlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ3VzZV9vd25fYnJvd3NlciddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iVXNlIHlvdXIgZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAga2VlcF9icm93c2VyX29wZW4gPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJLZWVwIEJyb3dzZXIgT3BlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2tlZXBfYnJvd3Nlcl9vcGVuJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJLZWVwIEJyb3dzZXIgT3BlbiBiZXR3ZWVuIFRhc2tzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBoZWFkbGVzcyA9IGdyLkNoZWNrYm94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IkhlYWRsZXNzIE1vZGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydoZWFkbGVzcyddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iUnVuIGJyb3dzZXIgd2l0aG91dCBHVUkiLAogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHkgPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJEaXNhYmxlIFNlY3VyaXR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snZGlzYWJsZV9zZWN1cml0eSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iRGlzYWJsZSBicm93c2VyIHNlY3VyaXR5IGZlYXR1cmVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nID0gZ3IuQ2hlY2tib3goCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iRW5hYmxlIFJlY29yZGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2VuYWJsZV9yZWNvcmRpbmcnXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IkVuYWJsZSBzYXZpbmcgYnJvd3NlciByZWNvcmRpbmdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3dfdyA9IGdyLk51bWJlcigKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJXaW5kb3cgV2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd3aW5kb3dfdyddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQnJvd3NlciB3aW5kb3cgd2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvd19oID0gZ3IuTnVtYmVyKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IldpbmRvdyBIZWlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd3aW5kb3dfaCddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQnJvd3NlciB3aW5kb3cgaGVpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlJlY29yZGluZyBQYXRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9ImUuZy4gLi90bXAvcmVjb3JkX3ZpZGVvcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV9yZWNvcmRpbmdfcGF0aCddLAogICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJQYXRoIHRvIHNhdmUgYnJvd3NlciByZWNvcmRpbmdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU9VHJ1ZSwgICMgQWxsb3cgZWRpdGluZyBvbmx5IGlmIHJlY29yZGluZyBpcyBlbmFibGVkCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICBzYXZlX3RyYWNlX3BhdGggPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iVHJhY2UgUGF0aCIsCiAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPSJlLmcuIC4vdG1wL3RyYWNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV90cmFjZV9wYXRoJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IlBhdGggdG8gc2F2ZSBBZ2VudCB0cmFjZXMiLAogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZT1UcnVlLAogICAgICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGggPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iQWdlbnQgSGlzdG9yeSBTYXZlIFBhdGgiLAogICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj0iZS5nLiwgLi90bXAvYWdlbnRfaGlzdG9yeSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgnXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU3BlY2lmeSB0aGUgZGlyZWN0b3J5IHdoZXJlIGFnZW50IGhpc3Rvcnkgc2hvdWxkIGJlIHNhdmVkLiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUsCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgd2l0aCBnci5UYWJJdGVtKCLwn6SWIFJ1biBBZ2VudCIsIGlkPTQpOgogICAgICAgICAgICAgICAgdGFzayA9IGdyLlRleHRib3goCiAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlRhc2sgRGVzY3JpcHRpb24iLAogICAgICAgICAgICAgICAgICAgIGxpbmVzPTQsCiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9IkVudGVyIHlvdXIgdGFzayBoZXJlLi4uIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ3Rhc2snXSwKICAgICAgICAgICAgICAgICAgICBpbmZvPSJEZXNjcmliZSB3aGF0IHlvdSB3YW50IHRoZSBhZ2VudCB0byBkbyIsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBhZGRfaW5mb3MgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBZGRpdGlvbmFsIEluZm9ybWF0aW9uIiwKICAgICAgICAgICAgICAgICAgICBsaW5lcz0zLAogICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPSJBZGQgYW55IGhlbHBmdWwgY29udGV4dCBvciBpbnN0cnVjdGlvbnMuLi4iLAogICAgICAgICAgICAgICAgICAgIGluZm89Ik9wdGlvbmFsIGhpbnRzIHRvIGhlbHAgdGhlIExMTSBjb21wbGV0ZSB0aGUgdGFzayIsCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICBydW5fYnV0dG9uID0gZ3IuQnV0dG9uKCLilrbvuI8gUnVuIEFnZW50IiwgdmFyaWFudD0icHJpbWFyeSIsIHNjYWxlPTIpCiAgICAgICAgICAgICAgICAgICAgc3RvcF9idXR0b24gPSBnci5CdXR0b24oIuKPue+4jyBTdG9wIiwgdmFyaWFudD0ic3RvcCIsIHNjYWxlPTEpCiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgIGJyb3dzZXJfdmlldyA9IGdyLkhUTUwoCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPSI8aDEgc3R5bGU9J3dpZHRoOjgwdnc7IGhlaWdodDo1MHZoJz5XYWl0aW5nIGZvciBicm93c2VyIHNlc3Npb24uLi48L2gxPiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJMaXZlIEJyb3dzZXIgVmlldyIsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIAogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCfp5AgRGVlcCBSZXNlYXJjaCIsIGlkPTUpOgogICAgICAgICAgICAgICAgcmVzZWFyY2hfdGFza19pbnB1dCA9IGdyLlRleHRib3gobGFiZWw9IlJlc2VhcmNoIFRhc2siLCBsaW5lcz01LCB2YWx1ZT0iQ29tcG9zZSBhIHJlcG9ydCBvbiB0aGUgdXNlIG9mIFJlaW5mb3JjZW1lbnQgTGVhcm5pbmcgZm9yIHRyYWluaW5nIExhcmdlIExhbmd1YWdlIE1vZGVscywgZW5jb21wYXNzaW5nIGl0cyBvcmlnaW5zLCBjdXJyZW50IGFkdmFuY2VtZW50cywgYW5kIGZ1dHVyZSBwcm9zcGVjdHMsIHN1YnN0YW50aWF0ZWQgd2l0aCBleGFtcGxlcyBvZiByZWxldmFudCBtb2RlbHMgYW5kIHRlY2huaXF1ZXMuIFRoZSByZXBvcnQgc2hvdWxkIHJlZmxlY3Qgb3JpZ2luYWwgaW5zaWdodHMgYW5kIGFuYWx5c2lzLCBtb3ZpbmcgYmV5b25kIG1lcmUgc3VtbWFyaXphdGlvbiBvZiBleGlzdGluZyBsaXRlcmF0dXJlLiIpCiAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0ID0gZ3IuTnVtYmVyKGxhYmVsPSJNYXggU2VhcmNoIEl0ZXJhdGlvbiIsIHZhbHVlPTMsIHByZWNpc2lvbj0wKSAjIHByZWNpc2lvbj0wIOehruS/neaYr+aVtOaVsAogICAgICAgICAgICAgICAgICAgIG1heF9xdWVyeV9wZXJfaXRlcl9pbnB1dCA9IGdyLk51bWJlcihsYWJlbD0iTWF4IFF1ZXJ5IHBlciBJdGVyYXRpb24iLCB2YWx1ZT0xLCBwcmVjaXNpb249MCkgIyBwcmVjaXNpb249MCDnoa7kv53mmK/mlbTmlbAKICAgICAgICAgICAgICAgIHdpdGggZ3IuUm93KCk6CiAgICAgICAgICAgICAgICAgICAgcmVzZWFyY2hfYnV0dG9uID0gZ3IuQnV0dG9uKCLilrbvuI8gUnVuIERlZXAgUmVzZWFyY2giLCB2YXJpYW50PSJwcmltYXJ5Iiwgc2NhbGU9MikKICAgICAgICAgICAgICAgICAgICBzdG9wX3Jlc2VhcmNoX2J1dHRvbiA9IGdyLkJ1dHRvbigi4o+577iPIFN0b3AiLCB2YXJpYW50PSJzdG9wIiwgc2NhbGU9MSkKICAgICAgICAgICAgICAgIG1hcmtkb3duX291dHB1dF9kaXNwbGF5ID0gZ3IuTWFya2Rvd24obGFiZWw9IlJlc2VhcmNoIFJlcG9ydCIpCiAgICAgICAgICAgICAgICBtYXJrZG93bl9kb3dubG9hZCA9IGdyLkZpbGUobGFiZWw9IkRvd25sb2FkIFJlc2VhcmNoIFJlcG9ydCIpCgoKICAgICAgICAgICAgd2l0aCBnci5UYWJJdGVtKCLwn5OKIFJlc3VsdHMiLCBpZD02KToKICAgICAgICAgICAgICAgIHdpdGggZ3IuR3JvdXAoKToKCiAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5nX2Rpc3BsYXkgPSBnci5WaWRlbyhsYWJlbD0iTGF0ZXN0IFJlY29yZGluZyIpCgogICAgICAgICAgICAgICAgICAgIGdyLk1hcmtkb3duKCIjIyMgUmVzdWx0cyIpCiAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Db2x1bW4oKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdF9vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJGaW5hbCBSZXN1bHQiLCBsaW5lcz0zLCBzaG93X2xhYmVsPVRydWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Db2x1bW4oKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yc19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJFcnJvcnMiLCBsaW5lcz0zLCBzaG93X2xhYmVsPVRydWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLkNvbHVtbigpOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9uc19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJNb2RlbCBBY3Rpb25zIiwgbGluZXM9Mywgc2hvd19sYWJlbD1UcnVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuQ29sdW1uKCk6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0c19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJNb2RlbCBUaG91Z2h0cyIsIGxpbmVzPTMsIHNob3dfbGFiZWw9VHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICB0cmFjZV9maWxlID0gZ3IuRmlsZShsYWJlbD0iVHJhY2UgRmlsZSIpCgogICAgICAgICAgICAgICAgICAgIGFnZW50X2hpc3RvcnlfZmlsZSA9IGdyLkZpbGUobGFiZWw9IkFnZW50IEhpc3RvcnkiKQoKICAgICAgICAgICAgICAgICMgQmluZCB0aGUgc3RvcCBidXR0b24gY2xpY2sgZXZlbnQgYWZ0ZXIgZXJyb3JzX291dHB1dCBpcyBkZWZpbmVkCiAgICAgICAgICAgICAgICBzdG9wX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zdG9wX2FnZW50LAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVtlcnJvcnNfb3V0cHV0LCBzdG9wX2J1dHRvbiwgcnVuX2J1dHRvbl0sCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgIyBSdW4gYnV0dG9uIGNsaWNrIGhhbmRsZXIKICAgICAgICAgICAgICAgIHJ1bl9idXR0b24uY2xpY2soCiAgICAgICAgICAgICAgICAgICAgZm49cnVuX3dpdGhfc3RyZWFtLAogICAgICAgICAgICAgICAgICAgICAgICBpbnB1dHM9WwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlbnRfdHlwZSwgbGxtX3Byb3ZpZGVyLCBsbG1fbW9kZWxfbmFtZSwgbGxtX3RlbXBlcmF0dXJlLCBsbG1fYmFzZV91cmwsIGxsbV9hcGlfa2V5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX293bl9icm93c2VyLCBrZWVwX2Jyb3dzZXJfb3BlbiwgaGVhZGxlc3MsIGRpc2FibGVfc2VjdXJpdHksIHdpbmRvd193LCB3aW5kb3dfaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLCBzYXZlX3RyYWNlX3BhdGgsICAjIEluY2x1ZGUgdGhlIG5ldyBwYXRoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nLCB0YXNrLCBhZGRfaW5mb3MsIG1heF9zdGVwcywgdXNlX3Zpc2lvbiwgbWF4X2FjdGlvbnNfcGVyX3N0ZXAsIHRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVsKICAgICAgICAgICAgICAgICAgICAgICAgYnJvd3Nlcl92aWV3LCAgICAgICAgICAgIyBCcm93c2VyIHZpZXcKICAgICAgICAgICAgICAgICAgICAgICAgZmluYWxfcmVzdWx0X291dHB1dCwgICAgIyBGaW5hbCByZXN1bHQKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JzX291dHB1dCwgICAgICAgICAgIyBFcnJvcnMKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9uc19vdXRwdXQsICAgIyBNb2RlbCBhY3Rpb25zCiAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3Rob3VnaHRzX291dHB1dCwgICMgTW9kZWwgdGhvdWdodHMKICAgICAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5nX2Rpc3BsYXksICAgICAgIyBMYXRlc3QgcmVjb3JkaW5nCiAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlX2ZpbGUsICAgICAgICAgICAgICMgVHJhY2UgZmlsZQogICAgICAgICAgICAgICAgICAgICAgICBhZ2VudF9oaXN0b3J5X2ZpbGUsICAgICAjIEFnZW50IGhpc3RvcnkgZmlsZQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wX2J1dHRvbiwgICAgICAgICAgICAjIFN0b3AgYnV0dG9uCiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bl9idXR0b24gICAgICAgICAgICAgICMgUnVuIGJ1dHRvbgogICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICMgUnVuIERlZXAgUmVzZWFyY2gKICAgICAgICAgICAgICAgIHJlc2VhcmNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICAgICAgZm49cnVuX2RlZXBfc2VhcmNoLAogICAgICAgICAgICAgICAgICAgICAgICBpbnB1dHM9W3Jlc2VhcmNoX3Rhc2tfaW5wdXQsIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0LCBtYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwgdXNlX3Zpc2lvbiwgdXNlX293bl9icm93c2VyLCBoZWFkbGVzc10sCiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHM9W21hcmtkb3duX291dHB1dF9kaXNwbGF5LCBtYXJrZG93bl9kb3dubG9hZCwgc3RvcF9yZXNlYXJjaF9idXR0b24sIHJlc2VhcmNoX2J1dHRvbl0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICMgQmluZCB0aGUgc3RvcCBidXR0b24gY2xpY2sgZXZlbnQgYWZ0ZXIgZXJyb3JzX291dHB1dCBpcyBkZWZpbmVkCiAgICAgICAgICAgICAgICBzdG9wX3Jlc2VhcmNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zdG9wX3Jlc2VhcmNoX2FnZW50LAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVtzdG9wX3Jlc2VhcmNoX2J1dHRvbiwgcmVzZWFyY2hfYnV0dG9uXSwKICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgIHdpdGggZ3IuVGFiSXRlbSgi8J+OpSBSZWNvcmRpbmdzIiwgaWQ9Nyk6CiAgICAgICAgICAgICAgICBkZWYgbGlzdF9yZWNvcmRpbmdzKHNhdmVfcmVjb3JkaW5nX3BhdGgpOgogICAgICAgICAgICAgICAgICAgIGlmIG5vdCBvcy5wYXRoLmV4aXN0cyhzYXZlX3JlY29yZGluZ19wYXRoKToKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdCgogICAgICAgICAgICAgICAgICAgICMgR2V0IGFsbCB2aWRlbyBmaWxlcwogICAgICAgICAgICAgICAgICAgIHJlY29yZGluZ3MgPSBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlttTV1bcFBdNCIpKSArIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW3dXXVtlRV1bYkJdW21NXSIpKQoKICAgICAgICAgICAgICAgICAgICAjIFNvcnQgcmVjb3JkaW5ncyBieSBjcmVhdGlvbiB0aW1lIChvbGRlc3QgZmlyc3QpCiAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5ncy5zb3J0KGtleT1vcy5wYXRoLmdldGN0aW1lKQoKICAgICAgICAgICAgICAgICAgICAjIEFkZCBudW1iZXJpbmcgdG8gdGhlIHJlY29yZGluZ3MKICAgICAgICAgICAgICAgICAgICBudW1iZXJlZF9yZWNvcmRpbmdzID0gW10KICAgICAgICAgICAgICAgICAgICBmb3IgaWR4LCByZWNvcmRpbmcgaW4gZW51bWVyYXRlKHJlY29yZGluZ3MsIHN0YXJ0PTEpOgogICAgICAgICAgICAgICAgICAgICAgICBmaWxlbmFtZSA9IG9zLnBhdGguYmFzZW5hbWUocmVjb3JkaW5nKQogICAgICAgICAgICAgICAgICAgICAgICBudW1iZXJlZF9yZWNvcmRpbmdzLmFwcGVuZCgocmVjb3JkaW5nLCBmIntpZHh9LiB7ZmlsZW5hbWV9IikpCgogICAgICAgICAgICAgICAgICAgIHJldHVybiBudW1iZXJlZF9yZWNvcmRpbmdzCgogICAgICAgICAgICAgICAgcmVjb3JkaW5nc19nYWxsZXJ5ID0gZ3IuR2FsbGVyeSgKICAgICAgICAgICAgICAgICAgICBsYWJlbD0iUmVjb3JkaW5ncyIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWU9bGlzdF9yZWNvcmRpbmdzKGNvbmZpZ1snc2F2ZV9yZWNvcmRpbmdfcGF0aCddKSwKICAgICAgICAgICAgICAgICAgICBjb2x1bW5zPTMsCiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PSJhdXRvIiwKICAgICAgICAgICAgICAgICAgICBvYmplY3RfZml0PSJjb250YWluIgogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIHJlZnJlc2hfYnV0dG9uID0gZ3IuQnV0dG9uKCLwn5SEIFJlZnJlc2ggUmVjb3JkaW5ncyIsIHZhcmlhbnQ9InNlY29uZGFyeSIpCiAgICAgICAgICAgICAgICByZWZyZXNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1saXN0X3JlY29yZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgaW5wdXRzPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgb3V0cHV0cz1yZWNvcmRpbmdzX2dhbGxlcnkKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgICAgIHdpdGggZ3IuVGFiSXRlbSgi8J+TgSBDb25maWd1cmF0aW9uIiwgaWQ9OCk6CiAgICAgICAgICAgICAgICB3aXRoIGdyLkdyb3VwKCk6CiAgICAgICAgICAgICAgICAgICAgY29uZmlnX2ZpbGVfaW5wdXQgPSBnci5GaWxlKAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTG9hZCBDb25maWcgRmlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfdHlwZXM9WyIucGtsIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUKICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgICAgIGxvYWRfY29uZmlnX2J1dHRvbiA9IGdyLkJ1dHRvbigiTG9hZCBFeGlzdGluZyBDb25maWcgRnJvbSBGaWxlIiwgdmFyaWFudD0icHJpbWFyeSIpCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9jb25maWdfYnV0dG9uID0gZ3IuQnV0dG9uKCJTYXZlIEN1cnJlbnQgQ29uZmlnIiwgdmFyaWFudD0icHJpbWFyeSIpCgogICAgICAgICAgICAgICAgICAgIGNvbmZpZ19zdGF0dXMgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iU3RhdHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXM9MiwKICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU9RmFsc2UKICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgbG9hZF9jb25maWdfYnV0dG9uLmNsaWNrKAogICAgICAgICAgICAgICAgICAgIGZuPXVwZGF0ZV91aV9mcm9tX2NvbmZpZywKICAgICAgICAgICAgICAgICAgICBpbnB1dHM9W2NvbmZpZ19maWxlX2lucHV0XSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVsKICAgICAgICAgICAgICAgICAgICAgICAgYWdlbnRfdHlwZSwgbWF4X3N0ZXBzLCBtYXhfYWN0aW9uc19wZXJfc3RlcCwgdXNlX3Zpc2lvbiwgdG9vbF9jYWxsaW5nX21ldGhvZCwKICAgICAgICAgICAgICAgICAgICAgICAgbGxtX3Byb3ZpZGVyLCBsbG1fbW9kZWxfbmFtZSwgbGxtX3RlbXBlcmF0dXJlLCBsbG1fYmFzZV91cmwsIGxsbV9hcGlfa2V5LAogICAgICAgICAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXIsIGtlZXBfYnJvd3Nlcl9vcGVuLCBoZWFkbGVzcywgZGlzYWJsZV9zZWN1cml0eSwgZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93X3csIHdpbmRvd19oLCBzYXZlX3JlY29yZGluZ19wYXRoLCBzYXZlX3RyYWNlX3BhdGgsIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICB0YXNrLCBjb25maWdfc3RhdHVzCiAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIHNhdmVfY29uZmlnX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zYXZlX2N1cnJlbnRfY29uZmlnLAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bCiAgICAgICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGUsIG1heF9zdGVwcywgbWF4X2FjdGlvbnNfcGVyX3N0ZXAsIHVzZV92aXNpb24sIHRvb2xfY2FsbGluZ19tZXRob2QsCiAgICAgICAgICAgICAgICAgICAgICAgIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwKICAgICAgICAgICAgICAgICAgICAgICAgdXNlX293bl9icm93c2VyLCBrZWVwX2Jyb3dzZXJfb3BlbiwgaGVhZGxlc3MsIGRpc2FibGVfc2VjdXJpdHksCiAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZV9yZWNvcmRpbmcsIHdpbmRvd193LCB3aW5kb3dfaCwgc2F2ZV9yZWNvcmRpbmdfcGF0aCwgc2F2ZV90cmFjZV9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwgdGFzaywKICAgICAgICAgICAgICAgICAgICBdLCAgCiAgICAgICAgICAgICAgICAgICAgb3V0cHV0cz1bY29uZmlnX3N0YXR1c10KICAgICAgICAgICAgICAgICkKCgogICAgICAgICMgQXR0YWNoIHRoZSBjYWxsYmFjayB0byB0aGUgTExNIHByb3ZpZGVyIGRyb3Bkb3duCiAgICAgICAgbGxtX3Byb3ZpZGVyLmNoYW5nZSgKICAgICAgICAgICAgbGFtYmRhIHByb3ZpZGVyLCBhcGlfa2V5LCBiYXNlX3VybDogdXBkYXRlX21vZGVsX2Ryb3Bkb3duKHByb3ZpZGVyLCBhcGlfa2V5LCBiYXNlX3VybCksCiAgICAgICAgICAgIGlucHV0cz1bbGxtX3Byb3ZpZGVyLCBsbG1fYXBpX2tleSwgbGxtX2Jhc2VfdXJsXSwKICAgICAgICAgICAgb3V0cHV0cz1sbG1fbW9kZWxfbmFtZQogICAgICAgICkKCiAgICAgICAgIyBBZGQgdGhpcyBhZnRlciBkZWZpbmluZyB0aGUgY29tcG9uZW50cwogICAgICAgIGVuYWJsZV9yZWNvcmRpbmcuY2hhbmdlKAogICAgICAgICAgICBsYW1iZGEgZW5hYmxlZDogZ3IudXBkYXRlKGludGVyYWN0aXZlPWVuYWJsZWQpLAogICAgICAgICAgICBpbnB1dHM9ZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgb3V0cHV0cz1zYXZlX3JlY29yZGluZ19wYXRoCiAgICAgICAgKQoKICAgICAgICB1c2Vfb3duX2Jyb3dzZXIuY2hhbmdlKGZuPWNsb3NlX2dsb2JhbF9icm93c2VyKQogICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuLmNoYW5nZShmbj1jbG9zZV9nbG9iYWxfYnJvd3NlcikKCiAgICAgICAgIyBQTEFDRUhPTERFUl9GT1JfUFJPTVBUUwoKICAgIHJldHVybiBkZW1vCgpkZWYgbWFpbigpOgogICAgcGFyc2VyID0gYXJncGFyc2UuQXJndW1lbnRQYXJzZXIoZGVzY3JpcHRpb249IkdyYWRpbyBVSSBmb3IgQnJvd3NlciBBZ2VudCIpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLWlwIiwgdHlwZT1zdHIsIGRlZmF1bHQ9IjEyNy4wLjAuMSIsIGhlbHA9IklQIGFkZHJlc3MgdG8gYmluZCB0byIpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLXBvcnQiLCB0eXBlPWludCwgZGVmYXVsdD03Nzg4LCBoZWxwPSJQb3J0IHRvIGxpc3RlbiBvbiIpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLXRoZW1lIiwgdHlwZT1zdHIsIGRlZmF1bHQ9Ik9jZWFuIiwgY2hvaWNlcz10aGVtZV9tYXAua2V5cygpLCBoZWxwPSJUaGVtZSB0byB1c2UgZm9yIHRoZSBVSSIpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCItLWRhcmstbW9kZSIsIGFjdGlvbj0ic3RvcmVfdHJ1ZSIsIGhlbHA9IkVuYWJsZSBkYXJrIG1vZGUiKQogICAgYXJncyA9IHBhcnNlci5wYXJzZV9hcmdzKCkKCiAgICBjb25maWdfZGljdCA9IGRlZmF1bHRfY29uZmlnKCkKCiAgICBkZW1vID0gY3JlYXRlX3VpKGNvbmZpZ19kaWN0LCB0aGVtZV9uYW1lPWFyZ3MudGhlbWUpCiAgICBkZW1vLmxhdW5jaChzZXJ2ZXJfbmFtZT1hcmdzLmlwLCBzZXJ2ZXJfcG9ydD1hcmdzLnBvcnQpCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgbWFpbigpCg==").decode("utf-8")
with open(WEB_UI_DIR / "webui.py.template", "w", encoding="utf-8") as f:
f.write(webui_template_content)
logging.info("Decoded and wrote embedded webui.py.template")
# Decode and write embedded initial webui.py file
webui_initial_content = base64.b64decode("aW1wb3J0IHBkYgppbXBvcnQgbG9nZ2luZwoKZnJvbSBkb3RlbnYgaW1wb3J0IGxvYWRfZG90ZW52Cgpsb2FkX2RvdGVudigpCmltcG9ydCBvcwppbXBvcnQgZ2xvYgppbXBvcnQgYXN5bmNpbwppbXBvcnQgYXJncGFyc2UKaW1wb3J0IG9zCgpsb2dnZXIgPSBsb2dnaW5nLmdldExvZ2dlcihfX25hbWVfXykKCmltcG9ydCBncmFkaW8gYXMgZ3IKCmZyb20gYnJvd3Nlcl91c2UuYWdlbnQuc2VydmljZSBpbXBvcnQgQWdlbnQKZnJvbSBwbGF5d3JpZ2h0LmFzeW5jX2FwaSBpbXBvcnQgYXN5bmNfcGxheXdyaWdodApmcm9tIGJyb3dzZXJfdXNlLmJyb3dzZXIuYnJvd3NlciBpbXBvcnQgQnJvd3NlciwgQnJvd3NlckNvbmZpZwpmcm9tIGJyb3dzZXJfdXNlLmJyb3dzZXIuY29udGV4dCBpbXBvcnQgKAogICAgQnJvd3NlckNvbnRleHRDb25maWcsCiAgICBCcm93c2VyQ29udGV4dFdpbmRvd1NpemUsCikKZnJvbSBsYW5nY2hhaW5fb2xsYW1hIGltcG9ydCBDaGF0T2xsYW1hCmZyb20gcGxheXdyaWdodC5hc3luY19hcGkgaW1wb3J0IGFzeW5jX3BsYXl3cmlnaHQKZnJvbSBzcmMudXRpbHMuYWdlbnRfc3RhdGUgaW1wb3J0IEFnZW50U3RhdGUKCmZyb20gc3JjLnV0aWxzIGltcG9ydCB1dGlscwpmcm9tIHNyYy5hZ2VudC5jdXN0b21fYWdlbnQgaW1wb3J0IEN1c3RvbUFnZW50CmZyb20gc3JjLmJyb3dzZXIuY3VzdG9tX2Jyb3dzZXIgaW1wb3J0IEN1c3RvbUJyb3dzZXIKZnJvbSBzcmMuYWdlbnQuY3VzdG9tX3Byb21wdHMgaW1wb3J0IEN1c3RvbVN5c3RlbVByb21wdCwgQ3VzdG9tQWdlbnRNZXNzYWdlUHJvbXB0CmZyb20gc3JjLmJyb3dzZXIuY3VzdG9tX2NvbnRleHQgaW1wb3J0IEJyb3dzZXJDb250ZXh0Q29uZmlnLCBDdXN0b21Ccm93c2VyQ29udGV4dApmcm9tIHNyYy5jb250cm9sbGVyLmN1c3RvbV9jb250cm9sbGVyIGltcG9ydCBDdXN0b21Db250cm9sbGVyCmZyb20gZ3JhZGlvLnRoZW1lcyBpbXBvcnQgQ2l0cnVzLCBEZWZhdWx0LCBHbGFzcywgTW9ub2Nocm9tZSwgT2NlYW4sIE9yaWdpbiwgU29mdCwgQmFzZQpmcm9tIHNyYy51dGlscy5kZWZhdWx0X2NvbmZpZ19zZXR0aW5ncyBpbXBvcnQgZGVmYXVsdF9jb25maWcsIGxvYWRfY29uZmlnX2Zyb21fZmlsZSwgc2F2ZV9jb25maWdfdG9fZmlsZSwgc2F2ZV9jdXJyZW50X2NvbmZpZywgdXBkYXRlX3VpX2Zyb21fY29uZmlnCmZyb20gc3JjLnV0aWxzLnV0aWxzIGltcG9ydCB1cGRhdGVfbW9kZWxfZHJvcGRvd24sIGdldF9sYXRlc3RfZmlsZXMsIGNhcHR1cmVfc2NyZWVuc2hvdAoKCiMgR2xvYmFsIHZhcmlhYmxlcyBmb3IgcGVyc2lzdGVuY2UKX2dsb2JhbF9icm93c2VyID0gTm9uZQpfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCA9IE5vbmUKCiMgQ3JlYXRlIHRoZSBnbG9iYWwgYWdlbnQgc3RhdGUgaW5zdGFuY2UKX2dsb2JhbF9hZ2VudF9zdGF0ZSA9IEFnZW50U3RhdGUoKQoKYXN5bmMgZGVmIHN0b3BfYWdlbnQoKToKICAgICIiIlJlcXVlc3QgdGhlIGFnZW50IHRvIHN0b3AgYW5kIHVwZGF0ZSBVSSB3aXRoIGVuaGFuY2VkIGZlZWRiYWNrIiIiCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQsIF9nbG9iYWxfYnJvd3NlcgoKICAgIHRyeToKICAgICAgICAjIFJlcXVlc3Qgc3RvcAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUucmVxdWVzdF9zdG9wKCkKCiAgICAgICAgIyBVcGRhdGUgVUkgaW1tZWRpYXRlbHkKICAgICAgICBtZXNzYWdlID0gIlN0b3AgcmVxdWVzdGVkIC0gdGhlIGFnZW50IHdpbGwgaGFsdCBhdCB0aGUgbmV4dCBzYWZlIHBvaW50IgogICAgICAgIGxvZ2dlci5pbmZvKGYi8J+bkSB7bWVzc2FnZX0iKQoKICAgICAgICAjIFJldHVybiBVSSB1cGRhdGVzCiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgbWVzc2FnZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBlcnJvcnNfb3V0cHV0CiAgICAgICAgICAgIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcHBpbmcuLi4iLCBpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHN0b3BfYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1GYWxzZSksICAgICAgICAgICAgICAgICAgICAgICMgcnVuX2J1dHRvbgogICAgICAgICkKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBlcnJvcl9tc2cgPSBmIkVycm9yIGR1cmluZyBzdG9wOiB7c3RyKGUpfSIKICAgICAgICBsb2dnZXIuZXJyb3IoZXJyb3JfbXNnKQogICAgICAgIHJldHVybiAoCiAgICAgICAgICAgIGVycm9yX21zZywKICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKQogICAgICAgICkKICAgICAgICAKYXN5bmMgZGVmIHN0b3BfcmVzZWFyY2hfYWdlbnQoKToKICAgICIiIlJlcXVlc3QgdGhlIGFnZW50IHRvIHN0b3AgYW5kIHVwZGF0ZSBVSSB3aXRoIGVuaGFuY2VkIGZlZWRiYWNrIiIiCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQsIF9nbG9iYWxfYnJvd3NlcgoKICAgIHRyeToKICAgICAgICAjIFJlcXVlc3Qgc3RvcAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUucmVxdWVzdF9zdG9wKCkKCiAgICAgICAgIyBVcGRhdGUgVUkgaW1tZWRpYXRlbHkKICAgICAgICBtZXNzYWdlID0gIlN0b3AgcmVxdWVzdGVkIC0gdGhlIGFnZW50IHdpbGwgaGFsdCBhdCB0aGUgbmV4dCBzYWZlIHBvaW50IgogICAgICAgIGxvZ2dlci5pbmZvKGYi8J+bkSB7bWVzc2FnZX0iKQoKICAgICAgICAjIFJldHVybiBVSSB1cGRhdGVzCiAgICAgICAgcmV0dXJuICggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZXJyb3JzX291dHB1dAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3BwaW5nLi4uIiwgaW50ZXJhY3RpdmU9RmFsc2UpLCAgIyBzdG9wX2J1dHRvbgogICAgICAgICAgICBnci51cGRhdGUoaW50ZXJhY3RpdmU9RmFsc2UpLCAgICAgICAgICAgICAgICAgICAgICAjIHJ1bl9idXR0b24KICAgICAgICApCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgZXJyb3JfbXNnID0gZiJFcnJvciBkdXJpbmcgc3RvcDoge3N0cihlKX0iCiAgICAgICAgbG9nZ2VyLmVycm9yKGVycm9yX21zZykKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwKICAgICAgICAgICAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpCiAgICAgICAgKQoKYXN5bmMgZGVmIHJ1bl9icm93c2VyX2FnZW50KAogICAgICAgIGFnZW50X3R5cGUsCiAgICAgICAgbGxtX3Byb3ZpZGVyLAogICAgICAgIGxsbV9tb2RlbF9uYW1lLAogICAgICAgIGxsbV90ZW1wZXJhdHVyZSwKICAgICAgICBsbG1fYmFzZV91cmwsCiAgICAgICAgbGxtX2FwaV9rZXksCiAgICAgICAgdXNlX293bl9icm93c2VyLAogICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgIGhlYWRsZXNzLAogICAgICAgIGRpc2FibGVfc2VjdXJpdHksCiAgICAgICAgd2luZG93X3csCiAgICAgICAgd2luZG93X2gsCiAgICAgICAgc2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgICAgICBzYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgZW5hYmxlX3JlY29yZGluZywKICAgICAgICB0YXNrLAogICAgICAgIGFkZF9pbmZvcywKICAgICAgICBtYXhfc3RlcHMsCiAgICAgICAgdXNlX3Zpc2lvbiwKICAgICAgICBtYXhfYWN0aW9uc19wZXJfc3RlcCwKICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kCik6CiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZQogICAgX2dsb2JhbF9hZ2VudF9zdGF0ZS5jbGVhcl9zdG9wKCkgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdHMKCiAgICB0cnk6CiAgICAgICAgIyBEaXNhYmxlIHJlY29yZGluZyBpZiB0aGUgY2hlY2tib3ggaXMgdW5jaGVja2VkCiAgICAgICAgaWYgbm90IGVuYWJsZV9yZWNvcmRpbmc6CiAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGggPSBOb25lCgogICAgICAgICMgRW5zdXJlIHRoZSByZWNvcmRpbmcgZGlyZWN0b3J5IGV4aXN0cyBpZiByZWNvcmRpbmcgaXMgZW5hYmxlZAogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIG9zLm1ha2VkaXJzKHNhdmVfcmVjb3JkaW5nX3BhdGgsIGV4aXN0X29rPVRydWUpCgogICAgICAgICMgR2V0IHRoZSBsaXN0IG9mIGV4aXN0aW5nIHZpZGVvcyBiZWZvcmUgdGhlIGFnZW50IHJ1bnMKICAgICAgICBleGlzdGluZ192aWRlb3MgPSBzZXQoKQogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIGV4aXN0aW5nX3ZpZGVvcyA9IHNldCgKICAgICAgICAgICAgICAgIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW21NXVtwUF00IikpCiAgICAgICAgICAgICAgICArIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW3dXXVtlRV1bYkJdW21NXSIpKQogICAgICAgICAgICApCgogICAgICAgICMgUnVuIHRoZSBhZ2VudAogICAgICAgIGxsbSA9IHV0aWxzLmdldF9sbG1fbW9kZWwoCiAgICAgICAgICAgIHByb3ZpZGVyPWxsbV9wcm92aWRlciwKICAgICAgICAgICAgbW9kZWxfbmFtZT1sbG1fbW9kZWxfbmFtZSwKICAgICAgICAgICAgdGVtcGVyYXR1cmU9bGxtX3RlbXBlcmF0dXJlLAogICAgICAgICAgICBiYXNlX3VybD1sbG1fYmFzZV91cmwsCiAgICAgICAgICAgIGFwaV9rZXk9bGxtX2FwaV9rZXksCiAgICAgICAgKQogICAgICAgIGlmIGFnZW50X3R5cGUgPT0gIm9yZyI6CiAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwgZXJyb3JzLCBtb2RlbF9hY3Rpb25zLCBtb2RlbF90aG91Z2h0cywgdHJhY2VfZmlsZSwgaGlzdG9yeV9maWxlID0gYXdhaXQgcnVuX29yZ19hZ2VudCgKICAgICAgICAgICAgICAgIGxsbT1sbG0sCiAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXI9dXNlX293bl9icm93c2VyLAogICAgICAgICAgICAgICAga2VlcF9icm93c2VyX29wZW49a2VlcF9icm93c2VyX29wZW4sCiAgICAgICAgICAgICAgICBoZWFkbGVzcz1oZWFkbGVzcywKICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgIHdpbmRvd193PXdpbmRvd193LAogICAgICAgICAgICAgICAgd2luZG93X2g9d2luZG93X2gsCiAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aD1zYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgICAgICAgICAgICAgIHNhdmVfdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgICAgICAgICB0YXNrPXRhc2ssCiAgICAgICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgKQogICAgICAgIGVsaWYgYWdlbnRfdHlwZSA9PSAiY3VzdG9tIjoKICAgICAgICAgICAgZmluYWxfcmVzdWx0LCBlcnJvcnMsIG1vZGVsX2FjdGlvbnMsIG1vZGVsX3Rob3VnaHRzLCB0cmFjZV9maWxlLCBoaXN0b3J5X2ZpbGUgPSBhd2FpdCBydW5fY3VzdG9tX2FnZW50KAogICAgICAgICAgICAgICAgbGxtPWxsbSwKICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAgICAgICAgICBrZWVwX2Jyb3dzZXJfb3Blbj1rZWVwX2Jyb3dzZXJfb3BlbiwKICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICAgICAgd2luZG93X3c9d2luZG93X3csCiAgICAgICAgICAgICAgICB3aW5kb3dfaD13aW5kb3dfaCwKICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICAgICAgICAgIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoPXNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgICAgICAgICAgc2F2ZV90cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCwKICAgICAgICAgICAgICAgIHRhc2s9dGFzaywKICAgICAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoZiJJbnZhbGlkIGFnZW50IHR5cGU6IHthZ2VudF90eXBlfSIpCgogICAgICAgICMgR2V0IHRoZSBsaXN0IG9mIHZpZGVvcyBhZnRlciB0aGUgYWdlbnQgcnVucyAoaWYgcmVjb3JkaW5nIGlzIGVuYWJsZWQpCiAgICAgICAgbGF0ZXN0X3ZpZGVvID0gTm9uZQogICAgICAgIGlmIHNhdmVfcmVjb3JkaW5nX3BhdGg6CiAgICAgICAgICAgIG5ld192aWRlb3MgPSBzZXQoCiAgICAgICAgICAgICAgICBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlttTV1bcFBdNCIpKQogICAgICAgICAgICAgICAgKyBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlt3V11bZUVdW2JCXVttTV0iKSkKICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBuZXdfdmlkZW9zIC0gZXhpc3RpbmdfdmlkZW9zOgogICAgICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvID0gbGlzdChuZXdfdmlkZW9zIC0gZXhpc3RpbmdfdmlkZW9zKVswXSAgIyBHZXQgdGhlIGZpcnN0IG5ldyB2aWRlbwoKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICBmaW5hbF9yZXN1bHQsCiAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgbW9kZWxfYWN0aW9ucywKICAgICAgICAgICAgbW9kZWxfdGhvdWdodHMsCiAgICAgICAgICAgIGxhdGVzdF92aWRlbywKICAgICAgICAgICAgdHJhY2VfZmlsZSwKICAgICAgICAgICAgaGlzdG9yeV9maWxlLAogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwgICMgUmUtZW5hYmxlIHN0b3AgYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKSAgICAjIFJlLWVuYWJsZSBydW4gYnV0dG9uCiAgICAgICAgKQoKICAgIGV4Y2VwdCBnci5FcnJvcjoKICAgICAgICByYWlzZQoKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBpbXBvcnQgdHJhY2ViYWNrCiAgICAgICAgdHJhY2ViYWNrLnByaW50X2V4YygpCiAgICAgICAgZXJyb3JzID0gc3RyKGUpICsgIlxuIiArIHRyYWNlYmFjay5mb3JtYXRfZXhjKCkKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAnJywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmluYWxfcmVzdWx0CiAgICAgICAgICAgIGVycm9ycywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBlcnJvcnMKICAgICAgICAgICAgJycsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1vZGVsX2FjdGlvbnMKICAgICAgICAgICAgJycsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1vZGVsX3Rob3VnaHRzCiAgICAgICAgICAgIE5vbmUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBsYXRlc3RfdmlkZW8KICAgICAgICAgICAgTm9uZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGhpc3RvcnlfZmlsZQogICAgICAgICAgICBOb25lLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdHJhY2VfZmlsZQogICAgICAgICAgICBnci51cGRhdGUodmFsdWU9IlN0b3AiLCBpbnRlcmFjdGl2ZT1UcnVlKSwgICMgUmUtZW5hYmxlIHN0b3AgYnV0dG9uCiAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1UcnVlKSAgICAjIFJlLWVuYWJsZSBydW4gYnV0dG9uCiAgICAgICAgKQoKCmFzeW5jIGRlZiBydW5fb3JnX2FnZW50KAogICAgICAgIGxsbSwKICAgICAgICB1c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAga2VlcF9icm93c2VyX29wZW4sCiAgICAgICAgaGVhZGxlc3MsCiAgICAgICAgZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICB3aW5kb3dfdywKICAgICAgICB3aW5kb3dfaCwKICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoLAogICAgICAgIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgIHNhdmVfdHJhY2VfcGF0aCwKICAgICAgICB0YXNrLAogICAgICAgIG1heF9zdGVwcywKICAgICAgICB1c2VfdmlzaW9uLAogICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2QKKToKICAgIHRyeToKICAgICAgICBnbG9iYWwgX2dsb2JhbF9icm93c2VyLCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwgX2dsb2JhbF9hZ2VudF9zdGF0ZQogICAgICAgIAogICAgICAgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdAogICAgICAgIF9nbG9iYWxfYWdlbnRfc3RhdGUuY2xlYXJfc3RvcCgpCgogICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3MgPSBbZiItLXdpbmRvdy1zaXplPXt3aW5kb3dfd30se3dpbmRvd19ofSJdCiAgICAgICAgaWYgdXNlX293bl9icm93c2VyOgogICAgICAgICAgICBjaHJvbWVfcGF0aCA9IG9zLmdldGVudigiQ0hST01FX1BBVEgiLCBOb25lKQogICAgICAgICAgICBpZiBjaHJvbWVfcGF0aCA9PSAiIjoKICAgICAgICAgICAgICAgIGNocm9tZV9wYXRoID0gTm9uZQogICAgICAgICAgICBjaHJvbWVfdXNlcl9kYXRhID0gb3MuZ2V0ZW52KCJDSFJPTUVfVVNFUl9EQVRBIiwgTm9uZSkKICAgICAgICAgICAgaWYgY2hyb21lX3VzZXJfZGF0YToKICAgICAgICAgICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3MgKz0gW2YiLS11c2VyLWRhdGEtZGlyPXtjaHJvbWVfdXNlcl9kYXRhfSJdCiAgICAgICAgZWxzZToKICAgICAgICAgICAgY2hyb21lX3BhdGggPSBOb25lCiAgICAgICAgICAgIAogICAgICAgIGlmIF9nbG9iYWxfYnJvd3NlciBpcyBOb25lOgogICAgICAgICAgICBfZ2xvYmFsX2Jyb3dzZXIgPSBCcm93c2VyKAogICAgICAgICAgICAgICAgY29uZmlnPUJyb3dzZXJDb25maWcoCiAgICAgICAgICAgICAgICAgICAgaGVhZGxlc3M9aGVhZGxlc3MsCiAgICAgICAgICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICAgICAgICAgIGNocm9tZV9pbnN0YW5jZV9wYXRoPWNocm9tZV9wYXRoLAogICAgICAgICAgICAgICAgICAgIGV4dHJhX2Nocm9taXVtX2FyZ3M9ZXh0cmFfY2hyb21pdW1fYXJncywKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgKQoKICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCBpcyBOb25lOgogICAgICAgICAgICBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCA9IGF3YWl0IF9nbG9iYWxfYnJvd3Nlci5uZXdfY29udGV4dCgKICAgICAgICAgICAgICAgIGNvbmZpZz1Ccm93c2VyQ29udGV4dENvbmZpZygKICAgICAgICAgICAgICAgICAgICB0cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCBpZiBzYXZlX3RyYWNlX3BhdGggZWxzZSBOb25lLAogICAgICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCBpZiBzYXZlX3JlY29yZGluZ19wYXRoIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICBub192aWV3cG9ydD1GYWxzZSwKICAgICAgICAgICAgICAgICAgICBicm93c2VyX3dpbmRvd19zaXplPUJyb3dzZXJDb250ZXh0V2luZG93U2l6ZSgKICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9d2luZG93X3csIGhlaWdodD13aW5kb3dfaAogICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgYWdlbnQgPSBBZ2VudCgKICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICBsbG09bGxtLAogICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgIGJyb3dzZXI9X2dsb2JhbF9icm93c2VyLAogICAgICAgICAgICBicm93c2VyX2NvbnRleHQ9X2dsb2JhbF9icm93c2VyX2NvbnRleHQsCiAgICAgICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwPW1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICApCiAgICAgICAgaGlzdG9yeSA9IGF3YWl0IGFnZW50LnJ1bihtYXhfc3RlcHM9bWF4X3N0ZXBzKQoKICAgICAgICBoaXN0b3J5X2ZpbGUgPSBvcy5wYXRoLmpvaW4oc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsIGYie2FnZW50LmFnZW50X2lkfS5qc29uIikKICAgICAgICBhZ2VudC5zYXZlX2hpc3RvcnkoaGlzdG9yeV9maWxlKQoKICAgICAgICBmaW5hbF9yZXN1bHQgPSBoaXN0b3J5LmZpbmFsX3Jlc3VsdCgpCiAgICAgICAgZXJyb3JzID0gaGlzdG9yeS5lcnJvcnMoKQogICAgICAgIG1vZGVsX2FjdGlvbnMgPSBoaXN0b3J5Lm1vZGVsX2FjdGlvbnMoKQogICAgICAgIG1vZGVsX3Rob3VnaHRzID0gaGlzdG9yeS5tb2RlbF90aG91Z2h0cygpCgogICAgICAgIHRyYWNlX2ZpbGUgPSBnZXRfbGF0ZXN0X2ZpbGVzKHNhdmVfdHJhY2VfcGF0aCkKCiAgICAgICAgcmV0dXJuIGZpbmFsX3Jlc3VsdCwgZXJyb3JzLCBtb2RlbF9hY3Rpb25zLCBtb2RlbF90aG91Z2h0cywgdHJhY2VfZmlsZS5nZXQoJy56aXAnKSwgaGlzdG9yeV9maWxlCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgaW1wb3J0IHRyYWNlYmFjawogICAgICAgIHRyYWNlYmFjay5wcmludF9leGMoKQogICAgICAgIGVycm9ycyA9IHN0cihlKSArICJcbiIgKyB0cmFjZWJhY2suZm9ybWF0X2V4YygpCiAgICAgICAgcmV0dXJuICcnLCBlcnJvcnMsICcnLCAnJywgTm9uZSwgTm9uZQogICAgZmluYWxseToKICAgICAgICAjIEhhbmRsZSBjbGVhbnVwIGJhc2VkIG9uIHBlcnNpc3RlbmNlIGNvbmZpZ3VyYXRpb24KICAgICAgICBpZiBub3Qga2VlcF9icm93c2VyX29wZW46CiAgICAgICAgICAgIGlmIF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0OgogICAgICAgICAgICAgICAgYXdhaXQgX2dsb2JhbF9icm93c2VyX2NvbnRleHQuY2xvc2UoKQogICAgICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBOb25lCgogICAgICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXI6CiAgICAgICAgICAgICAgICBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXIuY2xvc2UoKQogICAgICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyID0gTm9uZQoKYXN5bmMgZGVmIHJ1bl9jdXN0b21fYWdlbnQoCiAgICAgICAgbGxtLAogICAgICAgIHVzZV9vd25fYnJvd3NlciwKICAgICAgICBrZWVwX2Jyb3dzZXJfb3BlbiwKICAgICAgICBoZWFkbGVzcywKICAgICAgICBkaXNhYmxlX3NlY3VyaXR5LAogICAgICAgIHdpbmRvd193LAogICAgICAgIHdpbmRvd19oLAogICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgc2F2ZV90cmFjZV9wYXRoLAogICAgICAgIHRhc2ssCiAgICAgICAgYWRkX2luZm9zLAogICAgICAgIG1heF9zdGVwcywKICAgICAgICB1c2VfdmlzaW9uLAogICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2QKKToKICAgIHRyeToKICAgICAgICBnbG9iYWwgX2dsb2JhbF9icm93c2VyLCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwgX2dsb2JhbF9hZ2VudF9zdGF0ZQoKICAgICAgICAjIENsZWFyIGFueSBwcmV2aW91cyBzdG9wIHJlcXVlc3QKICAgICAgICBfZ2xvYmFsX2FnZW50X3N0YXRlLmNsZWFyX3N0b3AoKQoKICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzID0gW2YiLS13aW5kb3ctc2l6ZT17d2luZG93X3d9LHt3aW5kb3dfaH0iXQogICAgICAgIGlmIHVzZV9vd25fYnJvd3NlcjoKICAgICAgICAgICAgY2hyb21lX3BhdGggPSBvcy5nZXRlbnYoIkNIUk9NRV9QQVRIIiwgTm9uZSkKICAgICAgICAgICAgaWYgY2hyb21lX3BhdGggPT0gIiI6CiAgICAgICAgICAgICAgICBjaHJvbWVfcGF0aCA9IE5vbmUKICAgICAgICAgICAgY2hyb21lX3VzZXJfZGF0YSA9IG9zLmdldGVudigiQ0hST01FX1VTRVJfREFUQSIsIE5vbmUpCiAgICAgICAgICAgIGlmIGNocm9tZV91c2VyX2RhdGE6CiAgICAgICAgICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzICs9IFtmIi0tdXNlci1kYXRhLWRpcj17Y2hyb21lX3VzZXJfZGF0YX0iXQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGNocm9tZV9wYXRoID0gTm9uZQoKICAgICAgICBjb250cm9sbGVyID0gQ3VzdG9tQ29udHJvbGxlcigpCgogICAgICAgICMgSW5pdGlhbGl6ZSBnbG9iYWwgYnJvd3NlciBpZiBuZWVkZWQKICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXIgaXMgTm9uZToKICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyID0gQ3VzdG9tQnJvd3NlcigKICAgICAgICAgICAgICAgIGNvbmZpZz1Ccm93c2VyQ29uZmlnKAogICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgICAgICBjaHJvbWVfaW5zdGFuY2VfcGF0aD1jaHJvbWVfcGF0aCwKICAgICAgICAgICAgICAgICAgICBleHRyYV9jaHJvbWl1bV9hcmdzPWV4dHJhX2Nocm9taXVtX2FyZ3MsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKCiAgICAgICAgaWYgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgaXMgTm9uZToKICAgICAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXIubmV3X2NvbnRleHQoCiAgICAgICAgICAgICAgICBjb25maWc9QnJvd3NlckNvbnRleHRDb25maWcoCiAgICAgICAgICAgICAgICAgICAgdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGggaWYgc2F2ZV90cmFjZV9wYXRoIGVsc2UgTm9uZSwKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGggaWYgc2F2ZV9yZWNvcmRpbmdfcGF0aCBlbHNlIE5vbmUsCiAgICAgICAgICAgICAgICAgICAgbm9fdmlld3BvcnQ9RmFsc2UsCiAgICAgICAgICAgICAgICAgICAgYnJvd3Nlcl93aW5kb3dfc2l6ZT1Ccm93c2VyQ29udGV4dFdpbmRvd1NpemUoCiAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPXdpbmRvd193LCBoZWlnaHQ9d2luZG93X2gKICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICApCiAgICAgICAgICAgIAogICAgICAgICMgQ3JlYXRlIGFuZCBydW4gYWdlbnQKICAgICAgICBhZ2VudCA9IEN1c3RvbUFnZW50KAogICAgICAgICAgICB0YXNrPXRhc2ssCiAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgIHVzZV92aXNpb249dXNlX3Zpc2lvbiwKICAgICAgICAgICAgbGxtPWxsbSwKICAgICAgICAgICAgYnJvd3Nlcj1fZ2xvYmFsX2Jyb3dzZXIsCiAgICAgICAgICAgIGJyb3dzZXJfY29udGV4dD1fZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCwKICAgICAgICAgICAgY29udHJvbGxlcj1jb250cm9sbGVyLAogICAgICAgICAgICBzeXN0ZW1fcHJvbXB0X2NsYXNzPUN1c3RvbVN5c3RlbVByb21wdCwKICAgICAgICAgICAgYWdlbnRfcHJvbXB0X2NsYXNzPUN1c3RvbUFnZW50TWVzc2FnZVByb21wdCwKICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgIGFnZW50X3N0YXRlPV9nbG9iYWxfYWdlbnRfc3RhdGUsCiAgICAgICAgICAgIHRvb2xfY2FsbGluZ19tZXRob2Q9dG9vbF9jYWxsaW5nX21ldGhvZAogICAgICAgICkKICAgICAgICBoaXN0b3J5ID0gYXdhaXQgYWdlbnQucnVuKG1heF9zdGVwcz1tYXhfc3RlcHMpCgogICAgICAgIGhpc3RvcnlfZmlsZSA9IG9zLnBhdGguam9pbihzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwgZiJ7YWdlbnQuYWdlbnRfaWR9Lmpzb24iKQogICAgICAgIGFnZW50LnNhdmVfaGlzdG9yeShoaXN0b3J5X2ZpbGUpCgogICAgICAgIGZpbmFsX3Jlc3VsdCA9IGhpc3RvcnkuZmluYWxfcmVzdWx0KCkKICAgICAgICBlcnJvcnMgPSBoaXN0b3J5LmVycm9ycygpCiAgICAgICAgbW9kZWxfYWN0aW9ucyA9IGhpc3RvcnkubW9kZWxfYWN0aW9ucygpCiAgICAgICAgbW9kZWxfdGhvdWdodHMgPSBoaXN0b3J5Lm1vZGVsX3Rob3VnaHRzKCkKCiAgICAgICAgdHJhY2VfZmlsZSA9IGdldF9sYXRlc3RfZmlsZXMoc2F2ZV90cmFjZV9wYXRoKSAgICAgICAgCgogICAgICAgIHJldHVybiBmaW5hbF9yZXN1bHQsIGVycm9ycywgbW9kZWxfYWN0aW9ucywgbW9kZWxfdGhvdWdodHMsIHRyYWNlX2ZpbGUuZ2V0KCcuemlwJyksIGhpc3RvcnlfZmlsZQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgIGltcG9ydCB0cmFjZWJhY2sKICAgICAgICB0cmFjZWJhY2sucHJpbnRfZXhjKCkKICAgICAgICBlcnJvcnMgPSBzdHIoZSkgKyAiXG4iICsgdHJhY2ViYWNrLmZvcm1hdF9leGMoKQogICAgICAgIHJldHVybiAnJywgZXJyb3JzLCAnJywgJycsIE5vbmUsIE5vbmUKICAgIGZpbmFsbHk6CiAgICAgICAgIyBIYW5kbGUgY2xlYW51cCBiYXNlZCBvbiBwZXJzaXN0ZW5jZSBjb25maWd1cmF0aW9uCiAgICAgICAgaWYgbm90IGtlZXBfYnJvd3Nlcl9vcGVuOgogICAgICAgICAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dDoKICAgICAgICAgICAgICAgIGF3YWl0IF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0LmNsb3NlKCkKICAgICAgICAgICAgICAgIF9nbG9iYWxfYnJvd3Nlcl9jb250ZXh0ID0gTm9uZQoKICAgICAgICAgICAgaWYgX2dsb2JhbF9icm93c2VyOgogICAgICAgICAgICAgICAgYXdhaXQgX2dsb2JhbF9icm93c2VyLmNsb3NlKCkKICAgICAgICAgICAgICAgIF9nbG9iYWxfYnJvd3NlciA9IE5vbmUKCmFzeW5jIGRlZiBydW5fd2l0aF9zdHJlYW0oCiAgICBhZ2VudF90eXBlLAogICAgbGxtX3Byb3ZpZGVyLAogICAgbGxtX21vZGVsX25hbWUsCiAgICBsbG1fdGVtcGVyYXR1cmUsCiAgICBsbG1fYmFzZV91cmwsCiAgICBsbG1fYXBpX2tleSwKICAgIHVzZV9vd25fYnJvd3NlciwKICAgIGtlZXBfYnJvd3Nlcl9vcGVuLAogICAgaGVhZGxlc3MsCiAgICBkaXNhYmxlX3NlY3VyaXR5LAogICAgd2luZG93X3csCiAgICB3aW5kb3dfaCwKICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwKICAgIHNhdmVfdHJhY2VfcGF0aCwKICAgIGVuYWJsZV9yZWNvcmRpbmcsCiAgICB0YXNrLAogICAgYWRkX2luZm9zLAogICAgbWF4X3N0ZXBzLAogICAgdXNlX3Zpc2lvbiwKICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgdG9vbF9jYWxsaW5nX21ldGhvZAopOgogICAgZ2xvYmFsIF9nbG9iYWxfYWdlbnRfc3RhdGUKICAgIHN0cmVhbV92dyA9IDgwCiAgICBzdHJlYW1fdmggPSBpbnQoODAgKiB3aW5kb3dfaCAvLyB3aW5kb3dfdykKICAgIGlmIG5vdCBoZWFkbGVzczoKICAgICAgICByZXN1bHQgPSBhd2FpdCBydW5fYnJvd3Nlcl9hZ2VudCgKICAgICAgICAgICAgYWdlbnRfdHlwZT1hZ2VudF90eXBlLAogICAgICAgICAgICBsbG1fcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICBsbG1fbW9kZWxfbmFtZT1sbG1fbW9kZWxfbmFtZSwKICAgICAgICAgICAgbGxtX3RlbXBlcmF0dXJlPWxsbV90ZW1wZXJhdHVyZSwKICAgICAgICAgICAgbGxtX2Jhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgbGxtX2FwaV9rZXk9bGxtX2FwaV9rZXksCiAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIsCiAgICAgICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuPWtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgICAgICBoZWFkbGVzcz1oZWFkbGVzcywKICAgICAgICAgICAgZGlzYWJsZV9zZWN1cml0eT1kaXNhYmxlX3NlY3VyaXR5LAogICAgICAgICAgICB3aW5kb3dfdz13aW5kb3dfdywKICAgICAgICAgICAgd2luZG93X2g9d2luZG93X2gsCiAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGg9c2F2ZV9yZWNvcmRpbmdfcGF0aCwKICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGg9c2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgICAgIHNhdmVfdHJhY2VfcGF0aD1zYXZlX3RyYWNlX3BhdGgsCiAgICAgICAgICAgIGVuYWJsZV9yZWNvcmRpbmc9ZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICBhZGRfaW5mb3M9YWRkX2luZm9zLAogICAgICAgICAgICBtYXhfc3RlcHM9bWF4X3N0ZXBzLAogICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgIG1heF9hY3Rpb25zX3Blcl9zdGVwPW1heF9hY3Rpb25zX3Blcl9zdGVwLAogICAgICAgICAgICB0b29sX2NhbGxpbmdfbWV0aG9kPXRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICApCiAgICAgICAgIyBBZGQgSFRNTCBjb250ZW50IGF0IHRoZSBzdGFydCBvZiB0aGUgcmVzdWx0IGFycmF5CiAgICAgICAgaHRtbF9jb250ZW50ID0gZiI8aDEgc3R5bGU9J3dpZHRoOntzdHJlYW1fdnd9dnc7IGhlaWdodDp7c3RyZWFtX3ZofXZoJz5Vc2luZyBicm93c2VyLi4uPC9oMT4iCiAgICAgICAgeWllbGQgW2h0bWxfY29udGVudF0gKyBsaXN0KHJlc3VsdCkKICAgIGVsc2U6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBfZ2xvYmFsX2FnZW50X3N0YXRlLmNsZWFyX3N0b3AoKQogICAgICAgICAgICAjIFJ1biB0aGUgYnJvd3NlciBhZ2VudCBpbiB0aGUgYmFja2dyb3VuZAogICAgICAgICAgICBhZ2VudF90YXNrID0gYXN5bmNpby5jcmVhdGVfdGFzaygKICAgICAgICAgICAgICAgIHJ1bl9icm93c2VyX2FnZW50KAogICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGU9YWdlbnRfdHlwZSwKICAgICAgICAgICAgICAgICAgICBsbG1fcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICAgICAgICAgIGxsbV9tb2RlbF9uYW1lPWxsbV9tb2RlbF9uYW1lLAogICAgICAgICAgICAgICAgICAgIGxsbV90ZW1wZXJhdHVyZT1sbG1fdGVtcGVyYXR1cmUsCiAgICAgICAgICAgICAgICAgICAgbGxtX2Jhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgICAgICAgICBsbG1fYXBpX2tleT1sbG1fYXBpX2tleSwKICAgICAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXI9dXNlX293bl9icm93c2VyLAogICAgICAgICAgICAgICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuPWtlZXBfYnJvd3Nlcl9vcGVuLAogICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHk9ZGlzYWJsZV9zZWN1cml0eSwKICAgICAgICAgICAgICAgICAgICB3aW5kb3dfdz13aW5kb3dfdywKICAgICAgICAgICAgICAgICAgICB3aW5kb3dfaD13aW5kb3dfaCwKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGg9c2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgc2F2ZV90cmFjZV9wYXRoPXNhdmVfdHJhY2VfcGF0aCwKICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nPWVuYWJsZV9yZWNvcmRpbmcsCiAgICAgICAgICAgICAgICAgICAgdGFzaz10YXNrLAogICAgICAgICAgICAgICAgICAgIGFkZF9pbmZvcz1hZGRfaW5mb3MsCiAgICAgICAgICAgICAgICAgICAgbWF4X3N0ZXBzPW1heF9zdGVwcywKICAgICAgICAgICAgICAgICAgICB1c2VfdmlzaW9uPXVzZV92aXNpb24sCiAgICAgICAgICAgICAgICAgICAgbWF4X2FjdGlvbnNfcGVyX3N0ZXA9bWF4X2FjdGlvbnNfcGVyX3N0ZXAsCiAgICAgICAgICAgICAgICAgICAgdG9vbF9jYWxsaW5nX21ldGhvZD10b29sX2NhbGxpbmdfbWV0aG9kCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKCiAgICAgICAgICAgICMgSW5pdGlhbGl6ZSB2YWx1ZXMgZm9yIHN0cmVhbWluZwogICAgICAgICAgICBodG1sX2NvbnRlbnQgPSBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPlVzaW5nIGJyb3dzZXIuLi48L2gxPiIKICAgICAgICAgICAgZmluYWxfcmVzdWx0ID0gZXJyb3JzID0gbW9kZWxfYWN0aW9ucyA9IG1vZGVsX3Rob3VnaHRzID0gIiIKICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvcyA9IHRyYWNlID0gaGlzdG9yeV9maWxlID0gTm9uZQoKCiAgICAgICAgICAgICMgUGVyaW9kaWNhbGx5IHVwZGF0ZSB0aGUgc3RyZWFtIHdoaWxlIHRoZSBhZ2VudCB0YXNrIGlzIHJ1bm5pbmcKICAgICAgICAgICAgd2hpbGUgbm90IGFnZW50X3Rhc2suZG9uZSgpOgogICAgICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgICAgIGVuY29kZWRfc2NyZWVuc2hvdCA9IGF3YWl0IGNhcHR1cmVfc2NyZWVuc2hvdChfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dCkKICAgICAgICAgICAgICAgICAgICBpZiBlbmNvZGVkX3NjcmVlbnNob3QgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCA9IGYnPGltZyBzcmM9ImRhdGE6aW1hZ2UvanBlZztiYXNlNjQse2VuY29kZWRfc2NyZWVuc2hvdH0iIHN0eWxlPSJ3aWR0aDp7c3RyZWFtX3Z3fXZ3OyBoZWlnaHQ6e3N0cmVhbV92aH12aCA7IGJvcmRlcjoxcHggc29saWQgI2NjYzsiPicKICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICBodG1sX2NvbnRlbnQgPSBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPldhaXRpbmcgZm9yIGJyb3dzZXIgc2Vzc2lvbi4uLjwvaDE+IgogICAgICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCA9IGYiPGgxIHN0eWxlPSd3aWR0aDp7c3RyZWFtX3Z3fXZ3OyBoZWlnaHQ6e3N0cmVhbV92aH12aCc+V2FpdGluZyBmb3IgYnJvd3NlciBzZXNzaW9uLi4uPC9oMT4iCgogICAgICAgICAgICAgICAgaWYgX2dsb2JhbF9hZ2VudF9zdGF0ZSBhbmQgX2dsb2JhbF9hZ2VudF9zdGF0ZS5pc19zdG9wX3JlcXVlc3RlZCgpOgogICAgICAgICAgICAgICAgICAgIHlpZWxkIFsKICAgICAgICAgICAgICAgICAgICAgICAgaHRtbF9jb250ZW50LAogICAgICAgICAgICAgICAgICAgICAgICBmaW5hbF9yZXN1bHQsCiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfdGhvdWdodHMsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhdGVzdF92aWRlb3MsCiAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlLAogICAgICAgICAgICAgICAgICAgICAgICBoaXN0b3J5X2ZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcHBpbmcuLi4iLCBpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHN0b3BfYnV0dG9uCiAgICAgICAgICAgICAgICAgICAgICAgIGdyLnVwZGF0ZShpbnRlcmFjdGl2ZT1GYWxzZSksICAjIHJ1bl9idXR0b24KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgeWllbGQgWwogICAgICAgICAgICAgICAgICAgICAgICBodG1sX2NvbnRlbnQsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JzLAogICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9hY3Rpb25zLAogICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cywKICAgICAgICAgICAgICAgICAgICAgICAgbGF0ZXN0X3ZpZGVvcywKICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UsCiAgICAgICAgICAgICAgICAgICAgICAgIGhpc3RvcnlfZmlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksICAjIFJlLWVuYWJsZSBzdG9wIGJ1dHRvbgogICAgICAgICAgICAgICAgICAgICAgICBnci51cGRhdGUoaW50ZXJhY3RpdmU9VHJ1ZSkgICMgUmUtZW5hYmxlIHJ1biBidXR0b24KICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICBhd2FpdCBhc3luY2lvLnNsZWVwKDAuMDUpCgogICAgICAgICAgICAjIE9uY2UgdGhlIGFnZW50IHRhc2sgY29tcGxldGVzLCBnZXQgdGhlIHJlc3VsdHMKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgcmVzdWx0ID0gYXdhaXQgYWdlbnRfdGFzawogICAgICAgICAgICAgICAgZmluYWxfcmVzdWx0LCBlcnJvcnMsIG1vZGVsX2FjdGlvbnMsIG1vZGVsX3Rob3VnaHRzLCBsYXRlc3RfdmlkZW9zLCB0cmFjZSwgaGlzdG9yeV9maWxlLCBzdG9wX2J1dHRvbiwgcnVuX2J1dHRvbiA9IHJlc3VsdAogICAgICAgICAgICBleGNlcHQgZ3IuRXJyb3I6CiAgICAgICAgICAgICAgICBmaW5hbF9yZXN1bHQgPSAiIgogICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9ucyA9ICIiCiAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cyA9ICIiCiAgICAgICAgICAgICAgICBsYXRlc3RfdmlkZW9zID0gdHJhY2UgPSBoaXN0b3J5X2ZpbGUgPSBOb25lCgogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgICAgICBlcnJvcnMgPSBmIkFnZW50IGVycm9yOiB7c3RyKGUpfSIKCiAgICAgICAgICAgIHlpZWxkIFsKICAgICAgICAgICAgICAgIGh0bWxfY29udGVudCwKICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdCwKICAgICAgICAgICAgICAgIGVycm9ycywKICAgICAgICAgICAgICAgIG1vZGVsX2FjdGlvbnMsCiAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0cywKICAgICAgICAgICAgICAgIGxhdGVzdF92aWRlb3MsCiAgICAgICAgICAgICAgICB0cmFjZSwKICAgICAgICAgICAgICAgIGhpc3RvcnlfZmlsZSwKICAgICAgICAgICAgICAgIHN0b3BfYnV0dG9uLAogICAgICAgICAgICAgICAgcnVuX2J1dHRvbgogICAgICAgICAgICBdCgogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgaW1wb3J0IHRyYWNlYmFjawogICAgICAgICAgICB5aWVsZCBbCiAgICAgICAgICAgICAgICBmIjxoMSBzdHlsZT0nd2lkdGg6e3N0cmVhbV92d312dzsgaGVpZ2h0OntzdHJlYW1fdmh9dmgnPldhaXRpbmcgZm9yIGJyb3dzZXIgc2Vzc2lvbi4uLjwvaDE+IiwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgZiJFcnJvcjoge3N0cihlKX1cbnt0cmFjZWJhY2suZm9ybWF0X2V4YygpfSIsCiAgICAgICAgICAgICAgICAiIiwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgTm9uZSwKICAgICAgICAgICAgICAgIE5vbmUsCiAgICAgICAgICAgICAgICBOb25lLAogICAgICAgICAgICAgICAgZ3IudXBkYXRlKHZhbHVlPSJTdG9wIiwgaW50ZXJhY3RpdmU9VHJ1ZSksICAjIFJlLWVuYWJsZSBzdG9wIGJ1dHRvbgogICAgICAgICAgICAgICAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpICAgICMgUmUtZW5hYmxlIHJ1biBidXR0b24KICAgICAgICAgICAgXQoKIyBEZWZpbmUgdGhlIHRoZW1lIG1hcCBnbG9iYWxseQp0aGVtZV9tYXAgPSB7CiAgICAiRGVmYXVsdCI6IERlZmF1bHQoKSwKICAgICJTb2Z0IjogU29mdCgpLAogICAgIk1vbm9jaHJvbWUiOiBNb25vY2hyb21lKCksCiAgICAiR2xhc3MiOiBHbGFzcygpLAogICAgIk9yaWdpbiI6IE9yaWdpbigpLAogICAgIkNpdHJ1cyI6IENpdHJ1cygpLAogICAgIk9jZWFuIjogT2NlYW4oKSwKICAgICJCYXNlIjogQmFzZSgpCn0KCmFzeW5jIGRlZiBjbG9zZV9nbG9iYWxfYnJvd3NlcigpOgogICAgZ2xvYmFsIF9nbG9iYWxfYnJvd3NlciwgX2dsb2JhbF9icm93c2VyX2NvbnRleHQKCiAgICBpZiBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dDoKICAgICAgICBhd2FpdCBfZ2xvYmFsX2Jyb3dzZXJfY29udGV4dC5jbG9zZSgpCiAgICAgICAgX2dsb2JhbF9icm93c2VyX2NvbnRleHQgPSBOb25lCgogICAgaWYgX2dsb2JhbF9icm93c2VyOgogICAgICAgIGF3YWl0IF9nbG9iYWxfYnJvd3Nlci5jbG9zZSgpCiAgICAgICAgX2dsb2JhbF9icm93c2VyID0gTm9uZQogICAgICAgIAphc3luYyBkZWYgcnVuX2RlZXBfc2VhcmNoKHJlc2VhcmNoX3Rhc2ssIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0LCBtYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwgdXNlX3Zpc2lvbiwgdXNlX293bl9icm93c2VyLCBoZWFkbGVzcyk6CiAgICBmcm9tIHNyYy51dGlscy5kZWVwX3Jlc2VhcmNoIGltcG9ydCBkZWVwX3Jlc2VhcmNoCiAgICBnbG9iYWwgX2dsb2JhbF9hZ2VudF9zdGF0ZQoKICAgICMgQ2xlYXIgYW55IHByZXZpb3VzIHN0b3AgcmVxdWVzdAogICAgX2dsb2JhbF9hZ2VudF9zdGF0ZS5jbGVhcl9zdG9wKCkKICAgIAogICAgbGxtID0gdXRpbHMuZ2V0X2xsbV9tb2RlbCgKICAgICAgICAgICAgcHJvdmlkZXI9bGxtX3Byb3ZpZGVyLAogICAgICAgICAgICBtb2RlbF9uYW1lPWxsbV9tb2RlbF9uYW1lLAogICAgICAgICAgICB0ZW1wZXJhdHVyZT1sbG1fdGVtcGVyYXR1cmUsCiAgICAgICAgICAgIGJhc2VfdXJsPWxsbV9iYXNlX3VybCwKICAgICAgICAgICAgYXBpX2tleT1sbG1fYXBpX2tleSwKICAgICAgICApCiAgICBtYXJrZG93bl9jb250ZW50LCBmaWxlX3BhdGggPSBhd2FpdCBkZWVwX3Jlc2VhcmNoKHJlc2VhcmNoX3Rhc2ssIGxsbSwgX2dsb2JhbF9hZ2VudF9zdGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhfc2VhcmNoX2l0ZXJhdGlvbnM9bWF4X3NlYXJjaF9pdGVyYXRpb25faW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3F1ZXJ5X251bT1tYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX3Zpc2lvbj11c2VfdmlzaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRsZXNzPWhlYWRsZXNzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3Nlcj11c2Vfb3duX2Jyb3dzZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAKICAgIHJldHVybiBtYXJrZG93bl9jb250ZW50LCBmaWxlX3BhdGgsIGdyLnVwZGF0ZSh2YWx1ZT0iU3RvcCIsIGludGVyYWN0aXZlPVRydWUpLCAgZ3IudXBkYXRlKGludGVyYWN0aXZlPVRydWUpIAogICAgCgpkZWYgY3JlYXRlX3VpKGNvbmZpZywgdGhlbWVfbmFtZT0iT2NlYW4iKToKICAgIGNzcyA9ICIiIgogICAgLmdyYWRpby1jb250YWluZXIgewogICAgICAgIG1heC13aWR0aDogMTIwMHB4ICFpbXBvcnRhbnQ7CiAgICAgICAgbWFyZ2luOiBhdXRvICFpbXBvcnRhbnQ7CiAgICAgICAgcGFkZGluZy10b3A6IDIwcHggIWltcG9ydGFudDsKICAgIH0KICAgIC5oZWFkZXItdGV4dCB7CiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgICAgIG1hcmdpbi1ib3R0b206IDMwcHg7CiAgICB9CiAgICAudGhlbWUtc2VjdGlvbiB7CiAgICAgICAgbWFyZ2luLWJvdHRvbTogMjBweDsKICAgICAgICBwYWRkaW5nOiAxNXB4OwogICAgICAgIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgICB9CiAgICAiIiIKCiAgICB3aXRoIGdyLkJsb2NrcygKICAgICAgICAgICAgdGl0bGU9IkJyb3dzZXIgVXNlIFdlYlVJIiwgdGhlbWU9dGhlbWVfbWFwW3RoZW1lX25hbWVdLCBjc3M9Y3NzCiAgICApIGFzIGRlbW86CiAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgZ3IuTWFya2Rvd24oCiAgICAgICAgICAgICAgICAiIiIKICAgICAgICAgICAgICAgICMg8J+MkCBCcm93c2VyIFVzZSBXZWJVSQogICAgICAgICAgICAgICAgIyMjIENvbnRyb2wgeW91ciBicm93c2VyIHdpdGggQUkgYXNzaXN0YW5jZQogICAgICAgICAgICAgICAgIiIiLAogICAgICAgICAgICAgICAgZWxlbV9jbGFzc2VzPVsiaGVhZGVyLXRleHQiXSwKICAgICAgICAgICAgKQoKICAgICAgICB3aXRoIGdyLlRhYnMoKSBhcyB0YWJzOgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIuKame+4jyBBZ2VudCBTZXR0aW5ncyIsIGlkPTEpOgogICAgICAgICAgICAgICAgd2l0aCBnci5Hcm91cCgpOgogICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGUgPSBnci5SYWRpbygKICAgICAgICAgICAgICAgICAgICAgICAgWyJvcmciLCAiY3VzdG9tIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBZ2VudCBUeXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydhZ2VudF90eXBlJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IlNlbGVjdCB0aGUgdHlwZSBvZiBhZ2VudCB0byB1c2UiLAogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLkNvbHVtbigpOgogICAgICAgICAgICAgICAgICAgICAgICBtYXhfc3RlcHMgPSBnci5TbGlkZXIoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhpbXVtPTIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snbWF4X3N0ZXBzJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTWF4IFJ1biBTdGVwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJNYXhpbXVtIG51bWJlciBvZiBzdGVwcyB0aGUgYWdlbnQgd2lsbCB0YWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBtYXhfYWN0aW9uc19wZXJfc3RlcCA9IGdyLlNsaWRlcigKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW09MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGltdW09MjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ21heF9hY3Rpb25zX3Blcl9zdGVwJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwPTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTWF4IEFjdGlvbnMgcGVyIFN0ZXAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iTWF4aW11bSBudW1iZXIgb2YgYWN0aW9ucyB0aGUgYWdlbnQgd2lsbCB0YWtlIHBlciBzdGVwIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuQ29sdW1uKCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHVzZV92aXNpb24gPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJVc2UgVmlzaW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1sndXNlX3Zpc2lvbiddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iRW5hYmxlIHZpc3VhbCBwcm9jZXNzaW5nIGNhcGFiaWxpdGllcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgdG9vbF9jYWxsaW5nX21ldGhvZCA9IGdyLkRyb3Bkb3duKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlRvb2wgQ2FsbGluZyBNZXRob2QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd0b29sX2NhbGxpbmdfbWV0aG9kJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZT1UcnVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dfY3VzdG9tX3ZhbHVlPVRydWUsICAjIEFsbG93IHVzZXJzIHRvIGlucHV0IGN1c3RvbSBtb2RlbCBuYW1lcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hvaWNlcz1bImF1dG8iLCAianNvbl9zY2hlbWEiLCAiZnVuY3Rpb25fY2FsbGluZyJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iVG9vbCBDYWxscyBGdW50aW9uIE5hbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZT1GYWxzZQogICAgICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCflKcgTExNIENvbmZpZ3VyYXRpb24iLCBpZD0yKToKICAgICAgICAgICAgICAgIHdpdGggZ3IuR3JvdXAoKToKICAgICAgICAgICAgICAgICAgICBsbG1fcHJvdmlkZXIgPSBnci5Ecm9wZG93bigKICAgICAgICAgICAgICAgICAgICAgICAgY2hvaWNlcz1bcHJvdmlkZXIgZm9yIHByb3ZpZGVyLG1vZGVsIGluIHV0aWxzLm1vZGVsX25hbWVzLml0ZW1zKCldLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTExNIFByb3ZpZGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydsbG1fcHJvdmlkZXInXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU2VsZWN0IHlvdXIgcHJlZmVycmVkIGxhbmd1YWdlIG1vZGVsIHByb3ZpZGVyIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBsbG1fbW9kZWxfbmFtZSA9IGdyLkRyb3Bkb3duKAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTW9kZWwgTmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGNob2ljZXM9dXRpbHMubW9kZWxfbmFtZXNbJ29wZW5haSddLAogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2xsbV9tb2RlbF9uYW1lJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93X2N1c3RvbV92YWx1ZT1UcnVlLCAgIyBBbGxvdyB1c2VycyB0byBpbnB1dCBjdXN0b20gbW9kZWwgbmFtZXMKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU2VsZWN0IGEgbW9kZWwgZnJvbSB0aGUgZHJvcGRvd24gb3IgdHlwZSBhIGN1c3RvbSBtb2RlbCBuYW1lIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBsbG1fdGVtcGVyYXR1cmUgPSBnci5TbGlkZXIoCiAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW09MC4wLAogICAgICAgICAgICAgICAgICAgICAgICBtYXhpbXVtPTIuMCwKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydsbG1fdGVtcGVyYXR1cmUnXSwKICAgICAgICAgICAgICAgICAgICAgICAgc3RlcD0wLjEsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJUZW1wZXJhdHVyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IkNvbnRyb2xzIHJhbmRvbW5lc3MgaW4gbW9kZWwgb3V0cHV0cyIKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICAgICAgbGxtX2Jhc2VfdXJsID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJCYXNlIFVSTCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2xsbV9iYXNlX3VybCddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQVBJIGVuZHBvaW50IFVSTCAoaWYgcmVxdWlyZWQpIgogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIGxsbV9hcGlfa2V5ID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBUEkgS2V5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9InBhc3N3b3JkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snbGxtX2FwaV9rZXknXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IllvdXIgQVBJIGtleSAobGVhdmUgYmxhbmsgdG8gdXNlIC5lbnYpIgogICAgICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCfjJAgQnJvd3NlciBTZXR0aW5ncyIsIGlkPTMpOgogICAgICAgICAgICAgICAgd2l0aCBnci5Hcm91cCgpOgogICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuUm93KCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHVzZV9vd25fYnJvd3NlciA9IGdyLkNoZWNrYm94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlVzZSBPd24gQnJvd3NlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ3VzZV9vd25fYnJvd3NlciddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iVXNlIHlvdXIgZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAga2VlcF9icm93c2VyX29wZW4gPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJLZWVwIEJyb3dzZXIgT3BlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2tlZXBfYnJvd3Nlcl9vcGVuJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJLZWVwIEJyb3dzZXIgT3BlbiBiZXR3ZWVuIFRhc2tzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBoZWFkbGVzcyA9IGdyLkNoZWNrYm94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IkhlYWRsZXNzIE1vZGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWydoZWFkbGVzcyddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iUnVuIGJyb3dzZXIgd2l0aG91dCBHVUkiLAogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVfc2VjdXJpdHkgPSBnci5DaGVja2JveCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJEaXNhYmxlIFNlY3VyaXR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snZGlzYWJsZV9zZWN1cml0eSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iRGlzYWJsZSBicm93c2VyIHNlY3VyaXR5IGZlYXR1cmVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nID0gZ3IuQ2hlY2tib3goCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iRW5hYmxlIFJlY29yZGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ2VuYWJsZV9yZWNvcmRpbmcnXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IkVuYWJsZSBzYXZpbmcgYnJvd3NlciByZWNvcmRpbmdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3dfdyA9IGdyLk51bWJlcigKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJXaW5kb3cgV2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd3aW5kb3dfdyddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQnJvd3NlciB3aW5kb3cgd2lkdGgiLAogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvd19oID0gZ3IuTnVtYmVyKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IldpbmRvdyBIZWlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9Y29uZmlnWyd3aW5kb3dfaCddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iQnJvd3NlciB3aW5kb3cgaGVpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICBzYXZlX3JlY29yZGluZ19wYXRoID0gZ3IuVGV4dGJveCgKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlJlY29yZGluZyBQYXRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9ImUuZy4gLi90bXAvcmVjb3JkX3ZpZGVvcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV9yZWNvcmRpbmdfcGF0aCddLAogICAgICAgICAgICAgICAgICAgICAgICBpbmZvPSJQYXRoIHRvIHNhdmUgYnJvd3NlciByZWNvcmRpbmdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU9VHJ1ZSwgICMgQWxsb3cgZWRpdGluZyBvbmx5IGlmIHJlY29yZGluZyBpcyBlbmFibGVkCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICBzYXZlX3RyYWNlX3BhdGggPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iVHJhY2UgUGF0aCIsCiAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPSJlLmcuIC4vdG1wL3RyYWNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV90cmFjZV9wYXRoJ10sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm89IlBhdGggdG8gc2F2ZSBBZ2VudCB0cmFjZXMiLAogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZT1UcnVlLAogICAgICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGggPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iQWdlbnQgSGlzdG9yeSBTYXZlIFBhdGgiLAogICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj0iZS5nLiwgLi90bXAvYWdlbnRfaGlzdG9yeSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPWNvbmZpZ1snc2F2ZV9hZ2VudF9oaXN0b3J5X3BhdGgnXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mbz0iU3BlY2lmeSB0aGUgZGlyZWN0b3J5IHdoZXJlIGFnZW50IGhpc3Rvcnkgc2hvdWxkIGJlIHNhdmVkLiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUsCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgd2l0aCBnci5UYWJJdGVtKCLwn6SWIFJ1biBBZ2VudCIsIGlkPTQpOgogICAgICAgICAgICAgICAgdGFzayA9IGdyLlRleHRib3goCiAgICAgICAgICAgICAgICAgICAgbGFiZWw9IlRhc2sgRGVzY3JpcHRpb24iLAogICAgICAgICAgICAgICAgICAgIGxpbmVzPTQsCiAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9IkVudGVyIHlvdXIgdGFzayBoZXJlLi4uIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZT1jb25maWdbJ3Rhc2snXSwKICAgICAgICAgICAgICAgICAgICBpbmZvPSJEZXNjcmliZSB3aGF0IHlvdSB3YW50IHRoZSBhZ2VudCB0byBkbyIsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBhZGRfaW5mb3MgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgIGxhYmVsPSJBZGRpdGlvbmFsIEluZm9ybWF0aW9uIiwKICAgICAgICAgICAgICAgICAgICBsaW5lcz0zLAogICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPSJBZGQgYW55IGhlbHBmdWwgY29udGV4dCBvciBpbnN0cnVjdGlvbnMuLi4iLAogICAgICAgICAgICAgICAgICAgIGluZm89Ik9wdGlvbmFsIGhpbnRzIHRvIGhlbHAgdGhlIExMTSBjb21wbGV0ZSB0aGUgdGFzayIsCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICBydW5fYnV0dG9uID0gZ3IuQnV0dG9uKCLilrbvuI8gUnVuIEFnZW50IiwgdmFyaWFudD0icHJpbWFyeSIsIHNjYWxlPTIpCiAgICAgICAgICAgICAgICAgICAgc3RvcF9idXR0b24gPSBnci5CdXR0b24oIuKPue+4jyBTdG9wIiwgdmFyaWFudD0ic3RvcCIsIHNjYWxlPTEpCiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgIGJyb3dzZXJfdmlldyA9IGdyLkhUTUwoCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPSI8aDEgc3R5bGU9J3dpZHRoOjgwdnc7IGhlaWdodDo1MHZoJz5XYWl0aW5nIGZvciBicm93c2VyIHNlc3Npb24uLi48L2gxPiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJMaXZlIEJyb3dzZXIgVmlldyIsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIAogICAgICAgICAgICB3aXRoIGdyLlRhYkl0ZW0oIvCfp5AgRGVlcCBSZXNlYXJjaCIsIGlkPTUpOgogICAgICAgICAgICAgICAgcmVzZWFyY2hfdGFza19pbnB1dCA9IGdyLlRleHRib3gobGFiZWw9IlJlc2VhcmNoIFRhc2siLCBsaW5lcz01LCB2YWx1ZT0iQ29tcG9zZSBhIHJlcG9ydCBvbiB0aGUgdXNlIG9mIFJlaW5mb3JjZW1lbnQgTGVhcm5pbmcgZm9yIHRyYWluaW5nIExhcmdlIExhbmd1YWdlIE1vZGVscywgZW5jb21wYXNzaW5nIGl0cyBvcmlnaW5zLCBjdXJyZW50IGFkdmFuY2VtZW50cywgYW5kIGZ1dHVyZSBwcm9zcGVjdHMsIHN1YnN0YW50aWF0ZWQgd2l0aCBleGFtcGxlcyBvZiByZWxldmFudCBtb2RlbHMgYW5kIHRlY2huaXF1ZXMuIFRoZSByZXBvcnQgc2hvdWxkIHJlZmxlY3Qgb3JpZ2luYWwgaW5zaWdodHMgYW5kIGFuYWx5c2lzLCBtb3ZpbmcgYmV5b25kIG1lcmUgc3VtbWFyaXphdGlvbiBvZiBleGlzdGluZyBsaXRlcmF0dXJlLiIpCiAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0ID0gZ3IuTnVtYmVyKGxhYmVsPSJNYXggU2VhcmNoIEl0ZXJhdGlvbiIsIHZhbHVlPTMsIHByZWNpc2lvbj0wKSAjIHByZWNpc2lvbj0wIOehruS/neaYr+aVtOaVsAogICAgICAgICAgICAgICAgICAgIG1heF9xdWVyeV9wZXJfaXRlcl9pbnB1dCA9IGdyLk51bWJlcihsYWJlbD0iTWF4IFF1ZXJ5IHBlciBJdGVyYXRpb24iLCB2YWx1ZT0xLCBwcmVjaXNpb249MCkgIyBwcmVjaXNpb249MCDnoa7kv53mmK/mlbTmlbAKICAgICAgICAgICAgICAgIHdpdGggZ3IuUm93KCk6CiAgICAgICAgICAgICAgICAgICAgcmVzZWFyY2hfYnV0dG9uID0gZ3IuQnV0dG9uKCLilrbvuI8gUnVuIERlZXAgUmVzZWFyY2giLCB2YXJpYW50PSJwcmltYXJ5Iiwgc2NhbGU9MikKICAgICAgICAgICAgICAgICAgICBzdG9wX3Jlc2VhcmNoX2J1dHRvbiA9IGdyLkJ1dHRvbigi4o+577iPIFN0b3AiLCB2YXJpYW50PSJzdG9wIiwgc2NhbGU9MSkKICAgICAgICAgICAgICAgIG1hcmtkb3duX291dHB1dF9kaXNwbGF5ID0gZ3IuTWFya2Rvd24obGFiZWw9IlJlc2VhcmNoIFJlcG9ydCIpCiAgICAgICAgICAgICAgICBtYXJrZG93bl9kb3dubG9hZCA9IGdyLkZpbGUobGFiZWw9IkRvd25sb2FkIFJlc2VhcmNoIFJlcG9ydCIpCgoKICAgICAgICAgICAgd2l0aCBnci5UYWJJdGVtKCLwn5OKIFJlc3VsdHMiLCBpZD02KToKICAgICAgICAgICAgICAgIHdpdGggZ3IuR3JvdXAoKToKCiAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5nX2Rpc3BsYXkgPSBnci5WaWRlbyhsYWJlbD0iTGF0ZXN0IFJlY29yZGluZyIpCgogICAgICAgICAgICAgICAgICAgIGdyLk1hcmtkb3duKCIjIyMgUmVzdWx0cyIpCiAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Sb3coKToKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Db2x1bW4oKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbmFsX3Jlc3VsdF9vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJGaW5hbCBSZXN1bHQiLCBsaW5lcz0zLCBzaG93X2xhYmVsPVRydWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCBnci5Db2x1bW4oKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yc19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJFcnJvcnMiLCBsaW5lcz0zLCBzaG93X2xhYmVsPVRydWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLlJvdygpOgogICAgICAgICAgICAgICAgICAgICAgICB3aXRoIGdyLkNvbHVtbigpOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9uc19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJNb2RlbCBBY3Rpb25zIiwgbGluZXM9Mywgc2hvd19sYWJlbD1UcnVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgIHdpdGggZ3IuQ29sdW1uKCk6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF90aG91Z2h0c19vdXRwdXQgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSJNb2RlbCBUaG91Z2h0cyIsIGxpbmVzPTMsIHNob3dfbGFiZWw9VHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgICAgICB0cmFjZV9maWxlID0gZ3IuRmlsZShsYWJlbD0iVHJhY2UgRmlsZSIpCgogICAgICAgICAgICAgICAgICAgIGFnZW50X2hpc3RvcnlfZmlsZSA9IGdyLkZpbGUobGFiZWw9IkFnZW50IEhpc3RvcnkiKQoKICAgICAgICAgICAgICAgICMgQmluZCB0aGUgc3RvcCBidXR0b24gY2xpY2sgZXZlbnQgYWZ0ZXIgZXJyb3JzX291dHB1dCBpcyBkZWZpbmVkCiAgICAgICAgICAgICAgICBzdG9wX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zdG9wX2FnZW50LAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVtlcnJvcnNfb3V0cHV0LCBzdG9wX2J1dHRvbiwgcnVuX2J1dHRvbl0sCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgIyBSdW4gYnV0dG9uIGNsaWNrIGhhbmRsZXIKICAgICAgICAgICAgICAgIHJ1bl9idXR0b24uY2xpY2soCiAgICAgICAgICAgICAgICAgICAgZm49cnVuX3dpdGhfc3RyZWFtLAogICAgICAgICAgICAgICAgICAgICAgICBpbnB1dHM9WwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlbnRfdHlwZSwgbGxtX3Byb3ZpZGVyLCBsbG1fbW9kZWxfbmFtZSwgbGxtX3RlbXBlcmF0dXJlLCBsbG1fYmFzZV91cmwsIGxsbV9hcGlfa2V5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX293bl9icm93c2VyLCBrZWVwX2Jyb3dzZXJfb3BlbiwgaGVhZGxlc3MsIGRpc2FibGVfc2VjdXJpdHksIHdpbmRvd193LCB3aW5kb3dfaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhdmVfcmVjb3JkaW5nX3BhdGgsIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLCBzYXZlX3RyYWNlX3BhdGgsICAjIEluY2x1ZGUgdGhlIG5ldyBwYXRoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVfcmVjb3JkaW5nLCB0YXNrLCBhZGRfaW5mb3MsIG1heF9zdGVwcywgdXNlX3Zpc2lvbiwgbWF4X2FjdGlvbnNfcGVyX3N0ZXAsIHRvb2xfY2FsbGluZ19tZXRob2QKICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVsKICAgICAgICAgICAgICAgICAgICAgICAgYnJvd3Nlcl92aWV3LCAgICAgICAgICAgIyBCcm93c2VyIHZpZXcKICAgICAgICAgICAgICAgICAgICAgICAgZmluYWxfcmVzdWx0X291dHB1dCwgICAgIyBGaW5hbCByZXN1bHQKICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JzX291dHB1dCwgICAgICAgICAgIyBFcnJvcnMKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYWN0aW9uc19vdXRwdXQsICAgIyBNb2RlbCBhY3Rpb25zCiAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3Rob3VnaHRzX291dHB1dCwgICMgTW9kZWwgdGhvdWdodHMKICAgICAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5nX2Rpc3BsYXksICAgICAgIyBMYXRlc3QgcmVjb3JkaW5nCiAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlX2ZpbGUsICAgICAgICAgICAgICMgVHJhY2UgZmlsZQogICAgICAgICAgICAgICAgICAgICAgICBhZ2VudF9oaXN0b3J5X2ZpbGUsICAgICAjIEFnZW50IGhpc3RvcnkgZmlsZQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wX2J1dHRvbiwgICAgICAgICAgICAjIFN0b3AgYnV0dG9uCiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bl9idXR0b24gICAgICAgICAgICAgICMgUnVuIGJ1dHRvbgogICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICMgUnVuIERlZXAgUmVzZWFyY2gKICAgICAgICAgICAgICAgIHJlc2VhcmNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICAgICAgZm49cnVuX2RlZXBfc2VhcmNoLAogICAgICAgICAgICAgICAgICAgICAgICBpbnB1dHM9W3Jlc2VhcmNoX3Rhc2tfaW5wdXQsIG1heF9zZWFyY2hfaXRlcmF0aW9uX2lucHV0LCBtYXhfcXVlcnlfcGVyX2l0ZXJfaW5wdXQsIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwgdXNlX3Zpc2lvbiwgdXNlX293bl9icm93c2VyLCBoZWFkbGVzc10sCiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHM9W21hcmtkb3duX291dHB1dF9kaXNwbGF5LCBtYXJrZG93bl9kb3dubG9hZCwgc3RvcF9yZXNlYXJjaF9idXR0b24sIHJlc2VhcmNoX2J1dHRvbl0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICMgQmluZCB0aGUgc3RvcCBidXR0b24gY2xpY2sgZXZlbnQgYWZ0ZXIgZXJyb3JzX291dHB1dCBpcyBkZWZpbmVkCiAgICAgICAgICAgICAgICBzdG9wX3Jlc2VhcmNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zdG9wX3Jlc2VhcmNoX2FnZW50LAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bXSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVtzdG9wX3Jlc2VhcmNoX2J1dHRvbiwgcmVzZWFyY2hfYnV0dG9uXSwKICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgIHdpdGggZ3IuVGFiSXRlbSgi8J+OpSBSZWNvcmRpbmdzIiwgaWQ9Nyk6CiAgICAgICAgICAgICAgICBkZWYgbGlzdF9yZWNvcmRpbmdzKHNhdmVfcmVjb3JkaW5nX3BhdGgpOgogICAgICAgICAgICAgICAgICAgIGlmIG5vdCBvcy5wYXRoLmV4aXN0cyhzYXZlX3JlY29yZGluZ19wYXRoKToKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdCgogICAgICAgICAgICAgICAgICAgICMgR2V0IGFsbCB2aWRlbyBmaWxlcwogICAgICAgICAgICAgICAgICAgIHJlY29yZGluZ3MgPSBnbG9iLmdsb2Iob3MucGF0aC5qb2luKHNhdmVfcmVjb3JkaW5nX3BhdGgsICIqLlttTV1bcFBdNCIpKSArIGdsb2IuZ2xvYihvcy5wYXRoLmpvaW4oc2F2ZV9yZWNvcmRpbmdfcGF0aCwgIiouW3dXXVtlRV1bYkJdW21NXSIpKQoKICAgICAgICAgICAgICAgICAgICAjIFNvcnQgcmVjb3JkaW5ncyBieSBjcmVhdGlvbiB0aW1lIChvbGRlc3QgZmlyc3QpCiAgICAgICAgICAgICAgICAgICAgcmVjb3JkaW5ncy5zb3J0KGtleT1vcy5wYXRoLmdldGN0aW1lKQoKICAgICAgICAgICAgICAgICAgICAjIEFkZCBudW1iZXJpbmcgdG8gdGhlIHJlY29yZGluZ3MKICAgICAgICAgICAgICAgICAgICBudW1iZXJlZF9yZWNvcmRpbmdzID0gW10KICAgICAgICAgICAgICAgICAgICBmb3IgaWR4LCByZWNvcmRpbmcgaW4gZW51bWVyYXRlKHJlY29yZGluZ3MsIHN0YXJ0PTEpOgogICAgICAgICAgICAgICAgICAgICAgICBmaWxlbmFtZSA9IG9zLnBhdGguYmFzZW5hbWUocmVjb3JkaW5nKQogICAgICAgICAgICAgICAgICAgICAgICBudW1iZXJlZF9yZWNvcmRpbmdzLmFwcGVuZCgocmVjb3JkaW5nLCBmIntpZHh9LiB7ZmlsZW5hbWV9IikpCgogICAgICAgICAgICAgICAgICAgIHJldHVybiBudW1iZXJlZF9yZWNvcmRpbmdzCgogICAgICAgICAgICAgICAgcmVjb3JkaW5nc19nYWxsZXJ5ID0gZ3IuR2FsbGVyeSgKICAgICAgICAgICAgICAgICAgICBsYWJlbD0iUmVjb3JkaW5ncyIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWU9bGlzdF9yZWNvcmRpbmdzKGNvbmZpZ1snc2F2ZV9yZWNvcmRpbmdfcGF0aCddKSwKICAgICAgICAgICAgICAgICAgICBjb2x1bW5zPTMsCiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PSJhdXRvIiwKICAgICAgICAgICAgICAgICAgICBvYmplY3RfZml0PSJjb250YWluIgogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIHJlZnJlc2hfYnV0dG9uID0gZ3IuQnV0dG9uKCLwn5SEIFJlZnJlc2ggUmVjb3JkaW5ncyIsIHZhcmlhbnQ9InNlY29uZGFyeSIpCiAgICAgICAgICAgICAgICByZWZyZXNoX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1saXN0X3JlY29yZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgaW5wdXRzPXNhdmVfcmVjb3JkaW5nX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgb3V0cHV0cz1yZWNvcmRpbmdzX2dhbGxlcnkKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgICAgIHdpdGggZ3IuVGFiSXRlbSgi8J+TgSBDb25maWd1cmF0aW9uIiwgaWQ9OCk6CiAgICAgICAgICAgICAgICB3aXRoIGdyLkdyb3VwKCk6CiAgICAgICAgICAgICAgICAgICAgY29uZmlnX2ZpbGVfaW5wdXQgPSBnci5GaWxlKAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iTG9hZCBDb25maWcgRmlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfdHlwZXM9WyIucGtsIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0aXZlPVRydWUKICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgICAgIGxvYWRfY29uZmlnX2J1dHRvbiA9IGdyLkJ1dHRvbigiTG9hZCBFeGlzdGluZyBDb25maWcgRnJvbSBGaWxlIiwgdmFyaWFudD0icHJpbWFyeSIpCiAgICAgICAgICAgICAgICAgICAgc2F2ZV9jb25maWdfYnV0dG9uID0gZ3IuQnV0dG9uKCJTYXZlIEN1cnJlbnQgQ29uZmlnIiwgdmFyaWFudD0icHJpbWFyeSIpCgogICAgICAgICAgICAgICAgICAgIGNvbmZpZ19zdGF0dXMgPSBnci5UZXh0Ym94KAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0iU3RhdHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXM9MiwKICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU9RmFsc2UKICAgICAgICAgICAgICAgICAgICApCgogICAgICAgICAgICAgICAgbG9hZF9jb25maWdfYnV0dG9uLmNsaWNrKAogICAgICAgICAgICAgICAgICAgIGZuPXVwZGF0ZV91aV9mcm9tX2NvbmZpZywKICAgICAgICAgICAgICAgICAgICBpbnB1dHM9W2NvbmZpZ19maWxlX2lucHV0XSwKICAgICAgICAgICAgICAgICAgICBvdXRwdXRzPVsKICAgICAgICAgICAgICAgICAgICAgICAgYWdlbnRfdHlwZSwgbWF4X3N0ZXBzLCBtYXhfYWN0aW9uc19wZXJfc3RlcCwgdXNlX3Zpc2lvbiwgdG9vbF9jYWxsaW5nX21ldGhvZCwKICAgICAgICAgICAgICAgICAgICAgICAgbGxtX3Byb3ZpZGVyLCBsbG1fbW9kZWxfbmFtZSwgbGxtX3RlbXBlcmF0dXJlLCBsbG1fYmFzZV91cmwsIGxsbV9hcGlfa2V5LAogICAgICAgICAgICAgICAgICAgICAgICB1c2Vfb3duX2Jyb3dzZXIsIGtlZXBfYnJvd3Nlcl9vcGVuLCBoZWFkbGVzcywgZGlzYWJsZV9zZWN1cml0eSwgZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93X3csIHdpbmRvd19oLCBzYXZlX3JlY29yZGluZ19wYXRoLCBzYXZlX3RyYWNlX3BhdGgsIHNhdmVfYWdlbnRfaGlzdG9yeV9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICB0YXNrLCBjb25maWdfc3RhdHVzCiAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIHNhdmVfY29uZmlnX2J1dHRvbi5jbGljaygKICAgICAgICAgICAgICAgICAgICBmbj1zYXZlX2N1cnJlbnRfY29uZmlnLAogICAgICAgICAgICAgICAgICAgIGlucHV0cz1bCiAgICAgICAgICAgICAgICAgICAgICAgIGFnZW50X3R5cGUsIG1heF9zdGVwcywgbWF4X2FjdGlvbnNfcGVyX3N0ZXAsIHVzZV92aXNpb24sIHRvb2xfY2FsbGluZ19tZXRob2QsCiAgICAgICAgICAgICAgICAgICAgICAgIGxsbV9wcm92aWRlciwgbGxtX21vZGVsX25hbWUsIGxsbV90ZW1wZXJhdHVyZSwgbGxtX2Jhc2VfdXJsLCBsbG1fYXBpX2tleSwKICAgICAgICAgICAgICAgICAgICAgICAgdXNlX293bl9icm93c2VyLCBrZWVwX2Jyb3dzZXJfb3BlbiwgaGVhZGxlc3MsIGRpc2FibGVfc2VjdXJpdHksCiAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZV9yZWNvcmRpbmcsIHdpbmRvd193LCB3aW5kb3dfaCwgc2F2ZV9yZWNvcmRpbmdfcGF0aCwgc2F2ZV90cmFjZV9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICBzYXZlX2FnZW50X2hpc3RvcnlfcGF0aCwgdGFzaywKICAgICAgICAgICAgICAgICAgICBdLCAgCiAgICAgICAgICAgICAgICAgICAgb3V0cHV0cz1bY29uZmlnX3N0YXR1c10KICAgICAgICAgICAgICAgICkKCgogICAgICAgICMgQXR0YWNoIHRoZSBjYWxsYmFjayB0byB0aGUgTExNIHByb3ZpZGVyIGRyb3Bkb3duCiAgICAgICAgbGxtX3Byb3ZpZGVyLmNoYW5nZSgKICAgICAgICAgICAgbGFtYmRhIHByb3ZpZGVyLCBhcGlfa2V5LCBiYXNlX3VybDogdXBkYXRlX21vZGVsX2Ryb3Bkb3duKHByb3ZpZGVyLCBhcGlfa2V5LCBiYXNlX3VybCksCiAgICAgICAgICAgIGlucHV0cz1bbGxtX3Byb3ZpZGVyLCBsbG1fYXBpX2tleSwgbGxtX2Jhc2VfdXJsXSwKICAgICAgICAgICAgb3V0cHV0cz1sbG1fbW9kZWxfbmFtZQogICAgICAgICkKCiAgICAgICAgIyBBZGQgdGhpcyBhZnRlciBkZWZpbmluZyB0aGUgY29tcG9uZW50cwogICAgICAgIGVuYWJsZV9yZWNvcmRpbmcuY2hhbmdlKAogICAgICAgICAgICBsYW1iZGEgZW5hYmxlZDogZ3IudXBkYXRlKGludGVyYWN0aXZlPWVuYWJsZWQpLAogICAgICAgICAgICBpbnB1dHM9ZW5hYmxlX3JlY29yZGluZywKICAgICAgICAgICAgb3V0cHV0cz1zYXZlX3JlY29yZGluZ19wYXRoCiAgICAgICAgKQoKICAgICAgICB1c2Vfb3duX2Jyb3dzZXIuY2hhbmdlKGZuPWNsb3NlX2dsb2JhbF9icm93c2VyKQogICAgICAgIGtlZXBfYnJvd3Nlcl9vcGVuLmNoYW5nZShmbj1jbG9zZV9nbG9iYWxfYnJvd3NlcikKCiAgICByZXR1cm4gZGVtbwoKZGVmIG1haW4oKToKICAgIHBhcnNlciA9IGFyZ3BhcnNlLkFyZ3VtZW50UGFyc2VyKGRlc2NyaXB0aW9uPSJHcmFkaW8gVUkgZm9yIEJyb3dzZXIgQWdlbnQiKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1pcCIsIHR5cGU9c3RyLCBkZWZhdWx0PSIxMjcuMC4wLjEiLCBoZWxwPSJJUCBhZGRyZXNzIHRvIGJpbmQgdG8iKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1wb3J0IiwgdHlwZT1pbnQsIGRlZmF1bHQ9Nzc4OCwgaGVscD0iUG9ydCB0byBsaXN0ZW4gb24iKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS10aGVtZSIsIHR5cGU9c3RyLCBkZWZhdWx0PSJPY2VhbiIsIGNob2ljZXM9dGhlbWVfbWFwLmtleXMoKSwgaGVscD0iVGhlbWUgdG8gdXNlIGZvciB0aGUgVUkiKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgiLS1kYXJrLW1vZGUiLCBhY3Rpb249InN0b3JlX3RydWUiLCBoZWxwPSJFbmFibGUgZGFyayBtb2RlIikKICAgIGFyZ3MgPSBwYXJzZXIucGFyc2VfYXJncygpCgogICAgY29uZmlnX2RpY3QgPSBkZWZhdWx0X2NvbmZpZygpCgogICAgZGVtbyA9IGNyZWF0ZV91aShjb25maWdfZGljdCwgdGhlbWVfbmFtZT1hcmdzLnRoZW1lKQogICAgZGVtby5sYXVuY2goc2VydmVyX25hbWU9YXJncy5pcCwgc2VydmVyX3BvcnQ9YXJncy5wb3J0KQoKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIG1haW4oKQo=").decode("utf-8")
with open(WEB_UI_DIR / "webui.py", "w", encoding="utf-8") as f: # Write initial webui.py to webui.py
f.write(webui_initial_content)
logging.info("Decoded and wrote embedded initial webui.py to webui.py")
create_webui_template() # Create template immediately after cloning
modify_webui_py() # Call modify_webui_py() when repo exists as well.
except subprocess.CalledProcessError as e:
logging.error(f"Error cloning web-ui repository: Git command failed with error code {e.returncode}")
if hasattr(e, 'stderr') and e.stderr:
logging.error(f"Command output (stderr):\n{e.stderr.decode()}")
except Exception as e:
logging.error(f"Error in clone_web_ui: {e}")
async def set_default_llm_provider(page):
"""Sets the default LLM provider using Playwright."""
try:
# Wait for the dropdown to be visible (adjust timeout as needed)
await page.locator('input[aria-label="LLM Provider"]').wait_for(state="visible", timeout=10000) # Use the aria-label
# Click the dropdown to open the options
await page.click('input[aria-label="LLM Provider"]')
# Wait for the options to be visible (adjust timeout as needed)
await page.locator('ul[role="listbox"]').wait_for(state="visible", timeout=10000)
# Click the "google" option (replace "google" with the exact text)
await page.click('li[role="option"]:has-text("google")') # Use :has-text() selector
logging.info("Set default LLM provider to Google using Playwright.")
except Exception as e:
logging.exception(f"Error in clone_web_ui(): {e}") # Log the full exception with traceback
def create_webui_template(): # Renamed from modify_webui_py's template creation part
webui_py_path = WEB_UI_DIR / "webui.py"
webui_template_path = WEB_UI_DIR / "webui.py.template"
original_webui_path = WEB_UI_DIR / "webui.py.original"
if not webui_template_path.exists():
if original_webui_path.exists():
with open(original_webui_path, "r", encoding="utf-8") as original_file:
template_content = original_file.read()
# Replace placeholders for title, header, and API key link
template_content = template_content.replace('gr.Blocks(title="Browser Use WebUI"', 'gr.Blocks(title="PLACEHOLDER_TITLE"')
template_content = template_content.replace('gr.Markdown("""\n# 🌐 Browser Use WebUI', 'gr.Markdown("""\n# 🌐 PLACEHOLDER_HEADER_TITLE')
template_content = template_content.replace('### [Get Gemini FREE API Key](https://aistudio.google.com/apikey)', 'PLACEHOLDER_API_KEY_LINK')
# Add sound placeholder (improved regex for robustness)
template_content = re.sub(
r"(final_result, errors, model_actions, model_thoughts, latest_videos, trace, history_file, stop_button, run_button = result)",
r"\1\n # PLACEHOLDER_TASK_COMPLETED_SOUND",
template_content
)
with open(webui_template_path, "w", encoding="utf-8") as f:
f.write(template_content)
logging.info(f"Created webui.py.template at: {webui_template_path}")
else:
logging.error(f"Original webui.py file not found at {original_webui_path}. Cannot create template.")
# return
def modify_webui_py():
webui_py_path = WEB_UI_DIR / "webui.py"
webui_template_path = WEB_UI_DIR / "webui.py.template"
try:
with open(webui_template_path, "r", encoding="utf-8") as f:
template_content = f.read()
# Replace placeholders
modified_content = template_content.replace("PLACEHOLDER_TITLE", "AutoPyBOT with Browser Use WebUI")
modified_content = modified_content.replace("PLACEHOLDER_HEADER_TITLE", "AutoPyBOT with Browser Use WebUI")
modified_content = modified_content.replace("PLACEHOLDER_API_KEY_LINK", "### [Get Gemini FREE API Key](https://aistudio.google.com/apikey)")
with open(webui_py_path, "w", encoding="utf-8") as f:
f.write(modified_content)
logging.info("Modified webui.py from template successfully.")
# Insert sound code (using the robust split and insert method)
with open(webui_py_path, "r", encoding="utf-8") as f:
webui_content = f.read()
sound_code = """
import pyttsx3
engine = pyttsx3.init()
engine.say("Task Completed")
engine.runAndWait()
"""
parts = webui_content.split("# PLACEHOLDER_TASK_COMPLETED_SOUND")
if len(parts) == 2:
webui_content = parts[0] + "# PLACEHOLDER_TASK_COMPLETED_SOUND\n" + sound_code + parts[1]
with open(webui_py_path, "w", encoding="utf-8") as f:
f.write(webui_content)
logging.info("Inserted sound playing code into webui.py")
else:
logging.warning("Placeholder not found in webui.py")
except FileNotFoundError:
logging.error(f"webui.py.template not found at: {webui_template_path}")
except Exception as e:
logging.error(f"Error modifying webui.py from template: {e}")
def create_virtualenv():
"""Create a virtual environment at VENV_DIR, or check if existing one is valid."""
try:
if VENV_DIR.exists():
python_exe_test = VENV_DIR / "Scripts" / "python.exe"
if python_exe_test.exists():
try:
subprocess.check_call([str(python_exe_test), "-c", "import sys; print(sys.executable)"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
logging.info("Virtual environment already exists and is functional.")
return # Exit function if venv is OK
except (subprocess.CalledProcessError, FileNotFoundError):
logging.warning("Existing virtual environment is not functional. Recreating...")
shutil.rmtree(VENV_DIR) # Remove broken venv
# Fall through to create a new one
logging.info("Creating virtual environment...")
subprocess.check_call([sys.executable, "-m", "venv", str(VENV_DIR)])
logging.info("Virtual environment created successfully.")
except subprocess.CalledProcessError as e:
logging.error(f"Error creating virtual environment: Command failed with error code {e.returncode}")
if hasattr(e, 'stderr') and e.stderr:
logging.error(f"Command output (stderr):\n{e.stderr.decode()}")
if hasattr(e, 'stdout') and e.stdout:
logging.error(f"Command output (stdout):\n{e.stdout.decode()}")
except Exception as e:
logging.error(f"Error in create_virtualenv: {e}")
def run_in_venv(cmd_list, cwd=None):
"""Run a command inside the virtual environment."""
try:
python_exe = VENV_DIR / "Scripts" / "python.exe"
full_cmd = [str(python_exe)] + cmd_list
logging.info("Running in venv: " + " ".join(full_cmd))
subprocess.check_call(full_cmd, cwd=cwd)
except subprocess.CalledProcessError as e:
logging.error(f"Error running command in venv: Command failed with error code {e.returncode}")
logging.error(f"Command: {' '.join(cmd_list)}")
if hasattr(e, 'stderr') and e.stderr:
logging.error(f"Command output (stderr):\n{e.stderr.decode()}")
if hasattr(e, 'stdout') and e.stdout:
logging.error(f"Command output (stdout):\n{e.stdout.decode()}")
raise
except FileNotFoundError:
logging.error(f"Python executable not found in virtual environment: {python_exe}")
raise
except Exception as e:
logging.error(f"Error in run_in_venv: {e}")
raise
def install_packages():
"""Install required packages in the virtual environment from REQUIREMENTS list."""
try:
logging.info("Installing required packages...")
run_in_venv(["-m", "pip", "install", "--upgrade", "pip"])
run_in_venv(["-m", "pip", "install"] + REQUIREMENTS)
logging.info("Required packages installed successfully.")
except Exception as e:
logging.error(f"Error in install_packages: {e}")
raise
def install_web_ui_requirements():
"""Install packages from the web-ui's requirements.txt file if it exists."""
try:
req_file = WEB_UI_DIR / "requirements.txt"
if req_file.exists():
logging.info("Installing web-ui requirements...")
run_in_venv(["-m", "pip", "install", "-r", "requirements.txt"], cwd=str(WEB_UI_DIR))
logging.info("Web-ui requirements installed successfully.")
else:
logging.info(f"No requirements.txt file found in the web-ui repository at: {req_file}")
except Exception as e:
logging.error(f"Error in install_web_ui_requirements: {e}")
raise
def update_env_file():
"""Create or update the .env file with Chrome settings."""
try:
env_file = Path(".env")
env_content = f'CHROME_PATH="{CHROME_PATH}"\nCHROME_USER_DATA="{NEW_PROFILE_DIR}"\n'
env_file.write_text(env_content, encoding="utf-8")
load_dotenv()
logging.info("Updated .env file with Chrome settings.")
except Exception as e:
logging.error(f"Error in update_env_file: {e}")
# def free_port(port):
# """Terminate any process using the specified port."""
# try:
# for conn in psutil.net_connections(kind='inet'):
# # Ensure that the connection has a valid pid before processing
# if conn.laddr.port == port and conn.status == 'LISTEN' and conn.pid:
# proc = psutil.Process(conn.pid)
# logging.info(f"Terminating process {proc.pid} on port {port}...")
# proc.terminate()
# try:
# proc.wait(timeout=5) # Wait for process to terminate
# logging.info(f"Process {proc.pid} terminated successfully.")
# except psutil.TimeoutExpired:
# logging.warning(f"Process {proc.pid} did not terminate within timeout.")
# except psutil.NoSuchProcess:
# logging.info(f"Process using port {port} already terminated or not found.")
# except Exception as e:
# logging.error(f"Error in free_port: {e}")
def copy_user_data():
"""Copy the user's existing Chrome profile data to a new profile for AutoPyBot."""
try:
default_user_data_path = Path(DEFAULT_USER_DATA_DIR)
if not default_user_data_path.exists():
logging.error(f"Default user data directory not found: {DEFAULT_USER_DATA_DIR}")
sys.exit(1)
if NEW_PROFILE_DIR.exists():
logging.info(f"Profile directory {NEW_PROFILE_DIR} already exists. Skipping copy.")
else:
logging.info(f"Copying user data from {DEFAULT_USER_DATA_DIR} to {NEW_PROFILE_DIR}...")
shutil.copytree(default_user_data_path, NEW_PROFILE_DIR, dirs_exist_ok=True) # dirs_exist_ok is used, merging user data if NEW_PROFILE_DIR exists.
logging.info("User data copied successfully.")
except FileNotFoundError:
logging.error(f"Source user data directory not found: {DEFAULT_USER_DATA_DIR}")
sys.exit(1)
except shutil.Error as e:
logging.error(f"Error during user data copy operation: {e}")
sys.exit(1)
except Exception as e:
logging.error(f"Unexpected error copying user data: {e}")
sys.exit(1)
def launch_chrome_with_profile():
"""Launch Chrome with the newly created profile for customization."""
try:
subprocess.Popen([CHROME_PATH, f"--user-data-dir={NEW_PROFILE_DIR}", "--no-first-run"], shell=False)
logging.info("Chrome launched with the new profile for customization.")
except FileNotFoundError:
logging.error(f"Chrome executable not found at: {CHROME_PATH}")
sys.exit(1)
except Exception as e:
logging.error(f"Error launching Chrome with profile: {e}")
sys.exit(1)
def launch_chrome_with_remote_debugging():
"""Launch Chrome with remote debugging enabled, without opening a dummy empty browser."""
try:
logging.info("🔄 Launching Chrome with remote debugging...")
chrome_cmd = [
CHROME_PATH,
f"--remote-debugging-port={REMOTE_DEBUGGING_PORT}",
f"--user-data-dir={NEW_PROFILE_DIR}", # Use the new profile
"--no-first-run",
"--disable-popup-blocking",
"--start-maximized",
"--new-window", # Open a new window only (prevents extra tabs)
UI_URL # Open the required Web UI directly
]
# "--no-default-browser-check",
subprocess.Popen(chrome_cmd, shell=False)
logging.info(f"✅ Chrome launched with remote debugging on port {REMOTE_DEBUGGING_PORT}, loading {UI_URL}")
except FileNotFoundError:
logging.error(f"❌ Chrome executable not found at: {CHROME_PATH}")
sys.exit(1)
except Exception as e:
logging.error(f"❌ Error launching Chrome with remote debugging: {e}")
sys.exit(1)
def start_web_ui():
"""Start the Web UI in a separate process without launching an extra browser."""
try:
logging.info("🟢 Starting the Web UI...")
python_exe = VENV_DIR / "Scripts" / "python.exe"
cmd = [str(python_exe), "webui.py", "--ip", "127.0.0.1", "--port", str(UI_PORT), "--theme", "Soft", "--dark-mode"]
process = subprocess.Popen(cmd, cwd=str(WEB_UI_DIR))
logging.info(f"✅ Web UI process started successfully with PID: {process.pid}")
return process
except FileNotFoundError:
logging.error(f"❌ Python executable not found: {python_exe}")
sys.exit(1)
except Exception as e:
logging.error(f"❌ Error starting Web UI: {e}")
sys.exit(1)
def open_ui_browser():
"""Ensure that only http://127.0.0.1:7788 is opened in the already running Chrome."""
try:
time.sleep(2) # Wait for Web UI to initialize
logging.info(f"🌍 Opening Web UI in default browser: {UI_URL}")
# Use Chrome with remote debugging to navigate the already running browser
chrome_remote_url = f"http://127.0.0.1:{REMOTE_DEBUGGING_PORT}/json"
response = requests.get(chrome_remote_url)
tabs = response.json()
if tabs:
first_tab = tabs[0]["id"] # Get the first active tab
page_url = f"http://127.0.0.1:{REMOTE_DEBUGGING_PORT}/json/close/{first_tab}"
requests.get(page_url) # Close the empty tab if it exists
webbrowser.open_new_tab(UI_URL) # Open the Web UI in the already running browser
except Exception as e:
logging.error(f"❌ Error opening Web UI browser: {e}")
async def configure_api_key():
"""Instruct the user to configure the API key."""
engine = pyttsx3.init()
instructions = (
"To use Gemini, please visit the following website to obtain your API key: "
"Once you have the key, please configure it in the LLM Configuration."
)
logging.info(instructions) # Use logging.info instead of print
engine.say(instructions)
engine.runAndWait()
async def get_gemini_api_key(page):
"""Gets the Gemini API key (manual copy)."""
try:
# logging.info("Navigating to Gemini API Key page...")
# await page.goto("https://aistudio.google.com/apikey", wait_until="load", timeout=60000)
# logging.info("Gemini API Key page loaded successfully.")
# # 1. Click the "Get API Key" button
# get_api_key_button_selector = "button:has-text('Get API key')"
# await page.click(get_api_key_button_selector, timeout=60000)
# logging.info("Clicked the 'Get API Key' button.")
# # 2. Click the "Create API key" button
# create_api_key_button_selector = "button:has-text('Create API key')"
# await page.locator(create_api_key_button_selector).wait_for(state="visible", timeout=60000)
# await page.click(create_api_key_button_selector, timeout=60000)
# logging.info("Clicked the 'Create API key' button.")
# engine = pyttsx3.init()
# instructions = (
# "Please copy the API key from the opened website and paste it "
# "into the web interface at Browser Use WebUI, choosing Google from LLM Configuration."
# )
# logging.info(instructions) # Use logging.info instead of print
# engine.say(instructions)
# engine.runAndWait()
return None # Return None because the key is manually copied
except Exception as e:
logging.exception(f"Error getting API key: {e}") # logging.exception is better here to include traceback
logging.error(f"Error getting API key: {e}") # Keep error log for consistency
raise
async def welcome_user():
"""Welcome the user with a voice message."""
engine = pyttsx3.init()
welcome_message = "Welcome to AutoPyBOT with Browser Use WebUI!"
logging.info(welcome_message) # Use logging.info instead of print
engine.say(welcome_message)
engine.runAndWait()
def check_api_key_configured():
"""Check if the Gemini API key is already configured (e.g., in a file or setting)."""
# Placeholder logic; replace with actual API key verification.
return False # Consider implementing actual check or making it configurable
def check_api_key_in_webui():
"""Check if the Gemini API key is already present in the WebUI."""
try:
# Placeholder: replace with your actual logic to check the key.
return False # Consider implementing actual check or making it configurable
except Exception as e:
logging.error(f"Error checking API key in WebUI: {e}")
return False
# import time
# import gradio as gr # Ensure Gradio is imported
# def display_prompts():
# with gr.Row(): # Create a row layout
# gr.Markdown("### Prompt Examples")
# prompts = [
# "**Prompt:** Add my latest LinkedIn follower to my leads in Salesforce.",
# "**More Examples:** [View on GitHub](https://github.com/browser-use/browser-use?tab=readme-ov-file#demos)"
# ]
# with gr.Row():
# prompt_display = gr.Markdown("")
# for prompt in prompts:
# prompt_display.value = prompt # Assign prompt text dynamically
# time.sleep(2)
# return prompt_display
def insert_prompts_into_webui(webui_py_path):
try:
with open(webui_py_path, "r", encoding="utf-8") as f:
webui_content = f.read()
prompts_code = """
import time
def display_prompts():
prompts = [
"Prompt: Add my latest LinkedIn follower to my leads in Salesforce.",
"More Example at https://github.com/browser-use/browser-use?tab=readme-ov-file#demos"
]
with gr.Row():
prompt_display = gr.Markdown("")
for prompt in prompts:
prompt_display.value = prompt
time.sleep(2)
return prompt_display
"""
# ✅ Ensure the function definition is inserted after "import gradio as gr"
import_match = re.search(r"import gradio as gr", webui_content)
if import_match:
insert_point = import_match.end()
new_content = webui_content[:insert_point] + "\n" + prompts_code + webui_content[insert_point:]
else:
logging.warning("⚠️ 'import gradio as gr' not found. Function definition insertion skipped.")
return
# 2. Find the placeholder and insert the component call there.
placeholder_match = re.search(r"# PLACEHOLDER_FOR_PROMPTS", new_content) # Search for the placeholder
if placeholder_match:
insert_point = placeholder_match.start()
# Insert the actual call to the display_prompts function, not the function definition again.
insertion_code = "\n prompts_component = display_prompts()"
new_content = new_content[:insert_point] + insertion_code + new_content[placeholder_match.end():]
with open(webui_py_path, "w", encoding="utf-8") as f:
f.write(new_content)
logging.info("Prompts inserted into webui.py successfully.")
else:
logging.warning("Could not find the placeholder in webui.py. Prompts not inserted.")
except FileNotFoundError:
logging.error(f"❌ webui.py not found at: {webui_py_path}")
except Exception as e:
logging.error(f"❌ Error inserting 'More Examples' into webui.py: {e}")
async def check_webui_started(url, timeout=30):
start_time = time.time()
while time.time() - start_time < timeout:
try:
response = requests.get(url)
if response.status_code == 200:
logging.info("Web UI started successfully.")
return True
except requests.exceptions.ConnectionError:
logging.info("Web UI is not yet available. Retrying...")
time.sleep(2)
except Exception as e:
logging.error(f"Error checking Web UI status: {e}")
return False
return False
# --- Main Execution Flow ---
async def main():
try:
if not is_admin():
logging.warning("⚠️ Administrator privileges are required. Relaunching as administrator...")
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
return
logging.info("🔄 Starting setup...")
check_git_installed()
clone_web_ui()
time.sleep(3)
create_virtualenv()
install_packages()
install_web_ui_requirements()
update_env_file()
webui_py_path = WEB_UI_DIR / "webui.py"
insert_prompts_into_webui(webui_py_path) # Insert the prompts code
# Profile management - create and customize if needed
# ✅ Ensure only one browser opens by properly managing profile
if not NEW_PROFILE_DIR.exists():
logging.info("🟢 Creating a new Chrome profile for automation...")
copy_user_data()
if not (NEW_PROFILE_DIR / "FirstRun").exists():
launch_chrome_with_profile()
logging.info("🟢 Chrome profile created. Customize it (e.g., bookmarks, logins).")
input("Press Enter once customization is complete...")
(NEW_PROFILE_DIR / "FirstRun").touch()
# ✅ Start the Web UI and launch Chrome properly
# webui_process = start_web_ui()
start_web_ui()
time.sleep(5)
# if not await check_webui_started(UI_URL, timeout=30):
# logging.error("❌ Web UI did not start in time. Exiting.")
# webui_process.terminate()
# sys.exit(1)
launch_chrome_with_remote_debugging() # 🔄 Open Chrome with correct profile
open_ui_browser() # 🌍 Open only http://127.0.0.1:7788, prevent empty tabs
await welcome_user()
async with sync_playwright() as p:
try:
browser = await p.chromium.connect_over_cdp(f"ws://127.0.0.1:{REMOTE_DEBUGGING_PORT}/devtools/browser")
context = browser.contexts[0]
page = context.pages[0] if context.pages else await context.new_page()
await page.goto(UI_URL, wait_until="networkidle2")
logging.info("Web UI loaded successfully.")
await browser.close()
except Exception as e:
logging.error(f"Error in Playwright interaction: {e}")
if browser:
await browser.close()
sys.exit(1)
logging.info("✅ Setup and Automation Ready!")
input("Press Enter to exit.")
except Exception as e:
logging.error(f"❌ Unexpected error: {e}")
sys.exit(1)
if __name__ == "__main__":
asyncio.run(main())
# .\.venv\Scripts\activate
# python .\bootstrap.py
# pyinstaller --onefile bootstrap.py
# pyinstaller --onefile --add-data "D:\AutoPyBOT-Browser-UI\web-ui\webui.py.original;web-ui" --add-data "D:\AutoPyBOT-Browser-UI\web-ui\webui.py.template;web-ui" --add-data "D:\AutoPyBOT-Browser-UI\web-ui\webui.py;web-ui" bootstrap.py
# https://github.com/py-bots/AutoPyBOT-Browser-UI