-
Notifications
You must be signed in to change notification settings - Fork 16
/
sample_misp_playbook_to_cacao_malware_triage.json
518 lines (518 loc) · 165 KB
/
sample_misp_playbook_to_cacao_malware_triage.json
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
{
"type": "playbook",
"spec_version": "cacao-2.0",
"id": "playbook--3bc94d2b-598a-4c33-8f7d-44d07ac7652d",
"created": "2024-10-16T07:41:53Z",
"modified": "2024-10-16T07:41:53Z",
"created_by": "identity--ee23aaac-78d1-4b51-a88c-74dde045af42",
"name": "Malware triage with MISP",
"description": "Malware triage with MISP",
"labels": [
"malware",
"triage",
"incidentresponse",
"ir",
"dfir"
],
"playbook_types": [
"investigation"
],
"playbook_activities": [
"PR:1 Initialise environment",
"PR:2 Verify MISP modules",
"PR:3 Load helper functions",
"PR:4 Set helper variables",
"PR:5 Load and defang samples",
"PR:6 MISP event details",
"PR:7 Setup MISP event link",
"IN:1 File analysis",
"IN:2 VirusTotal results",
"IN:3 Hashlookup",
"IN:4 MalwareBazaar",
"IN:5 PE imports and exports",
"IN:6 MISP report for investigation",
"CR:1 Correlation with MISP events",
"CR:2 Correlation with MISP feeds",
"SA:1 Store in MWDB",
"EN:1 MISP indicators",
"EN:2 Create the summary of the playbook",
"EN:3 Print the input for malware triage",
"EN:4 Send a summary to Mattermost",
"EN:5 End of the playbook"
],
"workflow_start": "start--75f753e3-be32-4156-8b1f-188b3bac596a",
"workflow": {
"start--75f753e3-be32-4156-8b1f-188b3bac596a": {
"type": "start",
"name": "Start of Playbook",
"on_completion": "action--780722a7-1a73-40eb-bd71-b4289b818ea0"
},
"action--780722a7-1a73-40eb-bd71-b4289b818ea0": {
"type": "action",
"name": "Introduction",
"description": "# Malware triage with MISP\n\n## Introduction\n\n- UUID: **68b42f4d-8d5e-46c4-97f8-b87b9df210a3**\n- Started from [issue 2](https://github.com/MISP/misp-playbooks/issues/2)\n- State: **Published**\n- Purpose: A playbook to provide an analyst sufficient information to do basic malware triage on one or more samples.\n - This playbook creates a **MISP event** for malware triage. \n - Samples are **attached** to a MISP event (with file object relations).\n - VirusTotal and MalwareBazaar are used to get the **detection rate**, **threat classification** and **sandbox** information.\n - Hashlookup is used to check for **known hashes**.\n - PEfile analysis is done for **imports** and **exports**.\n - The results are stored in **MISP reports** and as MISP objects where relevant.\n - Correlations with MISP events or data feeds are added to a summary.\n - The sample is shared with a local instance of **MWDBcore**.\n - The summary is then sent to Mattermost.\n- Tags: [ \"malware\", \"triage\", \"incidentresponse\", \"ir\", \"dfir\" ]\n- External resources: **VirusTotal, Hashlookup, MalwareBazaar, MWDB, Mattermost**\n- Target audience: **SOC**, **CSIRT**, **CTI**\n- Notes:\n - Samples are stored in a \"malwarezoo\", defined in the variable `malwarezoo`.\n - All samples that do not have an extension \"do-not-run\" (set in `defangsuffix`) are considered as unprocessed.\n - The playbook adds the defangsuffix when it processes the samples.\n - For VirusTotal and MalwareBazaar, both the MISP modules as well as direct queries to VT/MB are used.",
"commands": [
{
"type": "manual",
"command": ""
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--059f72f4-25e6-40fb-b80d-b8c84ed26437"
},
"action--059f72f4-25e6-40fb-b80d-b8c84ed26437": {
"type": "action",
"name": "PR:1 Initialise environment",
"description": "# Preparation\n\n## PR:1 Initialise environment\n\nThis section **initialises the playbook environment** and loads the required Python libraries. \n\nThe credentials for MISP (**API key**) and other services are loaded from the file `keys.py` in the directory **vault**. A [PyMISP](https://github.com/MISP/PyMISP) object is created to interact with MISP and the active MISP server is displayed. By printing out the server name you know that it's possible to connect to MISP. In case of a problem PyMISP will indicate the error with `PyMISPError: Unable to connect to MISP`.\n\nThe contents of the `keys.py` file should contain at least :\n\n```\nmisp_url=\"<MISP URL>\" # The URL to our MISP server\nmisp_key=\"<MISP API KEY>\" # The MISP API key\nmisp_verifycert=<True or False> # Indicate if PyMISP should attempt to verify the certificate or ignore errors\n```",
"commands": [
{
"type": "manual",
"command": "# Initialise Python environment\nimport urllib3\nimport sys\nimport json\nfrom pyfaup.faup import Faup\nfrom prettytable import PrettyTable, MARKDOWN\nfrom IPython.display import Image, display, display_markdown, HTML\nfrom datetime import date\nimport requests\nimport uuid\n#from uuid import uuid4\nfrom pymisp import *\nfrom pymisp.tools import GenericObjectGenerator\nfrom pymisp.tools import make_binary_objects\nimport logging\n\nimport os\nimport time\nimport pefile\nfrom datetime import datetime\nfrom mwdblib import MWDB\n\n# Load the credentials\nsys.path.insert(0, \"../vault/\")\nfrom keys import *\nif misp_verifycert is False:\n import urllib3\n urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\nprint(\"The \\033[92mPython libraries\\033[90m are loaded and the \\033[92mcredentials\\033[90m are read from the keys file.\")\n\n# Create the PyMISP object\nmisp = PyMISP(misp_url, misp_key, misp_verifycert)\nprint(\"I will use the MISP server \\033[92m{}\\033[90m for this playbook.\\n\\n\".format(misp_url))\n\n# Create headers for specific cases\nmisp_headers = {\"Authorization\": misp_key, \"Content-Type\": \"application/json\", \"Accept\": \"application/json\"}"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--c0ff32ee-cf58-4fb3-948d-40670cd0f8e1"
},
"action--c0ff32ee-cf58-4fb3-948d-40670cd0f8e1": {
"type": "action",
"name": "PR:2 Verify MISP modules",
"description": "## PR:2 Verify MISP modules\n\nThis playbook uses the MISP modules to obtain additional correlation or enrichment information. [MISP modules](https://github.com/MISP/misp-modules) are autonomous modules that can be used to extend MISP for new services such as expansion, import and export. The modules are written in Python 3 following a simple API interface. The objective is to ease the extensions of MISP functionalities without modifying core components. The API is available via a simple REST API which is independent from MISP installation or configuration.\n\nIn the next cell we check if we have access to the **MISP module** server and if the required modules are enabled.",
"commands": [
{
"type": "manual",
"command": "# Where can we find the local MISP Module server? You can leave this to the default setting in most cases.\nmisp_modules_url = \"http://127.0.0.1:6666\"\n\n# How long do we wait between queries when using the MISP modules (API rate limiting of external service such as VirusTotal)\nmisp_modules_wait = 3\n\n# Initiliasation\nmisp_modules = {}\nmisp_modules_headers = {\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\"\n}\nmisp_modules_in_use = [\"hashlookup\", \"virustotal_public\", \"malwarebazaar\"]\n# Code block to query the MISP module server and check if our modules are enabled\nres = requests.get(\"{}/modules\".format(misp_modules_url), headers=misp_modules_headers)\nfor module in res.json():\n for module_requested in misp_modules_in_use:\n if module.get(\"name\", False) == module_requested:\n misp_modules[module_requested] = {\"enabled\": True, \"input\": module.get(\"mispattributes\").get(\"input\")}\n print(\"Found the \\033[92m{}\\033[90m MISP module (Accepted input: {}).\".format(module_requested, misp_modules[module_requested][\"input\"]))\nprint(\"\\n\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--20de29d0-f151-4a10-9830-f878cf4defc6"
},
"action--20de29d0-f151-4a10-9830-f878cf4defc6": {
"type": "action",
"name": "PR:3 Load helper functions",
"description": "## PR:3 Load helper functions\n\nThe next cell contains **helper functions** that are used in this playbook. \n\nInstead of distributing helper functions as separate Python files this playbook includes all the required code as one code cell. This makes portability of playbooks between instances easier. The downside is that functions defined in this playbook need to be defined again in other playbooks, which is not optimal for code re-use. For this iteration of playbooks it is chosen to include the code in the playbook (more portability), but you can easily create one \"helper\" file that contains all the helper code and then import that file in each playbook (for example by adding to the previous cell `from helpers import *`). Note that the graphical workflow image is included as an external image. A missing image would not influence the further progress of the playbook.",
"commands": [
{
"type": "manual",
"command": "def pb_get_misp_tags(tags=[], local_tags=[]):\n '''\n Get a list of MISP tags based on a Python list\n\n :param misp: MISP object\n :param object_template: which object template to return\n '''\n misp_tags = []\n for el in tags:\n t = MISPTag()\n t.name = el\n t.local = False\n misp_tags.append(t)\n\n for el in local_tags:\n t = MISPTag()\n t.name = el\n t.local = True\n misp_tags.append(t)\n return misp_tags\n\n\ndef calculate_risk_score(ratio):\n '''\n Calculate risk score and return the score and a tag\n '''\n detection_ratio_perc = 0\n score = 0\n base = 0\n tag = \"\"\n if len(ratio) > 0:\n for detection_ratio in ratio:\n score += int(detection_ratio.split(\"/\")[0])\n base += int(detection_ratio.split(\"/\")[1])\n if base > 0:\n detection_ratio_perc = round((score / base) * 100, 2)\n if detection_ratio_perc > 0:\n if detection_ratio_perc >= 75:\n tag = \"misp:threat-level=\\\"high-risk\\\"\"\n elif detection_ratio_perc >= 50:\n tag = \"misp:threat-level=\\\"medium-risk\\\"\"\n #elif detection_ratio_perc >= 25:\n else:\n tag = \"misp:threat-level=\\\"low-risk\\\"\"\n else:\n tag = \"misp:threat-level=\\\"no-risk\\\"\"\n return detection_ratio_perc, tag"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--f5e57d58-0eff-448b-94fb-b00371467294"
},
"action--f5e57d58-0eff-448b-94fb-b00371467294": {
"type": "action",
"name": "PR:4 Set helper variables",
"description": "## PR:4 Set helper variables\n\nThis cell contains **helper variables** that are used in this playbook. Their usage is explained in the next steps of the playbook.\n\n- `samples` : a dictionary of the objects that are created when the playbook progresses\n- `malwarezoo` : the location where the samples are uploaded\n- `defangsuffix` : the suffix to add when defanging the samples",
"commands": [
{
"type": "manual",
"command": "# Dictionary to store playbook results\nsamples = {}\n\n# Location to upload samples\nmalwarezoo = \"/data/notebook-demo/playbook/notebooks/evidence\"\n\n# Suffix to add when defanging the samples\ndefangsuffix = \".do-not-run\"\n\n# Helper variables\nmisp_event = False\nsummary = \"\""
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--4427808c-ac8f-466d-827a-7650479675b2"
},
"action--4427808c-ac8f-466d-827a-7650479675b2": {
"type": "action",
"name": "PR:5 Load and defang samples",
"description": "## PR:5 Load and defang samples\n\nThis section checks if there are unprocessed samples in `malwarezoo` and **loads these samples** in the dictionary `samples`. It will also defang the sample to prevent accidential execution. A sample with the `defangsuffix` suffix is considered as processed.",
"commands": [
{
"type": "manual",
"command": "# Check if the malware samples directory exists and misp modules are enabled\nmalwarezoo_errors = False\n\nmalwarezoo_samples = [file for file in os.listdir(malwarezoo) if os.path.isfile(os.path.join(malwarezoo, file))]\nif len(malwarezoo_samples) == 0:\n print(\"There are no files in \\033[91m{}\\033[90m.\".format(malwarezoo))\n print(\"\\033[91mUnable to proceed!\\033[90m\")\nelse:\n # Defang the samples before we continue\n print(\"Defang samples\")\n for sample in malwarezoo_samples:\n if defangsuffix not in sample:\n sample_path = \"{}/{}{}\".format(malwarezoo, sample, defangsuffix)\n sample_orig_path = \"{}/{}\".format(malwarezoo, sample)\n os.system(\"mv {} {}\".format(sample_orig_path, sample_path))\n samples[sample] = {\"path\": sample_path, \"orig_path\": sample_orig_path}\n samples[sample][\"MISP\"] = []\n samples[sample][\"Feeds\"] = []\n samples[sample][\"detection_ratio\"] = []\n samples[sample][\"detection_ratio_indirect\"] = []\n samples[sample][\"vt\"] = {}\n samples[sample][\"malwarebazaar\"] = {}\n samples[sample][\"hashlookup\"] = {}\n samples[sample][\"pe\"] = {}\n print(\" Renamed {} to \\033[92m{}\\033[90m\".format(sample, sample_path))\n else:\n print(\" Skip \\033[91m{}\\033[90m, already processed (defanged).\".format(sample))\n if len(samples) > 0:\n print(\"\\n\\033[92mContinue\\033[90m the playbook with \\033[92m{}\\033[90m samples.\\n\".format(len(samples)))\n else:\n print(\"All samples in the malwarezoo ({}) are \\033[91malready processed\\033[90m (defanged).\\n\".format(malwarezoo))"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--c06ffc4b-1955-4166-a665-a8170708b2f9"
},
"action--c06ffc4b-1955-4166-a665-a8170708b2f9": {
"type": "action",
"name": "PR:6 MISP event details",
"description": "## PR:6 MISP event details\n\n### Event title\n\nIn this playbook we create a **new** MISP event with title **Malware triage for _malwarelist_**. You get the chance to override this default title but remember that it is good practice to choose a self-explanatory **event title**. This event title is shown in the MISP event index and should provide you the necessary information what the event is about. You should avoid using generic event titles. Read the [Best Practices in Threat Intelligence](https://www.misp-project.org/best-practices-in-threat-intelligence.html) for further guidance.\n\n### Contexualisation\n\nThis playbook adds event contexualisation via the **tags** that are defined in `event_additional_global_tags` (for *global* tags) and `event_additional_local_tags` (for *local* tags). As a reminder, whereas *global* tags remain attached to the events that you share with your community, the *local* tags are not shared outside your organisation. It's also a good idea to primarily use tags that are part of a [taxonomy](https://github.com/MISP/misp-taxonomies), this allows you to make the contexualisation more portable accross multiple MISP instances.\n\nIn this playbook the list of tags is build via one of the helper functions `pb_get_misp_tags`. This function takes two arguments, first a list of tags to convert as *global* tags, and secondly a list of tags to convert as *local* tags. It then returns a Python list of MISPTag objects.\n\n### Traffic Light Protocol\n\nThe default **TLP** for this event is **<span style='color:#FFBF00'>tlp:amber</span>**. The Traffic Light Protocol (TLP) facilitates sharing of potentially sensitive information and allows for more effective collaboration. TLP is a set of four standard labels to indicate the sharing boundaries to be applied by the recipients. TLP is always set by the creator of information. You can find more information at [FIRST](https://www.first.org/tlp/). You can specify the TLP via `event_tlp`.\n\n### MISP galaxies\n\nThis playbook can also add MISP galaxies to the event with the variable `event_galaxies`. You can also leave the list empty if you do not want to add galaxies in this stage of the investigation.\n\n### MISP distribution, threat level and analysis level\n\nOptionally you can specifiy a MISP **distribution** (with `event_distribution`), **threat level** (with `event_threat_level_id`) or **analysis state** (with `event_analysis`). The event **date** is set to today via `event_date`.\n\nIf you cannot remember the options for distribution, threat level or the analysis state then use the next cell to guide you. This cell is set as **raw**. If you **change its type to code** and execute the cell you get an overview of the options available for creating a MISP event.",
"commands": [
{
"type": "manual",
"command": ""
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--b474b97f-4cd7-4d1f-b682-f67ee4252eaf"
},
"action--b474b97f-4cd7-4d1f-b682-f67ee4252eaf": {
"type": "action",
"name": "PR:7 Setup MISP event link",
"description": "## PR:7 Setup MISP event link\n\nBy default the playbook will generate a **title** with a prefix and the malware you want to investigate. You can override this event title with the variable `event_title`. If you leave this value empty the playbook will generate the MISP event title for you.",
"commands": [
{
"type": "manual",
"command": "# Provide the event title for a new event. Leave blank for the playbook to auto generate one\nevent_title = \"\"\n\n# Prefix for auto generate event title\nevent_title_default_prefix = \"Malware triage\"\n\n# Optionally, you can change TLP, add additional event (local and global) tags, threatlevel, analysis state or distribution level\nevent_tlp = \"tlp:amber\"\n\n# Event context\nevent_additional_global_tags = [] # This needs to be a Python list\nevent_additional_local_tags = [\"workflow:state=\\\"incomplete\\\"\"] # This needs to be a Python list\n\n# Event galaxies\nevent_galaxies = [ \"misp-galaxy:mitre-attack-pattern=\\\"Malware - T1587.001\\\"\", \"misp-galaxy:mitre-attack-pattern=\\\"Malware - T1588.001\\\"\"]\n\n# Additional MISP event settings\nevent_threat_level_id = ThreatLevel.low\nevent_analysis = Analysis.ongoing\nevent_distribution = Distribution.your_organisation_only\nevent_date = date.today()"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--b2bb108f-1dba-49e1-be21-e46cc4592e5a"
},
"action--b2bb108f-1dba-49e1-be21-e46cc4592e5a": {
"type": "action",
"name": "Create MISP event",
"description": "### Create MISP event\n\nThe next code cell will **create the MISP event** and store the references to the newly created event in the variable `misp_event`. This variable is used further when the playbook progresses.",
"commands": [
{
"type": "manual",
"command": "# Code block to create the event or add data to an existing event\nevent_title = event_title.strip()\n\nif not(len(event_title) > 0):\n query_sample = \"\"\n for key, sample in samples.items():\n query_sample = \"{} {}\".format(key, query_sample)\n event_title = \"{} for {}\".format(event_title_default_prefix, query_sample)\n\n# Construct the event tags\nevent_additional_global_tags.append(event_tlp)\nif len(event_galaxies) > 0:\n event_additional_global_tags.append(event_galaxies)\nevent_tags = pb_get_misp_tags(event_additional_global_tags, event_additional_local_tags)\n\n# Create the PyMISP object for an event\nevent = MISPEvent()\nevent.info = event_title\nevent.distribution = event_distribution\nevent.threat_level_id = event_threat_level_id\nevent.analysis = event_analysis\nevent.set_date(event_date)\n\n# Create the MISP event on the server side\nmisp_event = misp.add_event(event, pythonify=True)\nprint(\"Continue the playbook with the new \\033[92mcreated\\033[90m MISP event ID {} with title \\033[92m{}\\033[90m and UUID {}\".format(misp_event.id, misp_event.info, misp_event.uuid))\nfor tag in event_tags:\n if len(tag) > 0:\n misp.tag(misp_event.uuid, tag, local=tag.local)\n print(\"\\033[92mAdded\\033[90m event tag {}\".format(tag))\nprint(\"\\n\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--78f6bddc-589c-4cb9-9f73-826675f614c5"
},
"action--78f6bddc-589c-4cb9-9f73-826675f614c5": {
"type": "action",
"name": "IN:2 VirusTotal results",
"description": "## IN:2 VirusTotal results\n\nNext we use [VirusTotal](https://www.virustotal.com/gui/). First we use the MISP modules to query VirusTotal. The advantage of using the MISP modules is that it returns MISP attributes and objects that can then be easily added to the event.\n\nAfter using the modules, we query VirusTotal directly (without using the module) to get the **threat classification**, **sandbox** results and the **Sigma** rules that triggered detection.\n\nNote that the sample is **not** submitted to VirusTotal for analysis.",
"commands": [
{
"type": "manual",
"command": "# Loop through the samples\n\n# Use the modules to create MISP objects\n# Then do a second query to get the file details\n\nscan_count = 0\nmodule_name = \"virustotal_public\"\nheaders = {\n \"accept\": \"application/json\",\n \"x-apikey\": virustotal_apikey\n}\n\nprint(\"Verifying samples with {}\".format(module_name))\nfor key, sample in samples.items():\n attribute_type = \"sha256\"\n value = sample.get(\"sha256\")\n module_comment = \"From {} for {}\".format(module_name, key)\n data = {\n \"attribute\": {\n \"type\": f\"{attribute_type}\",\n \"uuid\": str(uuid.uuid4()),\n \"value\": f\"{value}\",\n },\n \"module\": module_name,\n \"config\": {\"apikey\": virustotal_apikey}\n }\n print(\"Query \\033[92m{}\\033[90m as \\033[92m{}\\033[90m\".format(value, attribute_type))\n result = requests.post(\"{}/query\".format(misp_modules_url), headers=misp_modules_headers, json=data)\n if \"results\" in result.json() and len(result.json()[\"results\"]) > 0:\n result_json = result.json()[\"results\"]\n\n for misp_attribute in result_json.get(\"Attribute\", []):\n misp_attribute[\"comment\"] = \"{}{}\".format(module_comment, misp_attribute.get(\"comment\", \"\"))\n created_attribute = misp.add_attribute(misp_event.uuid, misp_attribute, pythonify=True)\n if not \"errors\" in created_attribute:\n print(\" Got {} \\033[92m{}\\033[90m\".format(misp_attribute[\"type\"], misp_attribute[\"value\"]))\n misp.add_object_reference(sample.get(\"fileobject\").add_reference(created_attribute.uuid, \"related-to\"))\n else:\n print(\" Unable to add {} \\033[92m{}\\033[90m to MISP event\".format(misp_attribute[\"type\"], misp_attribute[\"value\"]))\n for misp_object in result_json.get(\"Object\", []):\n misp_object[\"comment\"] = \"{}{}\".format(module_comment, misp_object.get(\"comment\", \"\"))\n if len(misp_object[\"Attribute\"]) > 0:\n created_object = misp.add_object(misp_event.uuid, misp_object, pythonify=True)\n if not \"errors\" in created_object:\n print(\" Got \\033[92m{}\\033[90m \".format(misp_object[\"name\"]))\n misp.add_object_reference(sample.get(\"fileobject\").add_reference(created_object.uuid, \"related-to\"))\n if misp_object[\"name\"] == \"virustotal-report\":\n direct_vt_report = False\n detection_ratio = False\n for attribute in misp_object.get(\"Attribute\", []):\n if attribute.get(\"object_relation\") == \"permalink\" and value in attribute.get(\"value\"):\n direct_vt_report = True\n if attribute.get(\"object_relation\") == \"detection-ratio\":\n detection_ratio = attribute.get(\"value\")\n if detection_ratio:\n if direct_vt_report:\n samples[key][\"detection_ratio\"].append(detection_ratio)\n print(\" Got detection ratio \\033[92m{}\\033[90m \".format(detection_ratio))\n else:\n samples[key][\"detection_ratio_indirect\"].append(detection_ratio)\n print(\" Got indirect detection ratio \\033[92m{}\\033[90m \".format(detection_ratio))\n else:\n print(\" Unable to add \\033[92m{}\\033[90m to MISP event\".format(misp_object[\"name\"]))\n\n risk1, tag1 = calculate_risk_score(sample.get(\"detection_ratio\"))\n risk2, tag2 = calculate_risk_score(sample.get(\"detection_ratio_indirect\"))\n if len(tag1) > 0:\n misp.tag(sample.get(\"sha256_uuid\"), tag1)\n misp.tag(sample.get(\"malware-sample_uuid\"), tag1)\n\n risk_rating = \"vt-detection-ratio={}\\nvt-detection-ratio-indirect={}\".format(risk1, risk2)\n samples[key][\"detection_ratio_perc\"] = risk1\n samples[key][\"detection_ratio_indirect_perc\"] = risk2\n samples[key][\"risk_rating\"] = risk_rating\n sample.get(\"fileobject\").add_attribute(\"text\", risk_rating)\n misp.update_object(sample.get(\"fileobject\"))\n\n #################################################################\n\n print(\" Query VirusTotal directly to get file details\")\n vt_url = \"https://www.virustotal.com/api/v3/files/{}\".format(value)\n result = requests.get(vt_url, headers=headers)\n if \"data\" in result.json() and len(result.json()[\"data\"]) > 0:\n result_json = result.json()[\"data\"][\"attributes\"]\n samples[key][\"vt\"][\"data\"] = result_json\n samples[key][\"vt\"][\"popular_threat_classification\"] = result_json.get(\"popular_threat_classification\", [])\n samples[key][\"vt\"][\"sigma_analysis_results\"] = result_json.get(\"sigma_analysis_results\", [])\n samples[key][\"vt\"][\"sandbox_verdicts\"] = result_json.get(\"sandbox_verdicts\", [])\n samples[key][\"vt\"][\"sandboxes\"] = []\n samples[key][\"vt\"][\"markdown\"] = \"\"\n\n if len(samples[key][\"vt\"][\"popular_threat_classification\"]) > 0:\n samples[key][\"vt\"][\"markdown\"] = \"#### Popular threat classifications\\n\"\n for el in samples[key][\"vt\"][\"popular_threat_classification\"]:\n if el == \"suggested_threat_label\":\n samples[key][\"vt\"][\"suggested_threat_label\"] = samples[key][\"vt\"][\"popular_threat_classification\"][el]\n samples[key][\"vt\"][\"markdown\"] = \"{}\\n- {}: {}\".format(samples[key][\"vt\"][\"markdown\"], el, samples[key][\"vt\"][\"popular_threat_classification\"][el])\n\n if len(samples[key][\"vt\"][\"sigma_analysis_results\"]) > 0:\n samples[key][\"vt\"][\"markdown\"] = \"{}\\n\\n#### Sigma analysis results\\n\".format(samples[key][\"vt\"][\"markdown\"])\n for el in samples[key][\"vt\"][\"sigma_analysis_results\"]:\n samples[key][\"vt\"][\"markdown\"] = \"{}\\n - {}\".format(samples[key][\"vt\"][\"markdown\"], el[\"rule_title\"])\n\n if len(samples[key][\"vt\"][\"sandbox_verdicts\"]) > 0:\n samples[key][\"vt\"][\"markdown\"] = \"{}\\n\\n#### Sandbox verdicts\\n\".format(samples[key][\"vt\"][\"markdown\"])\n for el in samples[key][\"vt\"][\"sandbox_verdicts\"]:\n samples[key][\"vt\"][\"sandboxes\"].append(el)\n samples[key][\"vt\"][\"markdown\"] = \"{}\\n - **{}**\".format(samples[key][\"vt\"][\"markdown\"], el)\n for el_sandbox in samples[key][\"vt\"][\"sandbox_verdicts\"][el]:\n samples[key][\"vt\"][\"markdown\"] = \"{}\\n - {}: {}\".format(samples[key][\"vt\"][\"markdown\"], el_sandbox, samples[key][\"vt\"][\"sandbox_verdicts\"][el][el_sandbox])\n print(\" Finished query VirusTotal directly\")\n else:\n print(\"No results for \\033[91m{}\\033[90m.\".format(value))\n scan_count += 1\n if scan_count > 5:\n print(\"Sleeping for {} seconds\".format(misp_modules_wait))\n time.sleep(misp_modules_wait)\n scan_count = 0\nprint(\"Finished {}\".format(module_name))"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--1e3855ff-0256-42e7-9e34-3ec214f01a3e"
},
"action--1e3855ff-0256-42e7-9e34-3ec214f01a3e": {
"type": "action",
"name": "IN:3 Hashlookup",
"description": "## IN:3 Hashlookup\n\nWe use [CIRCL Hashlookup](https://www.circl.lu/services/hashlookup/) to identify if any of the samples correspond with **known hashes**.",
"commands": [
{
"type": "manual",
"command": "# Loop through the samples\n\nmodule_name = \"hashlookup\"\nprint(\"Lookup the file in {}\".format(module_name))\nfor key, sample in samples.items():\n attribute_type = \"sha256\"\n value = sample.get(\"sha256\")\n module_comment = \"From {} for {}\".format(module_name, key)\n data = {\n \"attribute\": {\n \"type\": f\"{attribute_type}\",\n \"uuid\": str(uuid.uuid4()),\n \"value\": f\"{value}\",\n },\n \"module\": module_name,\n \"config\": {\"custom_API\": False}\n }\n print(\"Query \\033[92m{}\\033[90m as \\033[92m{}\\033[90m\".format(value, attribute_type))\n result = requests.post(\"{}/query\".format(misp_modules_url), headers=misp_modules_headers, json=data)\n if \"results\" in result.json() and len(result.json()[\"results\"]) > 0:\n result_json = result.json()[\"results\"]\n hashlookup_hit = False\n hashlookuptext = \"\"\n for misp_attribute in result_json.get(\"Attribute\", []):\n misp_attribute[\"comment\"] = \"{}{}\".format(module_comment, misp_attribute.get(\"comment\", \"\"))\n created_attribute = misp.add_attribute(misp_event.uuid, misp_attribute, pythonify=True)\n if not \"errors\" in created_attribute:\n print(\" Got {} \\033[92m{}\\033[90m\".format(misp_attribute[\"type\"], misp_attribute[\"value\"]))\n misp.add_object_reference(sample.get(\"fileobject\").add_reference(created_attribute.uuid, \"related-to\"))\n else:\n print(\" Unable to add {} \\033[92m{}\\033[90m to MISP event\".format(misp_attribute[\"type\"], misp_attribute[\"value\"]))\n for misp_object in result_json.get(\"Object\", []):\n misp_object[\"comment\"] = \"{}{}\".format(module_comment, misp_object.get(\"comment\", \"\"))\n if len(misp_object[\"Attribute\"]) > 0:\n created_object = misp.add_object(misp_event.uuid, misp_object, pythonify=True)\n if not \"errors\" in created_object:\n\n print(\" Got \\033[92m{}\\033[90m \".format(misp_object[\"name\"]))\n misp.add_object_reference(sample.get(\"fileobject\").add_reference(created_object.uuid, \"related-to\"))\n for attribute in misp_object.get(\"Attribute\", []):\n if attribute[\"object_relation\"] not in [\"MD5\", \"SHA-1\", \"SHA-256\", \"SSDEEP\"]:\n hashlookuptext = \"{}: {}\\n{}\".format(attribute[\"object_relation\"], attribute[\"value\"], hashlookuptext)\n if attribute.get(\"object_relation\") == \"KnownMalicious\":\n hashlookup_hit = True\n else:\n print(\" Unable to add \\033[92m{}\\033[90m to MISP event\".format(misp_object[\"name\"]))\n\n if hashlookup_hit:\n misp.tag(sample.get(\"sha256_uuid\"), \"misp-workflow:analysis=\\\"known-file-hash\\\"\")\n misp.tag(sample.get(\"malware-sample_uuid\"), \"misp-workflow:analysis=\\\"known-file-hash\\\"\")\n\n sample.get(\"fileobject\").add_attribute(\"text\", hashlookuptext)\n samples[key][\"hashlookup\"][\"data\"] = result_json\n samples[key][\"hashlookup\"][\"markdown\"] = hashlookuptext\n misp.update_object(sample.get(\"fileobject\"))\n else:\n print(\"No results for \\033[91m{}\\033[90m.\".format(value))\nprint(\"Finished {}\".format(module_name))"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--5e6a08f4-39a2-4be9-a7cd-cf265fcd10f8"
},
"action--5e6a08f4-39a2-4be9-a7cd-cf265fcd10f8": {
"type": "action",
"name": "IN:4 MalwareBazaar",
"description": "## IN:4 MalwareBazaar\n\nNow we query [MalwareBazaar](https://bazaar.abuse.ch/). Similar as with VirusTotal, we use the MISP module to get useful attributes and objects. Afterwards we query MalwareBazaar directly to get more details such as vendor intel and tags.",
"commands": [
{
"type": "manual",
"command": "# Loop through the samples\n\nmodule_name = \"malwarebazaar\"\nprint(\"Lookup the file in {}\".format(module_name))\nfor key, sample in samples.items():\n attribute_type = \"sha256\"\n value = sample.get(\"sha256\")\n module_comment = \"From {} for {}\".format(module_name, key)\n data = {\n \"attribute\": {\n \"type\": f\"{attribute_type}\",\n \"uuid\": str(uuid.uuid4()),\n \"value\": f\"{value}\",\n },\n \"module\": module_name,\n }\n print(\"Query \\033[92m{}\\033[90m as \\033[92m{}\\033[90m\".format(value, attribute_type))\n result = requests.post(\"{}/query\".format(misp_modules_url), headers=misp_modules_headers, json=data)\n if \"results\" in result.json() and len(result.json()[\"results\"]) > 0:\n result_json = result.json()[\"results\"]\n for misp_attribute in result_json.get(\"Attribute\", []):\n misp_attribute[\"comment\"] = \"{}{}\".format(module_comment, misp_attribute.get(\"comment\", \"\"))\n created_attribute = misp.add_attribute(misp_event.uuid, misp_attribute, pythonify=True)\n if not \"errors\" in created_attribute:\n print(\" Got {} \\033[92m{}\\033[90m\".format(misp_attribute[\"type\"], misp_attribute[\"value\"]))\n misp.add_object_reference(sample.get(\"fileobject\").add_reference(created_attribute.uuid, \"related-to\"))\n else:\n print(\" Unable to add {} \\033[92m{}\\033[90m to MISP event\".format(misp_attribute[\"type\"], misp_attribute[\"value\"]))\n for misp_object in result_json.get(\"Object\", []):\n misp_object[\"comment\"] = \"{}{}\".format(module_comment, misp_object.get(\"comment\", \"\"))\n if len(misp_object[\"Attribute\"]) > 0:\n created_object = misp.add_object(misp_event.uuid, misp_object, pythonify=True)\n if not \"errors\" in created_object:\n print(\" Got \\033[92m{}\\033[90m \".format(misp_object[\"name\"]))\n misp.add_object_reference(sample.get(\"fileobject\").add_reference(created_object.uuid, \"related-to\"))\n else:\n print(\" Unable to add \\033[92m{}\\033[90m to MISP event\".format(misp_object[\"name\"]))\n\n #################################################################\n\n print(\" Query MalwareBazaar directly to get file details\")\n url = \"https://mb-api.abuse.ch/api/v1/\"\n result = requests.post(url, data={\"query\": \"get_info\", \"hash\": value})\n if \"data\" in result.json() and len(result.json()[\"data\"]) > 0:\n result_json = result.json()[\"data\"][0]\n samples[key][\"malwarebazaar\"][\"markdown\"] = \"\"\n samples[key][\"malwarebazaar\"][\"data\"] = result_json\n samples[key][\"malwarebazaar\"][\"tags\"] = result_json.get(\"tags\", \"\")\n samples[key][\"malwarebazaar\"][\"signature\"] = result_json.get(\"signature\", \"\")\n\n if len(samples[key][\"malwarebazaar\"][\"tags\"]) > 0:\n samples[key][\"malwarebazaar\"][\"markdown\"] = \"{}\\n**Tags**\\n\".format(samples[key][\"malwarebazaar\"][\"markdown\"])\n for tag in samples[key][\"malwarebazaar\"][\"tags\"]:\n samples[key][\"malwarebazaar\"][\"markdown\"] = \"{}\\n - {}\\n\".format(samples[key][\"malwarebazaar\"][\"markdown\"], tag)\n\n if len(result_json.get(\"vendor_intel\", [])) > 0:\n if len(result_json.get(\"vendor_intel\", []).get(\"Triage\", [])) > 0:\n samples[key][\"malwarebazaar\"][\"markdown\"] = \"{}\\n**Triage tags and signatures**\\n\".format(samples[key][\"malwarebazaar\"][\"markdown\"])\n for tag in result_json.get(\"vendor_intel\", []).get(\"Triage\", []).get(\"tags\", []):\n samples[key][\"malwarebazaar\"][\"markdown\"] = \"{}\\n - {}\\n\".format(samples[key][\"malwarebazaar\"][\"markdown\"], tag)\n for signature in result_json.get(\"vendor_intel\", []).get(\"Triage\", []).get(\"signatures\", []):\n samples[key][\"malwarebazaar\"][\"markdown\"] = \"{}\\n - {}\\n\".format(samples[key][\"malwarebazaar\"][\"markdown\"], signature[\"signature\"])\n print(\" Finished query MalwareBazaar directly\")\n else:\n print(\"No results for \\033[91m{}\\033[90m.\".format(value))\nprint(\"Finished {}\".format(module_name))"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--c642b273-cfb6-42cc-aed5-00a8d6076e4c"
},
"action--c642b273-cfb6-42cc-aed5-00a8d6076e4c": {
"type": "action",
"name": "IN:5 PE imports and exports",
"description": "## IN:5 PE imports and exports\n\nNext we use `pefile` to analyse the **imports and exports**. The results are added as a **MISP report**.",
"commands": [
{
"type": "manual",
"command": "summary_pe = \"## PEFile summary\\n\\n\"\nprint(\"Using pefile\")\nfor key, sample in samples.items():\n summary_pe += \"## {}\\n\\n\".format(sample[\"path\"])\n\n try:\n pe = pefile.PE(sample[\"path\"])\n samples[key][\"pe\"][\"imports\"] = \"### Imports\\n\\n\"\n samples[key][\"pe\"][\"exports\"] = \"### Exports\\n\\n\"\n pe.parse_data_directories()\n\n print(\" Reading imports for {}\".format(sample[\"path\"]))\n try:\n for entry in pe.DIRECTORY_ENTRY_IMPORT:\n #print(\" {}\".format(entry.dll))\n samples[key][\"pe\"][\"imports\"] = \"{}\\n**{}**\\n\".format(samples[key][\"pe\"][\"imports\"], entry.dll)\n for imp in entry.imports:\n samples[key][\"pe\"][\"imports\"] = \"{}\\n - {} {}\\n\".format(samples[key][\"pe\"][\"imports\"], hex(imp.address), imp.name)\n except:\n print(\" No imports\")\n samples[key][\"pe\"][\"imports\"] = \"{}\\n *No imports*\\n\".format(samples[key][\"pe\"][\"imports\"])\n summary_pe += samples[key][\"pe\"][\"imports\"]\n\n print(\" Reading exports for {}\".format(sample[\"path\"]))\n try:\n for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:\n samples[key][\"pe\"][\"exports\"] = \"{}\\n - {} {} {}\\n\".format(samples[key][\"pe\"][\"exports\"], hex(pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name, exp.ordinal)\n except:\n print(\" No exports\")\n samples[key][\"pe\"][\"exports\"] = \"{}\\n *No exports*\\n\".format(samples[key][\"pe\"][\"exports\"])\n summary_pe += samples[key][\"pe\"][\"imports\"]\n except:\n print(\" \\033[91mPEFormatError\\033[90m for {}\\n\".format(sample[\"path\"]))\n summary_pe += \"\\n*PEFormatError*\\n\"\n\nevent_title = \"PEFile analysis\"\nprint(\"\\nCreating MISP report \\033[92m{}\\033[90m\".format(event_title))\nchunk_size = 61500\nfor i in range(0, len(summary_pe), chunk_size):\n chunk = summary_pe[i:i + chunk_size]\n event_report = MISPEventReport()\n event_title_edit = event_title\n if i > 0:\n event_title_edit = \"{} ({} > {})\".format(event_title, i, i + chunk_size)\n event_report.name = event_title_edit\n event_report.content = chunk\n result = misp.add_event_report(misp_event.id, event_report)\n if \"EventReport\" in result:\n print(\" Report ID: \\033[92m{}\\033[90m\".format(result.get(\"EventReport\", []).get(\"id\", 0)))\n else:\n print(\"Failed to create report for \\033[91m{}\\033[90m.\".format(event_title))"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--4f13756f-2808-440f-9188-850a8642fc37"
},
"action--4f13756f-2808-440f-9188-850a8642fc37": {
"type": "action",
"name": "IN:6 MISP report for investigation",
"description": "## IN:6 MISP report for investigation\n\nApart from the report on PE data, we also create a report on the previous investigation steps.",
"commands": [
{
"type": "manual",
"command": "summary_iv = \"## Investigation report\\n\\n\"\ncurrent_date = datetime.now()\nformatted_date = current_date.strftime(\"%Y-%m-%d\")\nfor key, sample in samples.items():\n summary_iv += \"## Analysis for {}\\n\".format(key)\n summary_iv += \"- Date: **{}**\\n\".format(formatted_date)\n summary_iv += \"- MISP event: **{}** ({})\\n\".format(misp_event.info, misp_event.id)\n summary_iv += \"### File details\\n\"\n summary_iv += \" - Path: {}\\n\".format(sample[\"path\"])\n summary_iv += \" - MD5: {}\\n\".format(sample[\"md5\"])\n summary_iv += \" - SHA256: {}\\n\".format(sample[\"sha256\"])\n summary_iv += \" - Entropy: {}\\n\".format(sample[\"entropy\"])\n summary_iv += \" - Mime-type: {}\\n\".format(sample[\"mimetype\"])\n summary_iv += \"### Risk\\n\"\n if sample.get(\"detection_ratio\", False):\n summary_iv += \" - Detection ratio: **{}**\\n\".format(sample[\"detection_ratio\"])\n summary_iv += \" - Detection ratio percentage: **{}**\\n\".format(sample[\"detection_ratio_perc\"])\n summary_iv += \" - Detection ratio indirect: {}\\n\".format(sample[\"detection_ratio_indirect\"])\n summary_iv += \" - Detection ratio indirect percentage: {}\\n\".format(sample[\"detection_ratio_indirect_perc\"])\n else:\n summary_iv += \"*No detection ratio found*\\n\\n\"\n if sample.get(\"risk_rating\", False):\n summary_iv += \" - Risk rating: **{}**\\n\".format(sample[\"risk_rating\"])\n summary_iv += \"### VirusTotal\\n\"\n if sample[\"vt\"].get(\"markdown\"):\n summary_iv += sample[\"vt\"][\"markdown\"]\n else:\n summary_iv += \"*No results*\\n\"\n summary_iv += \"\\n\\n\"\n summary_iv += \"### Hashlookup\\n\"\n if sample[\"hashlookup\"].get(\"markdown\"):\n summary_iv += sample[\"hashlookup\"][\"markdown\"]\n else:\n summary_iv += \"*No results*\\n\"\n summary_iv += \"\\n\\n\"\n summary_iv += \"### MalwareBazaar\\n\"\n if sample[\"malwarebazaar\"].get(\"markdown\"):\n summary_iv += sample[\"malwarebazaar\"][\"markdown\"]\n else:\n summary_iv += \"*No results*\\n\"\n summary_iv += \"\\n\\n\"\n\nevent_title = \"Malware analysis\"\nprint(\"Creating MISP report \\033[92m{}\\033[90m\".format(event_title))\nchunk_size = 61500\nfor i in range(0, len(summary_iv), chunk_size):\n chunk = summary_iv[i:i + chunk_size]\n event_report = MISPEventReport()\n event_title_edit = event_title\n if i > 0:\n event_title_edit = \"{} ({} > {})\".format(event_title, i, i + chunk_size)\n event_report.name = event_title_edit\n event_report.content = chunk\n result = misp.add_event_report(misp_event.id, event_report)\n if \"EventReport\" in result:\n print(\" Report ID: \\033[92m{}\\033[90m\".format(result.get(\"EventReport\", []).get(\"id\", 0)))\n else:\n print(\"Failed to create report for \\033[91m{}\\033[90m.\".format(event_title))"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--affc277a-00be-4c03-bc6c-0fb048352794"
},
"action--affc277a-00be-4c03-bc6c-0fb048352794": {
"type": "action",
"name": "CR:1 Correlation with MISP events",
"description": "# Correlation\n\n## CR:1 Correlation with MISP events\n\nThis cell searches the **MISP server** for events that have a match with the analysed samples.\n\nOnly **published** events (`correlation_published`) and attributes that have the **to_ids** flag (`correlation_to_ids`) set are take into account. There is a default limit of **1000 hits** (`correlation_limit`) and you can limit the search with tags (`correlation_match_tags`).",
"commands": [
{
"type": "manual",
"command": "# Only query for published MISP events\ncorrelation_published = False\n\n# Only consider those values that have the to_ids field set to True\ncorrelation_to_ids = True\n\n# Limit the returned results to 1000 attributes\ncorrelation_limit = 1000\n\n# Only return results corresponding with these tags\ncorrelation_match_tags = [\"tlp:amber\", \"tlp:white\"]\nprint(\"Search for correlating MISP events\")\n# Code block to query MISP and find the correlations\nfor key, sample in samples.items():\n value = [sample.get(\"sha256\"), sample.get(\"md5\")]\n search_match = misp.search(\"attributes\", to_ids=correlation_to_ids, value=value, tags=correlation_match_tags,\n published=correlation_published, limit=correlation_limit, pythonify=True)\n if len(search_match) > 0: \n for attribute in search_match:\n if attribute.Event.id != misp_event.id: # Skip the event we just created for this playbook\n print(\" Found \\033[92m{}\\033[90m in \\033[92m{}\\033[90m ({})\".format(attribute.value, attribute.Event.info, attribute.Event.id ))\n entry = {\"source\": \"MISP\", \"category\": attribute.category, \"type\": attribute.type, \"event_id\": attribute.Event.id, \"event_info\": attribute.Event.info}\n samples[key][\"MISP\"].append(entry)\nprint(\"Finished searching for correlations\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--795647c7-91ad-4e63-8a9e-0ce1c8ea089a"
},
"action--795647c7-91ad-4e63-8a9e-0ce1c8ea089a": {
"type": "action",
"name": "MISP events correlation table",
"description": "### MISP events correlation table\n\nThe correlation results are now stored in `samples`. Execute the next cell to display them in a table format. The table is also included in the summary sent to Mattermost and TheHive.",
"commands": [
{
"type": "manual",
"command": "# Put the correlations in a pretty table. We can use this table later also for the summary\ntable = PrettyTable()\ntable.field_names = [\"Source\", \"Value\", \"Category\", \"Type\", \"Event\", \"Event ID\"]\ntable.align[\"Value\"] = \"l\"\ntable.align[\"Category\"] = \"l\"\ntable.align[\"Type\"] = \"l\"\ntable.align[\"Event\"] = \"l\"\ntable.align[\"Event ID\"] = \"l\"\ntable._max_width = {\"Event\": 50}\nfor key, sample in samples.items():\n for match in sample[\"MISP\"]:\n table.add_row([match[\"source\"], key, match[\"category\"], match[\"type\"], match[\"event_info\"], match[\"event_id\"]])\nprint(table.get_string(sortby=\"Value\"))\ntable_mispevents = table"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--b54d8aa4-abda-43db-b2dd-dd6440ab9d2a"
},
"action--b54d8aa4-abda-43db-b2dd-dd6440ab9d2a": {
"type": "action",
"name": "CR:2 Correlation with MISP feeds",
"description": "## CR:2 Correlation with MISP feeds\n\nThis cell searches the **MISP feeds** for events that have a match with the analysed samples. The output of this cell is a table with all the matches. The output is also repeated at the end of the playbook.\n\nNote that the correlation lookup in the MISP feeds does not return the name of the MISP event, it returns the UUID of the event as title.",
"commands": [
{
"type": "manual",
"command": "print(\"Search in MISP feeds\")\nmisp_cache_url = \"{}/feeds/searchCaches/\".format(misp_url)\nmatch = False\nfor key, sample in samples.items():\n # Instead of GET, use POST (https://github.com/MISP/MISP/issues/7478)\n value = sample.get(\"sha256\")\n cache_results = requests.post(misp_cache_url, headers=misp_headers, verify=misp_verifycert, json={\"value\": value})\n for result in cache_results.json():\n if \"Feed\" in result:\n match = True\n print(\" Found \\033[92m{}\\033[90m in \\033[92m{}\\033[90m\".format(value, result[\"Feed\"][\"name\"]))\n for match in result[\"Feed\"][\"direct_urls\"]:\n entry = {\"source\": \"Feeds\", \"feed_name\": result[\"Feed\"][\"name\"], \"match_url\": match[\"url\"]}\n samples[key][\"Feeds\"].append(entry)\n\nprint(\"Finished searching in MISP feeds\")\nif not match:\n print(\"\\033[93mNo correlating information found in MISP feeds.\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--dd67e644-a1f0-4485-b551-ec61b19d8da7"
},
"action--dd67e644-a1f0-4485-b551-ec61b19d8da7": {
"type": "action",
"name": "MISP feed correlations table",
"description": "### MISP feed correlations table\n\nThe correlation results are now stored in `samples`. Execute the next cell to display them in a table format. The table is also included in the summary sent to Mattermost and TheHive.",
"commands": [
{
"type": "manual",
"command": "# Put the correlations in a pretty table. We can use this table later also for the summary\ntable = PrettyTable()\ntable.field_names = [\"Source\", \"Value\", \"Feed\", \"URL\"]\ntable.align[\"Value\"] = \"l\"\ntable.align[\"Feed\"] = \"l\"\ntable.align[\"Feed URL\"] = \"l\"\ntable._max_width = {\"Feed\": 50}\nfor key, sample in samples.items():\n for match in sample[\"Feeds\"]:\n table.add_row([match[\"source\"], key, match[\"feed_name\"], match[\"match_url\"]])\nprint(table.get_string(sortby=\"Value\"))\ntable_mispfeeds = table"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--ed98e018-ea5d-4acc-a292-875c9d3082ff"
},
"action--ed98e018-ea5d-4acc-a292-875c9d3082ff": {
"type": "action",
"name": "SA:1 Store in MWDB",
"description": "# Share the sample\n\n## SA:1 Store in MWDB\n\nThe Malware Repository MWDB, formerly known as Malwarecage, is a project from CERT.pl that is available as a service (via [MWDB-CERT.pl](https://mwdb.cert.pl/login) but you can also host its core component [MWDB](https://github.com/CERT-Polska/mwdb-core) on your own infrastructure. In this playbook there's the option to store the sample in your instance of MWDB. Future variants of the playbook include sharing the sample with well-known malware sandboxes.\n\nThere is a MISP module that allows to upload samples from MISP to MWDB, but in this case the playbook will interact directly with MWDB.",
"commands": [
{
"type": "manual",
"command": "mwdb_public = True\nmwdb_metakeys = False\nmwdb = MWDB(api_key=mwdb_apikey, api_url=mwdb_api_url)\nmwdb_tags = [\"misp\", \"playbook\"]\n\nsummary_mwdb = \"## Samples stored in MWDB\\n\"\nprint(\"Start sharing with MWDB\")\nfor key, sample in samples.items():\n sample_filename = key\n with open(sample[\"path\"], 'rb') as file:\n data = file.read()\n file_object = mwdb.upload_file(sample_filename, data, metakeys=mwdb_metakeys, public=mwdb_public)\n for tag in mwdb_tags:\n file_object.add_tag(tag)\n file_object.add_comment(\"Uploaded from MISP playbook for malware triage, via event {}\".format(misp_event.id))\n mwdb_link = \"{}{}\".format(mwdb_api_url.replace(\"/api\", \"/file/\"), file_object.md5)\n attribute = MISPAttribute()\n attribute.value = mwdb_link\n attribute.to_ids = False\n attribute.type = \"link\"\n attribute.disable_correlation = True\n attribute.comment = \"MWDB link for sample {}\".format(key)\n attribute_mwdb = misp.add_attribute(misp_event.uuid, attribute, pythonify=True)\n summary_mwdb += \" {} in [{}]({})\\n\".format(key, mwdb_link, mwdb_link)\n if not \"errors\" in attribute_mwdb:\n misp.add_object_reference(sample[\"fileobject\"].add_reference(attribute_mwdb.uuid, \"related-to\"))\n else:\n print(\" Unable to add attribute with link to MWDB to MISP\")\n print(\" Sample {} at \\033[92m{}\\033[90m\".format(key, mwdb_link))\nsummary_mwdb += \"\\n\"\nprint(\"Finished sharing\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--280b9d4b-4c55-41a3-b089-61122adfa43b"
},
"action--280b9d4b-4c55-41a3-b089-61122adfa43b": {
"type": "action",
"name": "EN:1 MISP indicators",
"description": "## EN:1 MISP indicators\n\nThe next section first **queries MISP for the indicators added to the MISP event** that is linked to the execution of this playbook.\n\nThe indicators are stored in the variable `indicator_table` (table format) and `indicator_raw_list` (in raw format) which is used in a later section to create the playbook summary.",
"commands": [
{
"type": "manual",
"command": "# Get all the indicators for our event and store this is in a table. We can also use this for the summary.\nindicator_search = misp.search(\"attributes\", uuid=misp_event.uuid, to_ids=True, pythonify=True)\nindicator_raw_list = []\nindicator_table = PrettyTable()\nif len(indicator_search) > 0:\n indicator_table.field_names = [\"Type\", \"Category\", \"Indicator\", \"Comment\"]\n indicator_table.align[\"Type\"] = \"l\"\n indicator_table.align[\"Category\"] = \"l\"\n indicator_table.align[\"Indicator\"] = \"l\"\n indicator_table.align[\"Comment\"] = \"l\"\n indicator_table.border = True\n for indicator in indicator_search:\n if indicator.value not in indicator_raw_list:\n comment = indicator.comment\n if hasattr(indicator, 'object_relation'):\n object_ind = misp.get_object(indicator.object_id, pythonify=True)\n comment = \"From '{}' object {} {}\".format(object_ind.name, object_ind.comment.lower(), comment.lower())\n indicator_table.add_row([indicator.type, indicator.category, indicator.value, comment])\n indicator_raw_list.append(indicator.value)\n print(\"Got \\033[92m{}\\033[90m indicator(s) from the event \\033[92m{}\\033[90m ({}).\\n\".format(len(indicator_raw_list), misp_event.info, misp_event.id))\nelse:\n print(\"\\033[93mNo indicators found in the event \\033[92m{}\\033[90m ({})\".format(misp_event.info, misp_event.id))"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--f1c3a54c-5906-4071-af9a-ffe96f03c463"
},
"action--f1c3a54c-5906-4071-af9a-ffe96f03c463": {
"type": "action",
"name": "Raw list of MISP indicators",
"description": "### Raw list of MISP indicators\n\nThe indicators are now stored in `indicator_search` (as Python objects) and `indicator_raw_list` (in raw format, only the indicators). Execute the next cell to display them in a table format. The table is also included in the summary sent to Mattermost and TheHive.",
"commands": [
{
"type": "manual",
"command": "if len(indicator_raw_list) > 0:\n print(indicator_table.get_string(sortby=\"Type\"))\n print(\"\\n\\nIndicator list in raw format:\")\n print(\"---------------------------------------------------\")\n for el in indicator_raw_list:\n print(\"{}\".format(el))\n print(\"---------------------------------------------------\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--0ff07d73-09ba-4bfe-a5f6-97038cae0ae6"
},
"action--0ff07d73-09ba-4bfe-a5f6-97038cae0ae6": {
"type": "action",
"name": "EN:2 Create the summary of the playbook",
"description": "## EN:2 Create the summary of the playbook\n\nThe next section creates a summary and stores the output in the variable `summary` in Markdown format. It also stores an intro text in the variable `intro`. These variables are later used when sending information to Mattermost or TheHive.",
"commands": [
{
"type": "manual",
"command": "summary = \"# MISP Playbook summary\\nMalware triage with MISP event: **{}** ({}/events/view/{}). \".format(misp_event.info, misp_url, misp_event.id)\n\nsummary += \"\\n\"\nsummary += summary_iv\nsummary += \"\\n\"\nintro = summary\n\nsummary += \"## Indicators\\n\\n\"\nsummary += \"### Indicators table\\n\\n\"\nif len(indicator_raw_list) > 0:\n indicator_table.set_style(MARKDOWN)\n summary += indicator_table.get_string(sortby=\"Type\")\n summary += \"\\n\\n\\n\" \n summary += \"### Indicators in **raw format**\\n\\n\"\n for indicator in indicator_raw_list:\n summary += \"{}\\n\\n\".format(indicator)\n summary += \"\\n\" \nelse:\n summary += \"There are no indicators\"\nsummary += \"\\n\\n\"\n\nsummary += \"## Correlations\\n\\n\"\nsummary += \"### MISP event matches\\n\\n\"\ntable_mispevents.set_style(MARKDOWN)\nsummary += table_mispevents.get_string()\nsummary += \"\\n\\n\"\n\nsummary += \"### MISP feed matches\\n\\n\"\ntable_mispfeeds.set_style(MARKDOWN)\nsummary += table_mispfeeds.get_string()\nsummary += \"\\n\\n\"\n\nsummary += summary_pe\n\nsummary += \"\\n\\n\"\n\nprint(\"The \\033[92msummary\\033[90m of the playbook is available.\\n\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--077c63d0-d508-4521-a137-d85e02977f20"
},
"action--077c63d0-d508-4521-a137-d85e02977f20": {
"type": "action",
"name": "EN:3 Print the input for malware triage",
"description": "## EN:3 Print the input for malware triage\n\nApart from the full summary of the investigation, the malware triage summary provides the necessary input for the analyst. This summary was previously also added as a MISP report.",
"commands": [
{
"type": "manual",
"command": "print(summary_iv)\n# Or print with parsed markdown\n# display_markdown(summary_iv, raw=True)"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--56946bb4-7f77-46c5-9418-2fb8c79a4e0d"
},
"action--56946bb4-7f77-46c5-9418-2fb8c79a4e0d": {
"type": "action",
"name": "EN:4 Send a summary to Mattermost",
"description": "## EN:4 Send a summary to Mattermost\n\nNow you can send the summary to Mattermost. You can send the summary in two ways by selecting one of the options for the variable `send_to_mattermost_option` in the next cell.\n\n- The default option where the entire summary is in the **chat**, or\n- a short intro and the summary in a **card**\n\nFor this playbook we rely on a webhook in Mattermost. You can add a webhook by choosing the gear icon in Mattermost, then choose Integrations and then **Incoming Webhooks**. Set a channel for the webhook and lock the webhook to this channel with *\"Lock to this channel\"*.",
"commands": [
{
"type": "manual",
"command": "send_to_mattermost_option = \"via a chat message\"\n#send_to_mattermost_option = \"via a chat message with card\"\nmessage = False\nif send_to_mattermost_option == \"via a chat message\":\n message = {\"username\": mattermost_playbook_user, \"text\": summary}\nelif send_to_mattermost_option == \"via a chat message with card\":\n message = {\"username\": mattermost_playbook_user, \"text\": intro, \"props\": {\"card\": summary}}\n\nif message:\n r = requests.post(mattermost_hook, data=json.dumps(message))\n r.raise_for_status()\nif message and r.status_code == 200:\n print(\"Summary is \\033[92msent to Mattermost.\\n\")\nelse:\n print(\"\\033[91mFailed to sent summary\\033[90m to Mattermost.\\n\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--86141b38-8865-4f63-ae9b-f551314c2ba9"
},
"action--86141b38-8865-4f63-ae9b-f551314c2ba9": {
"type": "action",
"name": "EN:5 End of the playbook",
"description": "## EN:5 End of the playbook",
"commands": [
{
"type": "manual",
"command": "print(\"\\033[92m End of the playbook\")"
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "action--9f384216-61d0-4d16-aa6a-1f393092c870"
},
"action--9f384216-61d0-4d16-aa6a-1f393092c870": {
"type": "action",
"name": "MISP Playbook",
"description": "Copy of the MISP Playbook",
"commands": [
{
"type": "jupyter",
"command_b64": "ewogImNlbGxzIjogWwogIHsKICAgImNlbGxfdHlwZSI6ICJtYXJrZG93biIsCiAgICJpZCI6ICJjYTFmYmZiNSIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogWwogICAgICJwbGF5Ym9vay1pbnRyb2R1Y3Rpb24iCiAgICBdCiAgIH0sCiAgICJzb3VyY2UiOiBbCiAgICAiIyBNYWx3YXJlIHRyaWFnZSB3aXRoIE1JU1BcbiIsCiAgICAiXG4iLAogICAgIiMjIEludHJvZHVjdGlvblxuIiwKICAgICJcbiIsCiAgICAiLSBVVUlEOiAqKjY4YjQyZjRkLThkNWUtNDZjNC05N2Y4LWI4N2I5ZGYyMTBhMyoqXG4iLAogICAgIi0gU3RhcnRlZCBmcm9tIFtpc3N1ZSAyXShodHRwczovL2dpdGh1Yi5jb20vTUlTUC9taXNwLXBsYXlib29rcy9pc3N1ZXMvMilcbiIsCiAgICAiLSBTdGF0ZTogKipQdWJsaXNoZWQqKlxuIiwKICAgICItIFB1cnBvc2U6IEEgcGxheWJvb2sgdG8gcHJvdmlkZSBhbiBhbmFseXN0IHN1ZmZpY2llbnQgaW5mb3JtYXRpb24gdG8gZG8gYmFzaWMgbWFsd2FyZSB0cmlhZ2Ugb24gb25lIG9yIG1vcmUgc2FtcGxlcy5cbiIsCiAgICAiICAgIC0gVGhpcyBwbGF5Ym9vayBjcmVhdGVzIGEgKipNSVNQIGV2ZW50KiogZm9yIG1hbHdhcmUgdHJpYWdlLiBcbiIsCiAgICAiICAgIC0gU2FtcGxlcyBhcmUgKiphdHRhY2hlZCoqIHRvIGEgTUlTUCBldmVudCAod2l0aCBmaWxlIG9iamVjdCByZWxhdGlvbnMpLlxuIiwKICAgICIgICAgLSBWaXJ1c1RvdGFsIGFuZCBNYWx3YXJlQmF6YWFyIGFyZSB1c2VkIHRvIGdldCB0aGUgKipkZXRlY3Rpb24gcmF0ZSoqLCAqKnRocmVhdCBjbGFzc2lmaWNhdGlvbioqIGFuZCAqKnNhbmRib3gqKiBpbmZvcm1hdGlvbi5cbiIsCiAgICAiICAgIC0gSGFzaGxvb2t1cCBpcyB1c2VkIHRvIGNoZWNrIGZvciAqKmtub3duIGhhc2hlcyoqLlxuIiwKICAgICIgICAgLSBQRWZpbGUgYW5hbHlzaXMgaXMgZG9uZSBmb3IgKippbXBvcnRzKiogYW5kICoqZXhwb3J0cyoqLlxuIiwKICAgICIgICAgLSBUaGUgcmVzdWx0cyBhcmUgc3RvcmVkIGluICoqTUlTUCByZXBvcnRzKiogYW5kIGFzIE1JU1Agb2JqZWN0cyB3aGVyZSByZWxldmFudC5cbiIsCiAgICAiICAgIC0gQ29ycmVsYXRpb25zIHdpdGggTUlTUCBldmVudHMgb3IgZGF0YSBmZWVkcyBhcmUgYWRkZWQgdG8gYSBzdW1tYXJ5LlxuIiwKICAgICIgICAgLSBUaGUgc2FtcGxlIGlzIHNoYXJlZCB3aXRoIGEgbG9jYWwgaW5zdGFuY2Ugb2YgKipNV0RCY29yZSoqLlxuIiwKICAgICIgICAgLSBUaGUgc3VtbWFyeSBpcyB0aGVuIHNlbnQgdG8gTWF0dGVybW9zdC5cbiIsCiAgICAiLSBUYWdzOiBbIFwibWFsd2FyZVwiLCBcInRyaWFnZVwiLCBcImluY2lkZW50cmVzcG9uc2VcIiwgXCJpclwiLCBcImRmaXJcIiBdXG4iLAogICAgIi0gRXh0ZXJuYWwgcmVzb3VyY2VzOiAqKlZpcnVzVG90YWwsIEhhc2hsb29rdXAsIE1hbHdhcmVCYXphYXIsIE1XREIsIE1hdHRlcm1vc3QqKlxuIiwKICAgICItIFRhcmdldCBhdWRpZW5jZTogKipTT0MqKiwgKipDU0lSVCoqLCAqKkNUSSoqXG4iLAogICAgIi0gTm90ZXM6XG4iLAogICAgIiAgICAtIFNhbXBsZXMgYXJlIHN0b3JlZCBpbiBhIFwibWFsd2FyZXpvb1wiLCBkZWZpbmVkIGluIHRoZSB2YXJpYWJsZSBgbWFsd2FyZXpvb2AuXG4iLAogICAgIiAgICAtIEFsbCBzYW1wbGVzIHRoYXQgZG8gbm90IGhhdmUgYW4gZXh0ZW5zaW9uIFwiZG8tbm90LXJ1blwiIChzZXQgaW4gYGRlZmFuZ3N1ZmZpeGApIGFyZSBjb25zaWRlcmVkIGFzIHVucHJvY2Vzc2VkLlxuIiwKICAgICIgICAgLSBUaGUgcGxheWJvb2sgYWRkcyB0aGUgZGVmYW5nc3VmZml4IHdoZW4gaXQgcHJvY2Vzc2VzIHRoZSBzYW1wbGVzLlxuIiwKICAgICIgICAgLSBGb3IgVmlydXNUb3RhbCBhbmQgTWFsd2FyZUJhemFhciwgYm90aCB0aGUgTUlTUCBtb2R1bGVzIGFzIHdlbGwgYXMgZGlyZWN0IHF1ZXJpZXMgdG8gVlQvTUIgYXJlIHVzZWQuIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiYTUxMmEyYzEiLAogICAibWV0YWRhdGEiOiB7CiAgICAianAtTWFya2Rvd25IZWFkaW5nQ29sbGFwc2VkIjogdHJ1ZSwKICAgICJ0YWdzIjogW10KICAgfSwKICAgInNvdXJjZSI6IFsKICAgICIjIFBsYXlib29rXG4iLAogICAgIlxuIiwKICAgICItICoqUGxheWJvb2sgdGl0bGUqKlxuIiwKICAgICItIC0gSW50cm9kdWN0aW9uXG4iLAogICAgIi0gKipQcmVwYXJhdGlvbioqXG4iLAogICAgIiAgICAtIFBSOjEgSW5pdGlhbGlzZSBlbnZpcm9ubWVudFxuIiwKICAgICIgICAgLSBQUjoyIFZlcmlmeSBNSVNQIG1vZHVsZXNcbiIsCiAgICAiICAgIC0gUFI6MyBMb2FkIGhlbHBlciBmdW5jdGlvbnNcbiIsCiAgICAiICAgIC0gUFI6NCBTZXQgaGVscGVyIHZhcmlhYmxlc1xuIiwKICAgICIgICAgLSBQNTo1IExvYWQgYW5kIGRlZmFuZyBzYW1wbGVzXG4iLAogICAgIiAgICAtIFBSOjYgTUlTUCBldmVudCBkZXRhaWxzXG4iLAogICAgIiAgICAtIFBSOjcgU2V0dXAgTUlTUCBldmVudCBsaW5rXG4iLAogICAgIi0gKipJbnZlc3RpZ2F0ZSoqXG4iLAogICAgIiAgICAtIElOOjEgRmlsZSBhbmFseXNpc1xuIiwKICAgICIgICAgLSBJTjoyIFZpcnVzVG90YWwgcmVzdWx0c1xuIiwKICAgICIgICAgLSBJTjozIEhhc2hsb29rdXBcbiIsCiAgICAiICAgIC0gSU46NCBNYWx3YXJlQmF6YWFyXG4iLAogICAgIiAgICAtIElOOjUgUEUgaW1wb3J0cyBhbmQgZXhwb3J0c1xuIiwKICAgICIgICAgLSBJTjo2IE1JU1AgcmVwb3J0IGZvciBpbnZlc3RpZ2F0aW9uXG4iLAogICAgIi0gKipDb3JyZWxhdGlvbioqXG4iLAogICAgIiAgICAtIENSOjEgQ29ycmVsYXRpb24gd2l0aCBNSVNQIGV2ZW50c1xuIiwKICAgICIgICAgLSBDUjoyIENvcnJlbGF0aW9uIHdpdGggTUlTUCBmZWVkc1xuIiwKICAgICItICoqU2hhcmUgdGhlIHNhbXBsZSoqXG4iLAogICAgIiAgICAtIFNBOjEgU3RvcmUgaW4gTVdEQlxuIiwKICAgICItICoqU3VtbWFyeSoqXG4iLAogICAgIiAgICAtIEVOOjEgTUlTUCBpbmRpY2F0b3JzXG4iLAogICAgIiAgICAtIEVOOjIgQ3JlYXRlIHRoZSBzdW1tYXJ5IG9mIHRoZSBwbGF5Ym9va1xuIiwKICAgICIgICAgLSBFTjozIFByaW50IHRoZSBpbnB1dCBmb3IgbWFsd2FyZSB0cmlhZ2VcbiIsCiAgICAiICAgIC0gRU46NCBTZW5kIGEgc3VtbWFyeSB0byBNYXR0ZXJtb3N0XG4iLAogICAgIiAgICAtIEVOOjUgRW5kIG9mIHRoZSBwbGF5Ym9va1xuIiwKICAgICIgICAgLSBFeHRlcm5hbCByZWZlcmVuY2VzXG4iLAogICAgIiAgICAtIFRlY2huaWNhbCBkZXRhaWxzIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiOGRjMjQ5MTMiLAogICAibWV0YWRhdGEiOiB7CiAgICAidGFncyI6IFtdCiAgIH0sCiAgICJzb3VyY2UiOiBbCiAgICAiIyBQcmVwYXJhdGlvblxuIiwKICAgICJcbiIsCiAgICAiIyMgUFI6MSBJbml0aWFsaXNlIGVudmlyb25tZW50XG4iLAogICAgIlxuIiwKICAgICJUaGlzIHNlY3Rpb24gKippbml0aWFsaXNlcyB0aGUgcGxheWJvb2sgZW52aXJvbm1lbnQqKiBhbmQgbG9hZHMgdGhlIHJlcXVpcmVkIFB5dGhvbiBsaWJyYXJpZXMuIFxuIiwKICAgICJcbiIsCiAgICAiVGhlIGNyZWRlbnRpYWxzIGZvciBNSVNQICgqKkFQSSBrZXkqKikgYW5kIG90aGVyIHNlcnZpY2VzIGFyZSBsb2FkZWQgZnJvbSB0aGUgZmlsZSBga2V5cy5weWAgaW4gdGhlIGRpcmVjdG9yeSAqKnZhdWx0KiouIEEgW1B5TUlTUF0oaHR0cHM6Ly9naXRodWIuY29tL01JU1AvUHlNSVNQKSBvYmplY3QgaXMgY3JlYXRlZCB0byBpbnRlcmFjdCB3aXRoIE1JU1AgYW5kIHRoZSBhY3RpdmUgTUlTUCBzZXJ2ZXIgaXMgZGlzcGxheWVkLiBCeSBwcmludGluZyBvdXQgdGhlIHNlcnZlciBuYW1lIHlvdSBrbm93IHRoYXQgaXQncyBwb3NzaWJsZSB0byBjb25uZWN0IHRvIE1JU1AuIEluIGNhc2Ugb2YgYSBwcm9ibGVtIFB5TUlTUCB3aWxsIGluZGljYXRlIHRoZSBlcnJvciB3aXRoIGBQeU1JU1BFcnJvcjogVW5hYmxlIHRvIGNvbm5lY3QgdG8gTUlTUGAuXG4iLAogICAgIlxuIiwKICAgICJUaGUgY29udGVudHMgb2YgdGhlIGBrZXlzLnB5YCBmaWxlIHNob3VsZCBjb250YWluIGF0IGxlYXN0IDpcbiIsCiAgICAiXG4iLAogICAgImBgYFxuIiwKICAgICJtaXNwX3VybD1cIjxNSVNQIFVSTD5cIiAgICAgICAgICAgICAgICAgICMgVGhlIFVSTCB0byBvdXIgTUlTUCBzZXJ2ZXJcbiIsCiAgICAibWlzcF9rZXk9XCI8TUlTUCBBUEkgS0VZPlwiICAgICAgICAgICAgICAjIFRoZSBNSVNQIEFQSSBrZXlcbiIsCiAgICAibWlzcF92ZXJpZnljZXJ0PTxUcnVlIG9yIEZhbHNlPiAgICAgICAgIyBJbmRpY2F0ZSBpZiBQeU1JU1Agc2hvdWxkIGF0dGVtcHQgdG8gdmVyaWZ5IHRoZSBjZXJ0aWZpY2F0ZSBvciBpZ25vcmUgZXJyb3JzXG4iLAogICAgImBgYCIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjVmOTRjMzM2IiwKICAgIm1ldGFkYXRhIjogewogICAgInRhZ3MiOiBbXQogICB9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogWwogICAgIiMgSW5pdGlhbGlzZSBQeXRob24gZW52aXJvbm1lbnRcbiIsCiAgICAiaW1wb3J0IHVybGxpYjNcbiIsCiAgICAiaW1wb3J0IHN5c1xuIiwKICAgICJpbXBvcnQganNvblxuIiwKICAgICJmcm9tIHB5ZmF1cC5mYXVwIGltcG9ydCBGYXVwXG4iLAogICAgImZyb20gcHJldHR5dGFibGUgaW1wb3J0IFByZXR0eVRhYmxlLCBNQVJLRE9XTlxuIiwKICAgICJmcm9tIElQeXRob24uZGlzcGxheSBpbXBvcnQgSW1hZ2UsIGRpc3BsYXksIGRpc3BsYXlfbWFya2Rvd24sIEhUTUxcbiIsCiAgICAiZnJvbSBkYXRldGltZSBpbXBvcnQgZGF0ZVxuIiwKICAgICJpbXBvcnQgcmVxdWVzdHNcbiIsCiAgICAiaW1wb3J0IHV1aWRcbiIsCiAgICAiI2Zyb20gdXVpZCBpbXBvcnQgdXVpZDRcbiIsCiAgICAiZnJvbSBweW1pc3AgaW1wb3J0ICpcbiIsCiAgICAiZnJvbSBweW1pc3AudG9vbHMgaW1wb3J0IEdlbmVyaWNPYmplY3RHZW5lcmF0b3JcbiIsCiAgICAiZnJvbSBweW1pc3AudG9vbHMgaW1wb3J0IG1ha2VfYmluYXJ5X29iamVjdHNcbiIsCiAgICAiaW1wb3J0IGxvZ2dpbmdcbiIsCiAgICAiXG4iLAogICAgImltcG9ydCBvc1xuIiwKICAgICJpbXBvcnQgdGltZVxuIiwKICAgICJpbXBvcnQgcGVmaWxlXG4iLAogICAgImZyb20gZGF0ZXRpbWUgaW1wb3J0IGRhdGV0aW1lXG4iLAogICAgImZyb20gbXdkYmxpYiBpbXBvcnQgTVdEQlxuIiwKICAgICJcbiIsCiAgICAiIyBMb2FkIHRoZSBjcmVkZW50aWFsc1xuIiwKICAgICJzeXMucGF0aC5pbnNlcnQoMCwgXCIuLi92YXVsdC9cIilcbiIsCiAgICAiZnJvbSBrZXlzIGltcG9ydCAqXG4iLAogICAgImlmIG1pc3BfdmVyaWZ5Y2VydCBpcyBGYWxzZTpcbiIsCiAgICAiICAgIGltcG9ydCB1cmxsaWIzXG4iLAogICAgIiAgICB1cmxsaWIzLmRpc2FibGVfd2FybmluZ3ModXJsbGliMy5leGNlcHRpb25zLkluc2VjdXJlUmVxdWVzdFdhcm5pbmcpXG4iLAogICAgInByaW50KFwiVGhlIFxcMDMzWzkybVB5dGhvbiBsaWJyYXJpZXNcXDAzM1s5MG0gYXJlIGxvYWRlZCBhbmQgdGhlIFxcMDMzWzkybWNyZWRlbnRpYWxzXFwwMzNbOTBtIGFyZSByZWFkIGZyb20gdGhlIGtleXMgZmlsZS5cIilcbiIsCiAgICAiXG4iLAogICAgIiMgQ3JlYXRlIHRoZSBQeU1JU1Agb2JqZWN0XG4iLAogICAgIm1pc3AgPSBQeU1JU1AobWlzcF91cmwsIG1pc3Bfa2V5LCBtaXNwX3ZlcmlmeWNlcnQpXG4iLAogICAgInByaW50KFwiSSB3aWxsIHVzZSB0aGUgTUlTUCBzZXJ2ZXIgXFwwMzNbOTJte31cXDAzM1s5MG0gZm9yIHRoaXMgcGxheWJvb2suXFxuXFxuXCIuZm9ybWF0KG1pc3BfdXJsKSlcbiIsCiAgICAiXG4iLAogICAgIiMgQ3JlYXRlIGhlYWRlcnMgZm9yIHNwZWNpZmljIGNhc2VzXG4iLAogICAgIm1pc3BfaGVhZGVycyA9IHtcIkF1dGhvcml6YXRpb25cIjogbWlzcF9rZXksICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIiwgXCJBY2NlcHRcIjogXCJhcHBsaWNhdGlvbi9qc29uXCJ9IgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiMzQyY2IwMjctNWNhNi00ZTAxLWI1M2QtMTYyNWZmYzk1MzFmIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgUFI6MiBWZXJpZnkgTUlTUCBtb2R1bGVzXG4iLAogICAgIlxuIiwKICAgICJUaGlzIHBsYXlib29rIHVzZXMgdGhlIE1JU1AgbW9kdWxlcyB0byBvYnRhaW4gYWRkaXRpb25hbCBjb3JyZWxhdGlvbiBvciBlbnJpY2htZW50IGluZm9ybWF0aW9uLiBbTUlTUCBtb2R1bGVzXShodHRwczovL2dpdGh1Yi5jb20vTUlTUC9taXNwLW1vZHVsZXMpIGFyZSBhdXRvbm9tb3VzIG1vZHVsZXMgdGhhdCBjYW4gYmUgdXNlZCB0byBleHRlbmQgTUlTUCBmb3IgbmV3IHNlcnZpY2VzIHN1Y2ggYXMgZXhwYW5zaW9uLCBpbXBvcnQgYW5kIGV4cG9ydC4gVGhlIG1vZHVsZXMgYXJlIHdyaXR0ZW4gaW4gUHl0aG9uIDMgZm9sbG93aW5nIGEgc2ltcGxlIEFQSSBpbnRlcmZhY2UuIFRoZSBvYmplY3RpdmUgaXMgdG8gZWFzZSB0aGUgZXh0ZW5zaW9ucyBvZiBNSVNQIGZ1bmN0aW9uYWxpdGllcyB3aXRob3V0IG1vZGlmeWluZyBjb3JlIGNvbXBvbmVudHMuIFRoZSBBUEkgaXMgYXZhaWxhYmxlIHZpYSBhIHNpbXBsZSBSRVNUIEFQSSB3aGljaCBpcyBpbmRlcGVuZGVudCBmcm9tIE1JU1AgaW5zdGFsbGF0aW9uIG9yIGNvbmZpZ3VyYXRpb24uXG4iLAogICAgIlxuIiwKICAgICJJbiB0aGUgbmV4dCBjZWxsIHdlIGNoZWNrIGlmIHdlIGhhdmUgYWNjZXNzIHRvIHRoZSAqKk1JU1AgbW9kdWxlKiogc2VydmVyIGFuZCBpZiB0aGUgcmVxdWlyZWQgbW9kdWxlcyBhcmUgZW5hYmxlZC4iCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJjb2RlIiwKICAgImV4ZWN1dGlvbl9jb3VudCI6IG51bGwsCiAgICJpZCI6ICIyMDk1MzEwMy0yZGFiLTQzYzctYjQyMy0zOWQ5YmRjOWFlMTciLAogICAibWV0YWRhdGEiOiB7CiAgICAidGFncyI6IFtdCiAgIH0sCiAgICJvdXRwdXRzIjogW10sCiAgICJzb3VyY2UiOiBbCiAgICAiIyBXaGVyZSBjYW4gd2UgZmluZCB0aGUgbG9jYWwgTUlTUCBNb2R1bGUgc2VydmVyPyBZb3UgY2FuIGxlYXZlIHRoaXMgdG8gdGhlIGRlZmF1bHQgc2V0dGluZyBpbiBtb3N0IGNhc2VzLlxuIiwKICAgICJtaXNwX21vZHVsZXNfdXJsID0gXCJodHRwOi8vMTI3LjAuMC4xOjY2NjZcIlxuIiwKICAgICJcbiIsCiAgICAiIyBIb3cgbG9uZyBkbyB3ZSB3YWl0IGJldHdlZW4gcXVlcmllcyB3aGVuIHVzaW5nIHRoZSBNSVNQIG1vZHVsZXMgKEFQSSByYXRlIGxpbWl0aW5nIG9mIGV4dGVybmFsIHNlcnZpY2Ugc3VjaCBhcyBWaXJ1c1RvdGFsKVxuIiwKICAgICJtaXNwX21vZHVsZXNfd2FpdCA9IDNcbiIsCiAgICAiXG4iLAogICAgIiMgSW5pdGlsaWFzYXRpb25cbiIsCiAgICAibWlzcF9tb2R1bGVzID0ge31cbiIsCiAgICAibWlzcF9tb2R1bGVzX2hlYWRlcnMgPSB7XG4iLAogICAgIiAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiIsCiAgICAiICAgIFwiQWNjZXB0XCI6IFwiYXBwbGljYXRpb24vanNvblwiXG4iLAogICAgIn1cbiIsCiAgICAibWlzcF9tb2R1bGVzX2luX3VzZSA9IFtcImhhc2hsb29rdXBcIiwgXCJ2aXJ1c3RvdGFsX3B1YmxpY1wiLCBcIm1hbHdhcmViYXphYXJcIl1cbiIsCiAgICAiIyBDb2RlIGJsb2NrIHRvIHF1ZXJ5IHRoZSBNSVNQIG1vZHVsZSBzZXJ2ZXIgYW5kIGNoZWNrIGlmIG91ciBtb2R1bGVzIGFyZSBlbmFibGVkXG4iLAogICAgInJlcyA9IHJlcXVlc3RzLmdldChcInt9L21vZHVsZXNcIi5mb3JtYXQobWlzcF9tb2R1bGVzX3VybCksIGhlYWRlcnM9bWlzcF9tb2R1bGVzX2hlYWRlcnMpXG4iLAogICAgImZvciBtb2R1bGUgaW4gcmVzLmpzb24oKTpcbiIsCiAgICAiICAgIGZvciBtb2R1bGVfcmVxdWVzdGVkIGluIG1pc3BfbW9kdWxlc19pbl91c2U6XG4iLAogICAgIiAgICAgICAgaWYgbW9kdWxlLmdldChcIm5hbWVcIiwgRmFsc2UpID09IG1vZHVsZV9yZXF1ZXN0ZWQ6XG4iLAogICAgIiAgICAgICAgICAgIG1pc3BfbW9kdWxlc1ttb2R1bGVfcmVxdWVzdGVkXSA9IHtcImVuYWJsZWRcIjogVHJ1ZSwgXCJpbnB1dFwiOiBtb2R1bGUuZ2V0KFwibWlzcGF0dHJpYnV0ZXNcIikuZ2V0KFwiaW5wdXRcIil9XG4iLAogICAgIiAgICAgICAgICAgIHByaW50KFwiRm91bmQgdGhlIFxcMDMzWzkybXt9XFwwMzNbOTBtIE1JU1AgbW9kdWxlIChBY2NlcHRlZCBpbnB1dDoge30pLlwiLmZvcm1hdChtb2R1bGVfcmVxdWVzdGVkLCBtaXNwX21vZHVsZXNbbW9kdWxlX3JlcXVlc3RlZF1bXCJpbnB1dFwiXSkpXG4iLAogICAgInByaW50KFwiXFxuXCIpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiODQwZTdmYzEtOGIyMS00MDA1LWJmN2MtOWNjZDY1YTdkMTY2IiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgUFI6MyBMb2FkIGhlbHBlciBmdW5jdGlvbnNcbiIsCiAgICAiXG4iLAogICAgIlRoZSBuZXh0IGNlbGwgY29udGFpbnMgKipoZWxwZXIgZnVuY3Rpb25zKiogdGhhdCBhcmUgdXNlZCBpbiB0aGlzIHBsYXlib29rLiBcbiIsCiAgICAiXG4iLAogICAgIkluc3RlYWQgb2YgZGlzdHJpYnV0aW5nIGhlbHBlciBmdW5jdGlvbnMgYXMgc2VwYXJhdGUgUHl0aG9uIGZpbGVzIHRoaXMgcGxheWJvb2sgaW5jbHVkZXMgYWxsIHRoZSByZXF1aXJlZCBjb2RlIGFzIG9uZSBjb2RlIGNlbGwuIFRoaXMgbWFrZXMgcG9ydGFiaWxpdHkgb2YgcGxheWJvb2tzIGJldHdlZW4gaW5zdGFuY2VzIGVhc2llci4gVGhlIGRvd25zaWRlIGlzIHRoYXQgZnVuY3Rpb25zIGRlZmluZWQgaW4gdGhpcyBwbGF5Ym9vayBuZWVkIHRvIGJlIGRlZmluZWQgYWdhaW4gaW4gb3RoZXIgcGxheWJvb2tzLCB3aGljaCBpcyBub3Qgb3B0aW1hbCBmb3IgY29kZSByZS11c2UuIEZvciB0aGlzIGl0ZXJhdGlvbiBvZiBwbGF5Ym9va3MgaXQgaXMgY2hvc2VuIHRvIGluY2x1ZGUgdGhlIGNvZGUgaW4gdGhlIHBsYXlib29rIChtb3JlIHBvcnRhYmlsaXR5KSwgYnV0IHlvdSBjYW4gZWFzaWx5IGNyZWF0ZSBvbmUgXCJoZWxwZXJcIiBmaWxlIHRoYXQgY29udGFpbnMgYWxsIHRoZSBoZWxwZXIgY29kZSBhbmQgdGhlbiBpbXBvcnQgdGhhdCBmaWxlIGluIGVhY2ggcGxheWJvb2sgKGZvciBleGFtcGxlIGJ5IGFkZGluZyB0byB0aGUgcHJldmlvdXMgY2VsbCBgZnJvbSBoZWxwZXJzIGltcG9ydCAqYCkuIE5vdGUgdGhhdCB0aGUgZ3JhcGhpY2FsIHdvcmtmbG93IGltYWdlIGlzIGluY2x1ZGVkIGFzIGFuIGV4dGVybmFsIGltYWdlLiBBIG1pc3NpbmcgaW1hZ2Ugd291bGQgbm90IGluZmx1ZW5jZSB0aGUgZnVydGhlciBwcm9ncmVzcyBvZiB0aGUgcGxheWJvb2suIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAiY29kZSIsCiAgICJleGVjdXRpb25fY291bnQiOiBudWxsLAogICAiaWQiOiAiZTAxNTk0NGQtZWY0Zi00ZTM3LThlYzMtYjAxOTUwZjZlZTc2IiwKICAgIm1ldGFkYXRhIjogewogICAgInRhZ3MiOiBbXQogICB9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogWwogICAgImRlZiBwYl9nZXRfbWlzcF90YWdzKHRhZ3M9W10sIGxvY2FsX3RhZ3M9W10pOlxuIiwKICAgICIgICAgJycnXG4iLAogICAgIiAgICBHZXQgYSBsaXN0IG9mIE1JU1AgdGFncyBiYXNlZCBvbiBhIFB5dGhvbiBsaXN0XG4iLAogICAgIlxuIiwKICAgICIgICAgOnBhcmFtIG1pc3A6IE1JU1Agb2JqZWN0XG4iLAogICAgIiAgICA6cGFyYW0gb2JqZWN0X3RlbXBsYXRlOiB3aGljaCBvYmplY3QgdGVtcGxhdGUgdG8gcmV0dXJuXG4iLAogICAgIiAgICAnJydcbiIsCiAgICAiICAgIG1pc3BfdGFncyA9IFtdXG4iLAogICAgIiAgICBmb3IgZWwgaW4gdGFnczpcbiIsCiAgICAiICAgICAgICB0ID0gTUlTUFRhZygpXG4iLAogICAgIiAgICAgICAgdC5uYW1lID0gZWxcbiIsCiAgICAiICAgICAgICB0LmxvY2FsID0gRmFsc2VcbiIsCiAgICAiICAgICAgICBtaXNwX3RhZ3MuYXBwZW5kKHQpXG4iLAogICAgIlxuIiwKICAgICIgICAgZm9yIGVsIGluIGxvY2FsX3RhZ3M6XG4iLAogICAgIiAgICAgICAgdCA9IE1JU1BUYWcoKVxuIiwKICAgICIgICAgICAgIHQubmFtZSA9IGVsXG4iLAogICAgIiAgICAgICAgdC5sb2NhbCA9IFRydWVcbiIsCiAgICAiICAgICAgICBtaXNwX3RhZ3MuYXBwZW5kKHQpXG4iLAogICAgIiAgICByZXR1cm4gbWlzcF90YWdzXG4iLAogICAgIlxuIiwKICAgICJcbiIsCiAgICAiZGVmIGNhbGN1bGF0ZV9yaXNrX3Njb3JlKHJhdGlvKTpcbiIsCiAgICAiICAgICcnJ1xuIiwKICAgICIgICAgQ2FsY3VsYXRlIHJpc2sgc2NvcmUgYW5kIHJldHVybiB0aGUgc2NvcmUgYW5kIGEgdGFnXG4iLAogICAgIiAgICAnJydcbiIsCiAgICAiICAgIGRldGVjdGlvbl9yYXRpb19wZXJjID0gMFxuIiwKICAgICIgICAgc2NvcmUgPSAwXG4iLAogICAgIiAgICBiYXNlID0gMFxuIiwKICAgICIgICAgdGFnID0gXCJcIlxuIiwKICAgICIgICAgaWYgbGVuKHJhdGlvKSA+IDA6XG4iLAogICAgIiAgICAgICAgZm9yIGRldGVjdGlvbl9yYXRpbyBpbiByYXRpbzpcbiIsCiAgICAiICAgICAgICAgICAgc2NvcmUgKz0gaW50KGRldGVjdGlvbl9yYXRpby5zcGxpdChcIi9cIilbMF0pXG4iLAogICAgIiAgICAgICAgICAgIGJhc2UgKz0gaW50KGRldGVjdGlvbl9yYXRpby5zcGxpdChcIi9cIilbMV0pXG4iLAogICAgIiAgICAgICAgaWYgYmFzZSA+IDA6XG4iLAogICAgIiAgICAgICAgICAgIGRldGVjdGlvbl9yYXRpb19wZXJjID0gcm91bmQoKHNjb3JlIC8gYmFzZSkgKiAxMDAsIDIpXG4iLAogICAgIiAgICAgICAgICAgIGlmIGRldGVjdGlvbl9yYXRpb19wZXJjID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgICAgIGlmIGRldGVjdGlvbl9yYXRpb19wZXJjID49IDc1OlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIHRhZyA9IFwibWlzcDp0aHJlYXQtbGV2ZWw9XFxcImhpZ2gtcmlza1xcXCJcIlxuIiwKICAgICIgICAgICAgICAgICAgICAgZWxpZiBkZXRlY3Rpb25fcmF0aW9fcGVyYyA+PSA1MDpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICB0YWcgPSBcIm1pc3A6dGhyZWF0LWxldmVsPVxcXCJtZWRpdW0tcmlza1xcXCJcIlxuIiwKICAgICIgICAgICAgICAgICAgICAgI2VsaWYgZGV0ZWN0aW9uX3JhdGlvX3BlcmMgPj0gMjU6XG4iLAogICAgIiAgICAgICAgICAgICAgICBlbHNlOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIHRhZyA9IFwibWlzcDp0aHJlYXQtbGV2ZWw9XFxcImxvdy1yaXNrXFxcIlwiXG4iLAogICAgIiAgICAgICAgICAgIGVsc2U6XG4iLAogICAgIiAgICAgICAgICAgICAgICB0YWcgPSBcIm1pc3A6dGhyZWF0LWxldmVsPVxcXCJuby1yaXNrXFxcIlwiXG4iLAogICAgIiAgICByZXR1cm4gZGV0ZWN0aW9uX3JhdGlvX3BlcmMsIHRhZyIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjZiMGZlOWY0LTIzYjEtNGVlYy1iYzYxLThiYzk2NWZmYzYxOSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIFBSOjQgU2V0IGhlbHBlciB2YXJpYWJsZXNcbiIsCiAgICAiXG4iLAogICAgIlRoaXMgY2VsbCBjb250YWlucyAqKmhlbHBlciB2YXJpYWJsZXMqKiB0aGF0IGFyZSB1c2VkIGluIHRoaXMgcGxheWJvb2suIFRoZWlyIHVzYWdlIGlzIGV4cGxhaW5lZCBpbiB0aGUgbmV4dCBzdGVwcyBvZiB0aGUgcGxheWJvb2suXG4iLAogICAgIlxuIiwKICAgICItIGBzYW1wbGVzYCA6IGEgZGljdGlvbmFyeSBvZiB0aGUgb2JqZWN0cyB0aGF0IGFyZSBjcmVhdGVkIHdoZW4gdGhlIHBsYXlib29rIHByb2dyZXNzZXNcbiIsCiAgICAiLSBgbWFsd2FyZXpvb2AgOiB0aGUgbG9jYXRpb24gd2hlcmUgdGhlIHNhbXBsZXMgYXJlIHVwbG9hZGVkXG4iLAogICAgIi0gYGRlZmFuZ3N1ZmZpeGAgOiB0aGUgc3VmZml4IHRvIGFkZCB3aGVuIGRlZmFuZ2luZyB0aGUgc2FtcGxlcyIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjcyMjE0MWJkLTdhYjItNDc4Yi05NjE1LTg4ZDYyOGFkZGQ5OSIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICIjIERpY3Rpb25hcnkgdG8gc3RvcmUgcGxheWJvb2sgcmVzdWx0c1xuIiwKICAgICJzYW1wbGVzID0ge31cbiIsCiAgICAiXG4iLAogICAgIiMgTG9jYXRpb24gdG8gdXBsb2FkIHNhbXBsZXNcbiIsCiAgICAibWFsd2FyZXpvbyA9IFwiL2RhdGEvbm90ZWJvb2stZGVtby9wbGF5Ym9vay9ub3RlYm9va3MvZXZpZGVuY2VcIlxuIiwKICAgICJcbiIsCiAgICAiIyBTdWZmaXggdG8gYWRkIHdoZW4gZGVmYW5naW5nIHRoZSBzYW1wbGVzXG4iLAogICAgImRlZmFuZ3N1ZmZpeCA9IFwiLmRvLW5vdC1ydW5cIlxuIiwKICAgICJcbiIsCiAgICAiIyBIZWxwZXIgdmFyaWFibGVzXG4iLAogICAgIm1pc3BfZXZlbnQgPSBGYWxzZVxuIiwKICAgICJzdW1tYXJ5ID0gXCJcIiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjhmYWMxZWIzLTdjOTMtNGJhZS04NzAwLTM2MzIzNmU3YTYxZCIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIFBSOjUgTG9hZCBhbmQgZGVmYW5nIHNhbXBsZXNcbiIsCiAgICAiXG4iLAogICAgIlRoaXMgc2VjdGlvbiBjaGVja3MgaWYgdGhlcmUgYXJlIHVucHJvY2Vzc2VkIHNhbXBsZXMgaW4gYG1hbHdhcmV6b29gIGFuZCAqKmxvYWRzIHRoZXNlIHNhbXBsZXMqKiBpbiB0aGUgZGljdGlvbmFyeSBgc2FtcGxlc2AuIEl0IHdpbGwgYWxzbyBkZWZhbmcgdGhlIHNhbXBsZSB0byBwcmV2ZW50IGFjY2lkZW50aWFsIGV4ZWN1dGlvbi4gQSBzYW1wbGUgd2l0aCB0aGUgYGRlZmFuZ3N1ZmZpeGAgc3VmZml4IGlzIGNvbnNpZGVyZWQgYXMgcHJvY2Vzc2VkLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogImNiZTI3MTY0LWI3MTktNGQ1Yy04ODhjLTBkNDdlMWE5ZjU2OCIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICIjIENoZWNrIGlmIHRoZSBtYWx3YXJlIHNhbXBsZXMgZGlyZWN0b3J5IGV4aXN0cyBhbmQgbWlzcCBtb2R1bGVzIGFyZSBlbmFibGVkXG4iLAogICAgIm1hbHdhcmV6b29fZXJyb3JzID0gRmFsc2VcbiIsCiAgICAiXG4iLAogICAgIm1hbHdhcmV6b29fc2FtcGxlcyA9IFtmaWxlIGZvciBmaWxlIGluIG9zLmxpc3RkaXIobWFsd2FyZXpvbykgaWYgb3MucGF0aC5pc2ZpbGUob3MucGF0aC5qb2luKG1hbHdhcmV6b28sIGZpbGUpKV1cbiIsCiAgICAiaWYgbGVuKG1hbHdhcmV6b29fc2FtcGxlcykgPT0gMDpcbiIsCiAgICAiICAgIHByaW50KFwiVGhlcmUgYXJlIG5vIGZpbGVzIGluIFxcMDMzWzkxbXt9XFwwMzNbOTBtLlwiLmZvcm1hdChtYWx3YXJlem9vKSlcbiIsCiAgICAiICAgIHByaW50KFwiXFwwMzNbOTFtVW5hYmxlIHRvIHByb2NlZWQhXFwwMzNbOTBtXCIpXG4iLAogICAgImVsc2U6XG4iLAogICAgIiAgICAjIERlZmFuZyB0aGUgc2FtcGxlcyBiZWZvcmUgd2UgY29udGludWVcbiIsCiAgICAiICAgIHByaW50KFwiRGVmYW5nIHNhbXBsZXNcIilcbiIsCiAgICAiICAgIGZvciBzYW1wbGUgaW4gbWFsd2FyZXpvb19zYW1wbGVzOlxuIiwKICAgICIgICAgICAgIGlmIGRlZmFuZ3N1ZmZpeCBub3QgaW4gc2FtcGxlOlxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVfcGF0aCA9IFwie30ve317fVwiLmZvcm1hdChtYWx3YXJlem9vLCBzYW1wbGUsIGRlZmFuZ3N1ZmZpeClcbiIsCiAgICAiICAgICAgICAgICAgc2FtcGxlX29yaWdfcGF0aCA9IFwie30ve31cIi5mb3JtYXQobWFsd2FyZXpvbywgc2FtcGxlKVxuIiwKICAgICIgICAgICAgICAgICBvcy5zeXN0ZW0oXCJtdiB7fSB7fVwiLmZvcm1hdChzYW1wbGVfb3JpZ19wYXRoLCBzYW1wbGVfcGF0aCkpXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNbc2FtcGxlXSA9IHtcInBhdGhcIjogc2FtcGxlX3BhdGgsIFwib3JpZ19wYXRoXCI6IHNhbXBsZV9vcmlnX3BhdGh9XG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNbc2FtcGxlXVtcIk1JU1BcIl0gPSBbXVxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVzW3NhbXBsZV1bXCJGZWVkc1wiXSA9IFtdXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNbc2FtcGxlXVtcImRldGVjdGlvbl9yYXRpb1wiXSA9IFtdXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNbc2FtcGxlXVtcImRldGVjdGlvbl9yYXRpb19pbmRpcmVjdFwiXSA9IFtdXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNbc2FtcGxlXVtcInZ0XCJdID0ge31cbiIsCiAgICAiICAgICAgICAgICAgc2FtcGxlc1tzYW1wbGVdW1wibWFsd2FyZWJhemFhclwiXSA9IHt9XG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNbc2FtcGxlXVtcImhhc2hsb29rdXBcIl0gPSB7fVxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVzW3NhbXBsZV1bXCJwZVwiXSA9IHt9XG4iLAogICAgIiAgICAgICAgICAgIHByaW50KFwiIFJlbmFtZWQge30gdG8gXFwwMzNbOTJte31cXDAzM1s5MG1cIi5mb3JtYXQoc2FtcGxlLCBzYW1wbGVfcGF0aCkpXG4iLAogICAgIiAgICAgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICAgICAgcHJpbnQoXCIgU2tpcCBcXDAzM1s5MW17fVxcMDMzWzkwbSwgYWxyZWFkeSBwcm9jZXNzZWQgKGRlZmFuZ2VkKS5cIi5mb3JtYXQoc2FtcGxlKSlcbiIsCiAgICAiICAgIGlmIGxlbihzYW1wbGVzKSA+IDA6XG4iLAogICAgIiAgICAgICAgcHJpbnQoXCJcXG5cXDAzM1s5Mm1Db250aW51ZVxcMDMzWzkwbSB0aGUgcGxheWJvb2sgd2l0aCBcXDAzM1s5Mm17fVxcMDMzWzkwbSBzYW1wbGVzLlxcblwiLmZvcm1hdChsZW4oc2FtcGxlcykpKVxuIiwKICAgICIgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICBwcmludChcIkFsbCBzYW1wbGVzIGluIHRoZSBtYWx3YXJlem9vICh7fSkgYXJlIFxcMDMzWzkxbWFscmVhZHkgcHJvY2Vzc2VkXFwwMzNbOTBtIChkZWZhbmdlZCkuXFxuXCIuZm9ybWF0KG1hbHdhcmV6b28pKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjlkNzUwMzExLWZjODctNDVlMi1iM2YyLTg4YTE2MDNmM2RmZCIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIFBSOjYgTUlTUCBldmVudCBkZXRhaWxzXG4iLAogICAgIlxuIiwKICAgICIjIyMgRXZlbnQgdGl0bGVcbiIsCiAgICAiXG4iLAogICAgIkluIHRoaXMgcGxheWJvb2sgd2UgY3JlYXRlIGEgKipuZXcqKiBNSVNQIGV2ZW50IHdpdGggdGl0bGUgKipNYWx3YXJlIHRyaWFnZSBmb3IgX21hbHdhcmVsaXN0XyoqLiBZb3UgZ2V0IHRoZSBjaGFuY2UgdG8gb3ZlcnJpZGUgdGhpcyBkZWZhdWx0IHRpdGxlIGJ1dCByZW1lbWJlciB0aGF0IGl0IGlzIGdvb2QgcHJhY3RpY2UgdG8gY2hvb3NlIGEgc2VsZi1leHBsYW5hdG9yeSAqKmV2ZW50IHRpdGxlKiouIFRoaXMgZXZlbnQgdGl0bGUgaXMgc2hvd24gaW4gdGhlIE1JU1AgZXZlbnQgaW5kZXggYW5kIHNob3VsZCBwcm92aWRlIHlvdSB0aGUgbmVjZXNzYXJ5IGluZm9ybWF0aW9uIHdoYXQgdGhlIGV2ZW50IGlzIGFib3V0LiBZb3Ugc2hvdWxkIGF2b2lkIHVzaW5nIGdlbmVyaWMgZXZlbnQgdGl0bGVzLiBSZWFkIHRoZSBbQmVzdCBQcmFjdGljZXMgaW4gVGhyZWF0IEludGVsbGlnZW5jZV0oaHR0cHM6Ly93d3cubWlzcC1wcm9qZWN0Lm9yZy9iZXN0LXByYWN0aWNlcy1pbi10aHJlYXQtaW50ZWxsaWdlbmNlLmh0bWwpIGZvciBmdXJ0aGVyIGd1aWRhbmNlLlxuIiwKICAgICJcbiIsCiAgICAiIyMjIENvbnRleHVhbGlzYXRpb25cbiIsCiAgICAiXG4iLAogICAgIlRoaXMgcGxheWJvb2sgYWRkcyBldmVudCBjb250ZXh1YWxpc2F0aW9uIHZpYSB0aGUgKip0YWdzKiogdGhhdCBhcmUgZGVmaW5lZCBpbiBgZXZlbnRfYWRkaXRpb25hbF9nbG9iYWxfdGFnc2AgKGZvciAqZ2xvYmFsKiB0YWdzKSBhbmQgYGV2ZW50X2FkZGl0aW9uYWxfbG9jYWxfdGFnc2AgKGZvciAqbG9jYWwqIHRhZ3MpLiBBcyBhIHJlbWluZGVyLCB3aGVyZWFzICpnbG9iYWwqIHRhZ3MgcmVtYWluIGF0dGFjaGVkIHRvIHRoZSBldmVudHMgdGhhdCB5b3Ugc2hhcmUgd2l0aCB5b3VyIGNvbW11bml0eSwgdGhlICpsb2NhbCogdGFncyBhcmUgbm90IHNoYXJlZCBvdXRzaWRlIHlvdXIgb3JnYW5pc2F0aW9uLiBJdCdzIGFsc28gYSBnb29kIGlkZWEgdG8gcHJpbWFyaWx5IHVzZSB0YWdzIHRoYXQgYXJlIHBhcnQgb2YgYSBbdGF4b25vbXldKGh0dHBzOi8vZ2l0aHViLmNvbS9NSVNQL21pc3AtdGF4b25vbWllcyksIHRoaXMgYWxsb3dzIHlvdSB0byBtYWtlIHRoZSBjb250ZXh1YWxpc2F0aW9uIG1vcmUgcG9ydGFibGUgYWNjcm9zcyBtdWx0aXBsZSBNSVNQIGluc3RhbmNlcy5cbiIsCiAgICAiXG4iLAogICAgIkluIHRoaXMgcGxheWJvb2sgdGhlIGxpc3Qgb2YgdGFncyBpcyBidWlsZCB2aWEgb25lIG9mIHRoZSBoZWxwZXIgZnVuY3Rpb25zIGBwYl9nZXRfbWlzcF90YWdzYC4gVGhpcyBmdW5jdGlvbiB0YWtlcyB0d28gYXJndW1lbnRzLCBmaXJzdCBhIGxpc3Qgb2YgdGFncyB0byBjb252ZXJ0IGFzICpnbG9iYWwqIHRhZ3MsIGFuZCBzZWNvbmRseSBhIGxpc3Qgb2YgdGFncyB0byBjb252ZXJ0IGFzICpsb2NhbCogdGFncy4gSXQgdGhlbiByZXR1cm5zIGEgUHl0aG9uIGxpc3Qgb2YgTUlTUFRhZyBvYmplY3RzLlxuIiwKICAgICJcbiIsCiAgICAiIyMjIFRyYWZmaWMgTGlnaHQgUHJvdG9jb2xcbiIsCiAgICAiXG4iLAogICAgIlRoZSBkZWZhdWx0ICoqVExQKiogZm9yIHRoaXMgZXZlbnQgaXMgKio8c3BhbiBzdHlsZT0nY29sb3I6I0ZGQkYwMCc+dGxwOmFtYmVyPC9zcGFuPioqLiBUaGUgVHJhZmZpYyBMaWdodCBQcm90b2NvbCAoVExQKSBmYWNpbGl0YXRlcyBzaGFyaW5nIG9mIHBvdGVudGlhbGx5IHNlbnNpdGl2ZSBpbmZvcm1hdGlvbiBhbmQgYWxsb3dzIGZvciBtb3JlIGVmZmVjdGl2ZSBjb2xsYWJvcmF0aW9uLiBUTFAgaXMgYSBzZXQgb2YgZm91ciBzdGFuZGFyZCBsYWJlbHMgdG8gaW5kaWNhdGUgdGhlIHNoYXJpbmcgYm91bmRhcmllcyB0byBiZSBhcHBsaWVkIGJ5IHRoZSByZWNpcGllbnRzLiBUTFAgaXMgYWx3YXlzIHNldCBieSB0aGUgY3JlYXRvciBvZiBpbmZvcm1hdGlvbi4gWW91IGNhbiBmaW5kIG1vcmUgaW5mb3JtYXRpb24gYXQgW0ZJUlNUXShodHRwczovL3d3dy5maXJzdC5vcmcvdGxwLykuIFlvdSBjYW4gc3BlY2lmeSB0aGUgVExQIHZpYSBgZXZlbnRfdGxwYC5cbiIsCiAgICAiXG4iLAogICAgIiMjIyBNSVNQIGdhbGF4aWVzXG4iLAogICAgIlxuIiwKICAgICJUaGlzIHBsYXlib29rIGNhbiBhbHNvIGFkZCBNSVNQIGdhbGF4aWVzIHRvIHRoZSBldmVudCB3aXRoIHRoZSB2YXJpYWJsZSBgZXZlbnRfZ2FsYXhpZXNgLiBZb3UgY2FuIGFsc28gbGVhdmUgdGhlIGxpc3QgZW1wdHkgaWYgeW91IGRvIG5vdCB3YW50IHRvIGFkZCBnYWxheGllcyBpbiB0aGlzIHN0YWdlIG9mIHRoZSBpbnZlc3RpZ2F0aW9uLlxuIiwKICAgICJcbiIsCiAgICAiIyMjIE1JU1AgZGlzdHJpYnV0aW9uLCB0aHJlYXQgbGV2ZWwgYW5kIGFuYWx5c2lzIGxldmVsXG4iLAogICAgIlxuIiwKICAgICJPcHRpb25hbGx5IHlvdSBjYW4gc3BlY2lmaXkgYSBNSVNQICoqZGlzdHJpYnV0aW9uKiogKHdpdGggYGV2ZW50X2Rpc3RyaWJ1dGlvbmApLCAqKnRocmVhdCBsZXZlbCoqICh3aXRoIGBldmVudF90aHJlYXRfbGV2ZWxfaWRgKSBvciAqKmFuYWx5c2lzIHN0YXRlKiogKHdpdGggYGV2ZW50X2FuYWx5c2lzYCkuIFRoZSBldmVudCAqKmRhdGUqKiBpcyBzZXQgdG8gdG9kYXkgdmlhIGBldmVudF9kYXRlYC5cbiIsCiAgICAiXG4iLAogICAgIklmIHlvdSBjYW5ub3QgcmVtZW1iZXIgdGhlIG9wdGlvbnMgZm9yIGRpc3RyaWJ1dGlvbiwgdGhyZWF0IGxldmVsIG9yIHRoZSBhbmFseXNpcyBzdGF0ZSB0aGVuIHVzZSB0aGUgbmV4dCBjZWxsIHRvIGd1aWRlIHlvdS4gVGhpcyBjZWxsIGlzIHNldCBhcyAqKnJhdyoqLiBJZiB5b3UgKipjaGFuZ2UgaXRzIHR5cGUgdG8gY29kZSoqIGFuZCBleGVjdXRlIHRoZSBjZWxsIHlvdSBnZXQgYW4gb3ZlcnZpZXcgb2YgdGhlIG9wdGlvbnMgYXZhaWxhYmxlIGZvciBjcmVhdGluZyBhIE1JU1AgZXZlbnQuIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAicmF3IiwKICAgImlkIjogImE3ZDVmYTI1LTBlMjItNGZkMC04M2Q5LWYyNWU5Y2VlYzA1NiIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgInNvdXJjZSI6IFsKICAgICIjIFRoaXMgY2VsbCBpcyAncmF3JyBieSBkZWZhdWx0LiBDaGFuZ2UgaXQgdG8gJ2NvZGUnIHRvIGV4ZWN1dGUgaXQuXG4iLAogICAgIlxuIiwKICAgICJwcmludChcIkRpc3RyaWJ1dGlvbiB2YWx1ZVwiKVxuIiwKICAgICJmb3IgZSBpbiBEaXN0cmlidXRpb246XG4iLAogICAgIiAgICBwcmludChcIiBcIiwgZS52YWx1ZSwgXCI9XCIsIGUpXG4iLAogICAgInByaW50KFwiXFxuXCIpXG4iLAogICAgInByaW50KFwiVGhyZWF0IGxldmVsXCIpXG4iLAogICAgImZvciBlIGluIFRocmVhdExldmVsOlxuIiwKICAgICIgICAgcHJpbnQoXCIgXCIsIGUudmFsdWUsIFwiPVwiLCBlKVxuIiwKICAgICJwcmludChcIlxcblwiKVxuIiwKICAgICJwcmludChcIkFuYWx5c2lzIGxldmVsXCIpXG4iLAogICAgImZvciBlIGluIEFuYWx5c2lzOlxuIiwKICAgICIgICAgcHJpbnQoXCIgXCIsIGUudmFsdWUsIFwiPVwiLCBlKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjE3YmMxZjk4LTY5OTYtNDUyNy1iZjI4LWIzYmNkZDZjNGJjOCIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIFBSOjcgU2V0dXAgTUlTUCBldmVudCBsaW5rXG4iLAogICAgIlxuIiwKICAgICJCeSBkZWZhdWx0IHRoZSBwbGF5Ym9vayB3aWxsIGdlbmVyYXRlIGEgKip0aXRsZSoqIHdpdGggYSBwcmVmaXggYW5kIHRoZSBtYWx3YXJlIHlvdSB3YW50IHRvIGludmVzdGlnYXRlLiBZb3UgY2FuIG92ZXJyaWRlIHRoaXMgZXZlbnQgdGl0bGUgd2l0aCB0aGUgdmFyaWFibGUgYGV2ZW50X3RpdGxlYC4gSWYgeW91IGxlYXZlIHRoaXMgdmFsdWUgZW1wdHkgdGhlIHBsYXlib29rIHdpbGwgZ2VuZXJhdGUgdGhlIE1JU1AgZXZlbnQgdGl0bGUgZm9yIHlvdS4iCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJjb2RlIiwKICAgImV4ZWN1dGlvbl9jb3VudCI6IG51bGwsCiAgICJpZCI6ICI5YmFlM2U1Yy00ZDk0LTQ0MGUtODY2ZS1lYzI3MTdmMjA1MGMiLAogICAibWV0YWRhdGEiOiB7CiAgICAidGFncyI6IFtdCiAgIH0sCiAgICJvdXRwdXRzIjogW10sCiAgICJzb3VyY2UiOiBbCiAgICAiIyBQcm92aWRlIHRoZSBldmVudCB0aXRsZSBmb3IgYSBuZXcgZXZlbnQuIExlYXZlIGJsYW5rIGZvciB0aGUgcGxheWJvb2sgdG8gYXV0byBnZW5lcmF0ZSBvbmVcbiIsCiAgICAiZXZlbnRfdGl0bGUgPSBcIlwiXG4iLAogICAgIlxuIiwKICAgICIjIFByZWZpeCBmb3IgYXV0byBnZW5lcmF0ZSBldmVudCB0aXRsZVxuIiwKICAgICJldmVudF90aXRsZV9kZWZhdWx0X3ByZWZpeCA9IFwiTWFsd2FyZSB0cmlhZ2VcIlxuIiwKICAgICJcbiIsCiAgICAiIyBPcHRpb25hbGx5LCB5b3UgY2FuIGNoYW5nZSBUTFAsIGFkZCBhZGRpdGlvbmFsIGV2ZW50IChsb2NhbCBhbmQgZ2xvYmFsKSB0YWdzLCB0aHJlYXRsZXZlbCwgYW5hbHlzaXMgc3RhdGUgb3IgZGlzdHJpYnV0aW9uIGxldmVsXG4iLAogICAgImV2ZW50X3RscCA9IFwidGxwOmFtYmVyXCJcbiIsCiAgICAiXG4iLAogICAgIiMgRXZlbnQgY29udGV4dFxuIiwKICAgICJldmVudF9hZGRpdGlvbmFsX2dsb2JhbF90YWdzID0gW10gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRoaXMgbmVlZHMgdG8gYmUgYSBQeXRob24gbGlzdFxuIiwKICAgICJldmVudF9hZGRpdGlvbmFsX2xvY2FsX3RhZ3MgPSBbXCJ3b3JrZmxvdzpzdGF0ZT1cXFwiaW5jb21wbGV0ZVxcXCJcIl0gICAjIFRoaXMgbmVlZHMgdG8gYmUgYSBQeXRob24gbGlzdFxuIiwKICAgICJcbiIsCiAgICAiIyBFdmVudCBnYWxheGllc1xuIiwKICAgICJldmVudF9nYWxheGllcyA9IFsgXCJtaXNwLWdhbGF4eTptaXRyZS1hdHRhY2stcGF0dGVybj1cXFwiTWFsd2FyZSAtIFQxNTg3LjAwMVxcXCJcIiwgXCJtaXNwLWdhbGF4eTptaXRyZS1hdHRhY2stcGF0dGVybj1cXFwiTWFsd2FyZSAtIFQxNTg4LjAwMVxcXCJcIl1cbiIsCiAgICAiXG4iLAogICAgIiMgQWRkaXRpb25hbCBNSVNQIGV2ZW50IHNldHRpbmdzXG4iLAogICAgImV2ZW50X3RocmVhdF9sZXZlbF9pZCA9IFRocmVhdExldmVsLmxvd1xuIiwKICAgICJldmVudF9hbmFseXNpcyA9IEFuYWx5c2lzLm9uZ29pbmdcbiIsCiAgICAiZXZlbnRfZGlzdHJpYnV0aW9uID0gRGlzdHJpYnV0aW9uLnlvdXJfb3JnYW5pc2F0aW9uX29ubHlcbiIsCiAgICAiZXZlbnRfZGF0ZSA9IGRhdGUudG9kYXkoKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjg4OTZlZjE3LTczM2YtNDNkNy1iZjhiLTQ5YTcwZjY4MzQwYSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIyBDcmVhdGUgTUlTUCBldmVudFxuIiwKICAgICJcbiIsCiAgICAiVGhlIG5leHQgY29kZSBjZWxsIHdpbGwgKipjcmVhdGUgdGhlIE1JU1AgZXZlbnQqKiBhbmQgc3RvcmUgdGhlIHJlZmVyZW5jZXMgdG8gdGhlIG5ld2x5IGNyZWF0ZWQgZXZlbnQgaW4gdGhlIHZhcmlhYmxlIGBtaXNwX2V2ZW50YC4gVGhpcyB2YXJpYWJsZSBpcyB1c2VkIGZ1cnRoZXIgd2hlbiB0aGUgcGxheWJvb2sgcHJvZ3Jlc3Nlcy4iCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJjb2RlIiwKICAgImV4ZWN1dGlvbl9jb3VudCI6IG51bGwsCiAgICJpZCI6ICIzMDA5ZjhiMy0wNTg4LTQyM2UtYTdiZS02MTRkZmJjNWRjMmEiLAogICAibWV0YWRhdGEiOiB7CiAgICAidGFncyI6IFtdCiAgIH0sCiAgICJvdXRwdXRzIjogW10sCiAgICJzb3VyY2UiOiBbCiAgICAiIyBDb2RlIGJsb2NrIHRvIGNyZWF0ZSB0aGUgZXZlbnQgb3IgYWRkIGRhdGEgdG8gYW4gZXhpc3RpbmcgZXZlbnRcbiIsCiAgICAiZXZlbnRfdGl0bGUgPSBldmVudF90aXRsZS5zdHJpcCgpXG4iLAogICAgIlxuIiwKICAgICJpZiBub3QobGVuKGV2ZW50X3RpdGxlKSA+IDApOlxuIiwKICAgICIgICAgcXVlcnlfc2FtcGxlID0gXCJcIlxuIiwKICAgICIgICAgZm9yIGtleSwgc2FtcGxlIGluIHNhbXBsZXMuaXRlbXMoKTpcbiIsCiAgICAiICAgICAgICBxdWVyeV9zYW1wbGUgPSBcInt9IHt9XCIuZm9ybWF0KGtleSwgcXVlcnlfc2FtcGxlKVxuIiwKICAgICIgICAgZXZlbnRfdGl0bGUgPSBcInt9IGZvciB7fVwiLmZvcm1hdChldmVudF90aXRsZV9kZWZhdWx0X3ByZWZpeCwgcXVlcnlfc2FtcGxlKVxuIiwKICAgICJcbiIsCiAgICAiIyBDb25zdHJ1Y3QgdGhlIGV2ZW50IHRhZ3NcbiIsCiAgICAiZXZlbnRfYWRkaXRpb25hbF9nbG9iYWxfdGFncy5hcHBlbmQoZXZlbnRfdGxwKVxuIiwKICAgICJpZiBsZW4oZXZlbnRfZ2FsYXhpZXMpID4gMDpcbiIsCiAgICAiICAgIGV2ZW50X2FkZGl0aW9uYWxfZ2xvYmFsX3RhZ3MuYXBwZW5kKGV2ZW50X2dhbGF4aWVzKVxuIiwKICAgICJldmVudF90YWdzID0gcGJfZ2V0X21pc3BfdGFncyhldmVudF9hZGRpdGlvbmFsX2dsb2JhbF90YWdzLCBldmVudF9hZGRpdGlvbmFsX2xvY2FsX3RhZ3MpXG4iLAogICAgIlxuIiwKICAgICIjIENyZWF0ZSB0aGUgUHlNSVNQIG9iamVjdCBmb3IgYW4gZXZlbnRcbiIsCiAgICAiZXZlbnQgPSBNSVNQRXZlbnQoKVxuIiwKICAgICJldmVudC5pbmZvID0gZXZlbnRfdGl0bGVcbiIsCiAgICAiZXZlbnQuZGlzdHJpYnV0aW9uID0gZXZlbnRfZGlzdHJpYnV0aW9uXG4iLAogICAgImV2ZW50LnRocmVhdF9sZXZlbF9pZCA9IGV2ZW50X3RocmVhdF9sZXZlbF9pZFxuIiwKICAgICJldmVudC5hbmFseXNpcyA9IGV2ZW50X2FuYWx5c2lzXG4iLAogICAgImV2ZW50LnNldF9kYXRlKGV2ZW50X2RhdGUpXG4iLAogICAgIlxuIiwKICAgICIjIENyZWF0ZSB0aGUgTUlTUCBldmVudCBvbiB0aGUgc2VydmVyIHNpZGVcbiIsCiAgICAibWlzcF9ldmVudCA9IG1pc3AuYWRkX2V2ZW50KGV2ZW50LCBweXRob25pZnk9VHJ1ZSlcbiIsCiAgICAicHJpbnQoXCJDb250aW51ZSB0aGUgcGxheWJvb2sgd2l0aCB0aGUgbmV3IFxcMDMzWzkybWNyZWF0ZWRcXDAzM1s5MG0gTUlTUCBldmVudCBJRCB7fSB3aXRoIHRpdGxlIFxcMDMzWzkybXt9XFwwMzNbOTBtIGFuZCBVVUlEIHt9XCIuZm9ybWF0KG1pc3BfZXZlbnQuaWQsIG1pc3BfZXZlbnQuaW5mbywgbWlzcF9ldmVudC51dWlkKSlcbiIsCiAgICAiZm9yIHRhZyBpbiBldmVudF90YWdzOlxuIiwKICAgICIgICAgaWYgbGVuKHRhZykgPiAwOlxuIiwKICAgICIgICAgICAgIG1pc3AudGFnKG1pc3BfZXZlbnQudXVpZCwgdGFnLCBsb2NhbD10YWcubG9jYWwpXG4iLAogICAgIiAgICAgICAgcHJpbnQoXCJcXDAzM1s5Mm1BZGRlZFxcMDMzWzkwbSBldmVudCB0YWcge31cIi5mb3JtYXQodGFnKSlcbiIsCiAgICAicHJpbnQoXCJcXG5cIikiCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJtYXJrZG93biIsCiAgICJpZCI6ICI3YWU2YTM2Zi05MWJjLTQxZDYtYWQxMy0wNThhMmEzZjliNDUiLAogICAibWV0YWRhdGEiOiB7fSwKICAgInNvdXJjZSI6IFsKICAgICIjIEludmVzdGlnYXRlXG4iLAogICAgIlxuIiwKICAgICJUaGlzIHNlY3Rpb24gc3RhcnRzIHRoZSBpbnZlc3RpZ2F0aW9uIGZvciB0aGUgbWFsd2FyZSB0cmlhZ2UuXG4iLAogICAgIlxuIiwKICAgICIjIyBJTjoxIEZpbGUgYW5hbHlzaXNcbiIsCiAgICAiXG4iLAogICAgIlRoZSBmaXJzdCBzdGVwICoqdXBsb2FkcyB0aGUgc2FtcGxlcyoqIHRvIHRoZSBNSVNQIGV2ZW50IGFuZCB1c2VzIHRoZSAqKmFkdmFuY2VkIGV4dHJhY3Rpb24qKiBmZWF0dXJlcyB0byBpZGVudGlmeSB1c2VmdWwgZWxlbWVudHMuIFRoaXMgY3JlYXRlcyBhIHNldCBvZiByZWxhdGVkIG9iamVjdHMgaW4gdGhlIGV2ZW50IFRoZSByZXN1bHRzIGFyZSBhZGRlZCB0byB0aGUgYHNhbXBsZXNgIGRpY3Rpb25hcnkuXG4iLAogICAgIlxuIiwKICAgICJUaGUgc2VjdGlvbiB0ZW1wb3JhcmlseSBzZXRzIHRoZSBsb2dnaW5nIGxldmVsIG9mIE1JU1AgdG8gKmVycm9yKiBzbyB0aGF0IGl0IGRvZXMgbm90IHN0b3AgZXhlY3V0aW9uIHdoZW4gZXJyb3JzIG9jY3VyIHdoZW4gYW5hbHlzaW5nIHNwZWNpZmljIHNlY3Rpb25zIG9mIHRoZSBzYW1wbGVzLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjg1MTdkNDdiLTcwMTctNDk0NS05YjZhLTNhN2I5Mzg5YzExMiIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICIjIEF2b2lkIGdldHRpbmcgUHlNSVNQIGVycm9ycy4gV2UgcmVzZXQgaXQgdG8gdGhlIG9yaWdpbmFsIHN0YXRlIGFmdGVyd2FyZHNcbiIsCiAgICAiY3VycmVudF9sb2dnaW5nID0gbG9nZ2luZy5nZXRMb2dnZXIoXCJweW1pc3BcIikuZ2V0RWZmZWN0aXZlTGV2ZWwoKVxuIiwKICAgICJsb2dnaW5nLmdldExvZ2dlcihcInB5bWlzcFwiKS5zZXRMZXZlbChsb2dnaW5nLkVSUk9SKVxuIiwKICAgICJcbiIsCiAgICAiIyBMb29wIHRocm91Z2ggdGhlIHNhbXBsZXNcbiIsCiAgICAicHJpbnQoXCJQcm9jZXNzaW5nIHNhbXBsZXMgYW5kIGF0dGFjaGluZyB0aGVtIHRvIGFuIGV2ZW50XCIpXG4iLAogICAgImZvciBrZXksIHNhbXBsZSBpbiBzYW1wbGVzLml0ZW1zKCk6XG4iLAogICAgIiAgICBhdHRhY2htZW50ID0gc2FtcGxlLmdldChcInBhdGhcIilcbiIsCiAgICAiICAgIHRyeTpcbiIsCiAgICAiICAgICAgICBwcmludChcIiBXb3JraW5nIG9uICVzXCIgJSBhdHRhY2htZW50KVxuIiwKICAgICIgICAgICAgIGZvLCBwZW8sIHNlb3MgPSBtYWtlX2JpbmFyeV9vYmplY3RzKGF0dGFjaG1lbnQpXG4iLAogICAgIiAgICBleGNlcHQgRXhjZXB0aW9uOlxuIiwKICAgICIgICAgICAgIGNvbnRpbnVlXG4iLAogICAgIlxuIiwKICAgICIgICAgaWYgc2VvczpcbiIsCiAgICAiICAgICAgICBwcmludChcIiAgUEVTZWN0aW9uT2JqZWN0XCIpXG4iLAogICAgIiAgICAgICAgZm9yIHMgaW4gc2VvczpcbiIsCiAgICAiICAgICAgICAgICAgciA9IG1pc3AuYWRkX29iamVjdChtaXNwX2V2ZW50LnV1aWQsIHMpXG4iLAogICAgIlxuIiwKICAgICIgICAgaWYgcGVvOlxuIiwKICAgICIgICAgICAgIHByaW50KFwiICBQRU9iamVjdFwiKVxuIiwKICAgICIgICAgICAgIGlmIGhhc2F0dHIocGVvLCAnY2VydGlmaWNhdGVzJykgYW5kIGhhc2F0dHIocGVvLCAnc2lnbmVycycpOlxuIiwKICAgICIgICAgICAgICAgICBmb3IgYyBpbiBwZW8uY2VydGlmaWNhdGVzOlxuIiwKICAgICIgICAgICAgICAgICAgICAgbWlzcC5hZGRfb2JqZWN0KG1pc3BfZXZlbnQudXVpZCwgYywgcHl0aG9uaWZ5PVRydWUpXG4iLAogICAgIiAgICAgICAgICAgIGZvciBzIGluIHBlby5zaWduZXJzOlxuIiwKICAgICIgICAgICAgICAgICAgICAgbWlzcC5hZGRfb2JqZWN0KG1pc3BfZXZlbnQudXVpZCwgcywgcHl0aG9uaWZ5PVRydWUpXG4iLAogICAgIiAgICAgICAgICAgIGRlbCBwZW8uY2VydGlmaWNhdGVzXG4iLAogICAgIiAgICAgICAgICAgIGRlbCBwZW8uc2lnbmVyc1xuIiwKICAgICIgICAgICAgIGRlbCBwZW8uc2VjdGlvbnNcbiIsCiAgICAiICAgICAgICByID0gbWlzcC5hZGRfb2JqZWN0KG1pc3BfZXZlbnQudXVpZCwgcGVvLCBweXRob25pZnk9VHJ1ZSlcbiIsCiAgICAiICAgICAgICBmb3IgcmVmIGluIHBlby5PYmplY3RSZWZlcmVuY2U6XG4iLAogICAgIiAgICAgICAgICAgIHIgPSBtaXNwLmFkZF9vYmplY3RfcmVmZXJlbmNlKHJlZilcbiIsCiAgICAiXG4iLAogICAgIiAgICBpZiBmbzpcbiIsCiAgICAiICAgICAgICBwcmludChcIiAgRmlsZU9iamVjdFwiKVxuIiwKICAgICIgICAgICAgIHJlc3BvbnNlID0gbWlzcC5hZGRfb2JqZWN0KG1pc3BfZXZlbnQudXVpZCwgZm8sIHB5dGhvbmlmeT1UcnVlKVxuIiwKICAgICIgICAgICAgIGZvciByZWYgaW4gZm8uT2JqZWN0UmVmZXJlbmNlOlxuIiwKICAgICIgICAgICAgICAgICByID0gbWlzcC5hZGRfb2JqZWN0X3JlZmVyZW5jZShyZWYpXG4iLAogICAgIiAgICAgICAgc2FtcGxlc1trZXldW1wiZmlsZW9iamVjdFwiXSA9IHJlc3BvbnNlXG4iLAogICAgIiAgICAgICAgc2FtcGxlc1trZXldW1wiZmlsZW9iamVjdF91dWlkXCJdID0gcmVzcG9uc2UudXVpZFxuIiwKICAgICIgICAgICAgIHByaW50KFwiICAgQWRkZWQgZmlsZSBvYmplY3Qgd2l0aCBVVUlEIFxcMDMzWzkybXt9XFwwMzNbOTBtXCIuZm9ybWF0KHJlc3BvbnNlLnV1aWQpKVxuIiwKICAgICIgICAgICAgIGZvciBhdHRyaWJ1dGUgaW4gcmVzcG9uc2UuYXR0cmlidXRlczpcbiIsCiAgICAiICAgICAgICAgICAgaWYgYXR0cmlidXRlLm9iamVjdF9yZWxhdGlvbiA9PSBcInNoYTI1NlwiOlxuIiwKICAgICIgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wic2hhMjU2XCJdID0gYXR0cmlidXRlLnZhbHVlXG4iLAogICAgIiAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJzaGEyNTZfdXVpZFwiXSA9IGF0dHJpYnV0ZS51dWlkXG4iLAogICAgIiAgICAgICAgICAgIGlmIGF0dHJpYnV0ZS5vYmplY3RfcmVsYXRpb24gPT0gXCJtZDVcIjpcbiIsCiAgICAiICAgICAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcIm1kNVwiXSA9IGF0dHJpYnV0ZS52YWx1ZVxuIiwKICAgICIgICAgICAgICAgICBpZiBhdHRyaWJ1dGUub2JqZWN0X3JlbGF0aW9uID09IFwibWFsd2FyZS1zYW1wbGVcIjpcbiIsCiAgICAiICAgICAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcIm1hbHdhcmUtc2FtcGxlX3V1aWRcIl0gPSBhdHRyaWJ1dGUudXVpZFxuIiwKICAgICIgICAgICAgICAgICBpZiBhdHRyaWJ1dGUub2JqZWN0X3JlbGF0aW9uID09IFwiZW50cm9weVwiOlxuIiwKICAgICIgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wiZW50cm9weVwiXSA9IGF0dHJpYnV0ZS52YWx1ZVxuIiwKICAgICIgICAgICAgICAgICBpZiBhdHRyaWJ1dGUub2JqZWN0X3JlbGF0aW9uID09IFwibWltZXR5cGVcIjpcbiIsCiAgICAiICAgICAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcIm1pbWV0eXBlXCJdID0gYXR0cmlidXRlLnZhbHVlXG4iLAogICAgIiAgICAgICAgcHJpbnQoXCIgICAgTUQ1OiBcXDAzM1s5Mm17fVxcMDMzWzkwbVxcbiAgICBTSEEyNTY6IFxcMDMzWzkybXt9XFwwMzNbOTBtXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcIm1kNVwiXSwgc2FtcGxlc1trZXldW1wic2hhMjU2XCJdKSlcbiIsCiAgICAiXG4iLAogICAgImxvZ2dpbmcuZ2V0TG9nZ2VyKFwicHltaXNwXCIpLnNldExldmVsKGN1cnJlbnRfbG9nZ2luZylcbiIsCiAgICAicHJpbnQoXCJGaW5pc2hlZCBwcm9jZXNzaW5nIHNhbXBsZXMuXCIpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiNjI4YTcxMzQtNjZmOS00NTRmLWI0ZmItMjQxZjJlM2Q5N2IzIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgSU46MiBWaXJ1c1RvdGFsIHJlc3VsdHNcbiIsCiAgICAiXG4iLAogICAgIk5leHQgd2UgdXNlIFtWaXJ1c1RvdGFsXShodHRwczovL3d3dy52aXJ1c3RvdGFsLmNvbS9ndWkvKS4gRmlyc3Qgd2UgdXNlIHRoZSBNSVNQIG1vZHVsZXMgdG8gcXVlcnkgVmlydXNUb3RhbC4gVGhlIGFkdmFudGFnZSBvZiB1c2luZyB0aGUgTUlTUCBtb2R1bGVzIGlzIHRoYXQgaXQgcmV0dXJucyBNSVNQIGF0dHJpYnV0ZXMgYW5kIG9iamVjdHMgdGhhdCBjYW4gdGhlbiBiZSBlYXNpbHkgYWRkZWQgdG8gdGhlIGV2ZW50LlxuIiwKICAgICJcbiIsCiAgICAiQWZ0ZXIgdXNpbmcgdGhlIG1vZHVsZXMsIHdlIHF1ZXJ5IFZpcnVzVG90YWwgZGlyZWN0bHkgKHdpdGhvdXQgdXNpbmcgdGhlIG1vZHVsZSkgdG8gZ2V0IHRoZSAqKnRocmVhdCBjbGFzc2lmaWNhdGlvbioqLCAqKnNhbmRib3gqKiByZXN1bHRzIGFuZCB0aGUgKipTaWdtYSoqIHJ1bGVzIHRoYXQgdHJpZ2dlcmVkIGRldGVjdGlvbi5cbiIsCiAgICAiXG4iLAogICAgIk5vdGUgdGhhdCB0aGUgc2FtcGxlIGlzICoqbm90Kiogc3VibWl0dGVkIHRvIFZpcnVzVG90YWwgZm9yIGFuYWx5c2lzLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjVhZmFmZTBkLTg3YjItNDEzZi04ZWU4LWNkY2ZmN2ZiM2U5MCIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICIjIExvb3AgdGhyb3VnaCB0aGUgc2FtcGxlc1xuIiwKICAgICJcbiIsCiAgICAiIyBVc2UgdGhlIG1vZHVsZXMgdG8gY3JlYXRlIE1JU1Agb2JqZWN0c1xuIiwKICAgICIjIFRoZW4gZG8gYSBzZWNvbmQgcXVlcnkgdG8gZ2V0IHRoZSBmaWxlIGRldGFpbHNcbiIsCiAgICAiXG4iLAogICAgInNjYW5fY291bnQgPSAwXG4iLAogICAgIm1vZHVsZV9uYW1lID0gXCJ2aXJ1c3RvdGFsX3B1YmxpY1wiXG4iLAogICAgImhlYWRlcnMgPSB7XG4iLAogICAgIiAgICBcImFjY2VwdFwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiIsCiAgICAiICAgIFwieC1hcGlrZXlcIjogdmlydXN0b3RhbF9hcGlrZXlcbiIsCiAgICAifVxuIiwKICAgICJcbiIsCiAgICAicHJpbnQoXCJWZXJpZnlpbmcgc2FtcGxlcyB3aXRoIHt9XCIuZm9ybWF0KG1vZHVsZV9uYW1lKSlcbiIsCiAgICAiZm9yIGtleSwgc2FtcGxlIGluIHNhbXBsZXMuaXRlbXMoKTpcbiIsCiAgICAiICAgIGF0dHJpYnV0ZV90eXBlID0gXCJzaGEyNTZcIlxuIiwKICAgICIgICAgdmFsdWUgPSBzYW1wbGUuZ2V0KFwic2hhMjU2XCIpXG4iLAogICAgIiAgICBtb2R1bGVfY29tbWVudCA9IFwiRnJvbSB7fSBmb3Ige31cIi5mb3JtYXQobW9kdWxlX25hbWUsIGtleSlcbiIsCiAgICAiICAgIGRhdGEgPSB7XG4iLAogICAgIiAgICAgICAgXCJhdHRyaWJ1dGVcIjoge1xuIiwKICAgICIgICAgICAgICAgICBcInR5cGVcIjogZlwie2F0dHJpYnV0ZV90eXBlfVwiLFxuIiwKICAgICIgICAgICAgICAgICBcInV1aWRcIjogc3RyKHV1aWQudXVpZDQoKSksXG4iLAogICAgIiAgICAgICAgICAgIFwidmFsdWVcIjogZlwie3ZhbHVlfVwiLFxuIiwKICAgICIgICAgICAgIH0sXG4iLAogICAgIiAgICAgICAgXCJtb2R1bGVcIjogbW9kdWxlX25hbWUsXG4iLAogICAgIiAgICAgICAgXCJjb25maWdcIjoge1wiYXBpa2V5XCI6IHZpcnVzdG90YWxfYXBpa2V5fVxuIiwKICAgICIgICAgfVxuIiwKICAgICIgICAgcHJpbnQoXCJRdWVyeSBcXDAzM1s5Mm17fVxcMDMzWzkwbSBhcyBcXDAzM1s5Mm17fVxcMDMzWzkwbVwiLmZvcm1hdCh2YWx1ZSwgYXR0cmlidXRlX3R5cGUpKVxuIiwKICAgICIgICAgcmVzdWx0ID0gcmVxdWVzdHMucG9zdChcInt9L3F1ZXJ5XCIuZm9ybWF0KG1pc3BfbW9kdWxlc191cmwpLCBoZWFkZXJzPW1pc3BfbW9kdWxlc19oZWFkZXJzLCBqc29uPWRhdGEpXG4iLAogICAgIiAgICBpZiBcInJlc3VsdHNcIiBpbiByZXN1bHQuanNvbigpIGFuZCBsZW4ocmVzdWx0Lmpzb24oKVtcInJlc3VsdHNcIl0pID4gMDpcbiIsCiAgICAiICAgICAgICByZXN1bHRfanNvbiA9IHJlc3VsdC5qc29uKClbXCJyZXN1bHRzXCJdXG4iLAogICAgIlxuIiwKICAgICIgICAgICAgIGZvciBtaXNwX2F0dHJpYnV0ZSBpbiByZXN1bHRfanNvbi5nZXQoXCJBdHRyaWJ1dGVcIiwgW10pOlxuIiwKICAgICIgICAgICAgICAgICBtaXNwX2F0dHJpYnV0ZVtcImNvbW1lbnRcIl0gPSBcInt9e31cIi5mb3JtYXQobW9kdWxlX2NvbW1lbnQsIG1pc3BfYXR0cmlidXRlLmdldChcImNvbW1lbnRcIiwgXCJcIikpXG4iLAogICAgIiAgICAgICAgICAgIGNyZWF0ZWRfYXR0cmlidXRlID0gbWlzcC5hZGRfYXR0cmlidXRlKG1pc3BfZXZlbnQudXVpZCwgbWlzcF9hdHRyaWJ1dGUsIHB5dGhvbmlmeT1UcnVlKVxuIiwKICAgICIgICAgICAgICAgICBpZiBub3QgXCJlcnJvcnNcIiBpbiBjcmVhdGVkX2F0dHJpYnV0ZTpcbiIsCiAgICAiICAgICAgICAgICAgICAgIHByaW50KFwiIEdvdCB7fSBcXDAzM1s5Mm17fVxcMDMzWzkwbVwiLmZvcm1hdChtaXNwX2F0dHJpYnV0ZVtcInR5cGVcIl0sIG1pc3BfYXR0cmlidXRlW1widmFsdWVcIl0pKVxuIiwKICAgICIgICAgICAgICAgICAgICAgbWlzcC5hZGRfb2JqZWN0X3JlZmVyZW5jZShzYW1wbGUuZ2V0KFwiZmlsZW9iamVjdFwiKS5hZGRfcmVmZXJlbmNlKGNyZWF0ZWRfYXR0cmlidXRlLnV1aWQsIFwicmVsYXRlZC10b1wiKSlcbiIsCiAgICAiICAgICAgICAgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICAgICAgICAgIHByaW50KFwiIFVuYWJsZSB0byBhZGQge30gXFwwMzNbOTJte31cXDAzM1s5MG0gdG8gTUlTUCBldmVudFwiLmZvcm1hdChtaXNwX2F0dHJpYnV0ZVtcInR5cGVcIl0sIG1pc3BfYXR0cmlidXRlW1widmFsdWVcIl0pKVxuIiwKICAgICIgICAgICAgIGZvciBtaXNwX29iamVjdCBpbiByZXN1bHRfanNvbi5nZXQoXCJPYmplY3RcIiwgW10pOlxuIiwKICAgICIgICAgICAgICAgICBtaXNwX29iamVjdFtcImNvbW1lbnRcIl0gPSBcInt9e31cIi5mb3JtYXQobW9kdWxlX2NvbW1lbnQsIG1pc3Bfb2JqZWN0LmdldChcImNvbW1lbnRcIiwgXCJcIikpXG4iLAogICAgIiAgICAgICAgICAgIGlmIGxlbihtaXNwX29iamVjdFtcIkF0dHJpYnV0ZVwiXSkgPiAwOlxuIiwKICAgICIgICAgICAgICAgICAgICAgY3JlYXRlZF9vYmplY3QgPSBtaXNwLmFkZF9vYmplY3QobWlzcF9ldmVudC51dWlkLCBtaXNwX29iamVjdCwgcHl0aG9uaWZ5PVRydWUpXG4iLAogICAgIiAgICAgICAgICAgICAgICBpZiBub3QgXCJlcnJvcnNcIiBpbiBjcmVhdGVkX29iamVjdDpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBwcmludChcIiBHb3QgXFwwMzNbOTJte31cXDAzM1s5MG0gXCIuZm9ybWF0KG1pc3Bfb2JqZWN0W1wibmFtZVwiXSkpXG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgbWlzcC5hZGRfb2JqZWN0X3JlZmVyZW5jZShzYW1wbGUuZ2V0KFwiZmlsZW9iamVjdFwiKS5hZGRfcmVmZXJlbmNlKGNyZWF0ZWRfb2JqZWN0LnV1aWQsIFwicmVsYXRlZC10b1wiKSlcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBpZiBtaXNwX29iamVjdFtcIm5hbWVcIl0gPT0gXCJ2aXJ1c3RvdGFsLXJlcG9ydFwiOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3RfdnRfcmVwb3J0ID0gRmFsc2VcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgZGV0ZWN0aW9uX3JhdGlvID0gRmFsc2VcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGF0dHJpYnV0ZSBpbiBtaXNwX29iamVjdC5nZXQoXCJBdHRyaWJ1dGVcIiwgW10pOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgYXR0cmlidXRlLmdldChcIm9iamVjdF9yZWxhdGlvblwiKSA9PSBcInBlcm1hbGlua1wiIGFuZCB2YWx1ZSBpbiBhdHRyaWJ1dGUuZ2V0KFwidmFsdWVcIik6XG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0X3Z0X3JlcG9ydCA9IFRydWVcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGF0dHJpYnV0ZS5nZXQoXCJvYmplY3RfcmVsYXRpb25cIikgPT0gXCJkZXRlY3Rpb24tcmF0aW9cIjpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXRlY3Rpb25fcmF0aW8gPSBhdHRyaWJ1dGUuZ2V0KFwidmFsdWVcIilcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgaWYgZGV0ZWN0aW9uX3JhdGlvOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgZGlyZWN0X3Z0X3JlcG9ydDpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJkZXRlY3Rpb25fcmF0aW9cIl0uYXBwZW5kKGRldGVjdGlvbl9yYXRpbylcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludChcIiBHb3QgZGV0ZWN0aW9uIHJhdGlvIFxcMDMzWzkybXt9XFwwMzNbOTBtIFwiLmZvcm1hdChkZXRlY3Rpb25fcmF0aW8pKVxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJkZXRlY3Rpb25fcmF0aW9faW5kaXJlY3RcIl0uYXBwZW5kKGRldGVjdGlvbl9yYXRpbylcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludChcIiBHb3QgaW5kaXJlY3QgZGV0ZWN0aW9uIHJhdGlvIFxcMDMzWzkybXt9XFwwMzNbOTBtIFwiLmZvcm1hdChkZXRlY3Rpb25fcmF0aW8pKVxuIiwKICAgICIgICAgICAgICAgICAgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBwcmludChcIiBVbmFibGUgdG8gYWRkIFxcMDMzWzkybXt9XFwwMzNbOTBtIHRvIE1JU1AgZXZlbnRcIi5mb3JtYXQobWlzcF9vYmplY3RbXCJuYW1lXCJdKSlcbiIsCiAgICAiXG4iLAogICAgIiAgICAgICAgcmlzazEsIHRhZzEgPSBjYWxjdWxhdGVfcmlza19zY29yZShzYW1wbGUuZ2V0KFwiZGV0ZWN0aW9uX3JhdGlvXCIpKVxuIiwKICAgICIgICAgICAgIHJpc2syLCB0YWcyID0gY2FsY3VsYXRlX3Jpc2tfc2NvcmUoc2FtcGxlLmdldChcImRldGVjdGlvbl9yYXRpb19pbmRpcmVjdFwiKSlcbiIsCiAgICAiICAgICAgICBpZiBsZW4odGFnMSkgPiAwOlxuIiwKICAgICIgICAgICAgICAgICBtaXNwLnRhZyhzYW1wbGUuZ2V0KFwic2hhMjU2X3V1aWRcIiksIHRhZzEpXG4iLAogICAgIiAgICAgICAgICAgIG1pc3AudGFnKHNhbXBsZS5nZXQoXCJtYWx3YXJlLXNhbXBsZV91dWlkXCIpLCB0YWcxKVxuIiwKICAgICJcbiIsCiAgICAiICAgICAgICByaXNrX3JhdGluZyA9IFwidnQtZGV0ZWN0aW9uLXJhdGlvPXt9XFxudnQtZGV0ZWN0aW9uLXJhdGlvLWluZGlyZWN0PXt9XCIuZm9ybWF0KHJpc2sxLCByaXNrMilcbiIsCiAgICAiICAgICAgICBzYW1wbGVzW2tleV1bXCJkZXRlY3Rpb25fcmF0aW9fcGVyY1wiXSA9IHJpc2sxXG4iLAogICAgIiAgICAgICAgc2FtcGxlc1trZXldW1wiZGV0ZWN0aW9uX3JhdGlvX2luZGlyZWN0X3BlcmNcIl0gPSByaXNrMlxuIiwKICAgICIgICAgICAgIHNhbXBsZXNba2V5XVtcInJpc2tfcmF0aW5nXCJdID0gcmlza19yYXRpbmdcbiIsCiAgICAiICAgICAgICBzYW1wbGUuZ2V0KFwiZmlsZW9iamVjdFwiKS5hZGRfYXR0cmlidXRlKFwidGV4dFwiLCByaXNrX3JhdGluZylcbiIsCiAgICAiICAgICAgICBtaXNwLnVwZGF0ZV9vYmplY3Qoc2FtcGxlLmdldChcImZpbGVvYmplY3RcIikpXG4iLAogICAgIlxuIiwKICAgICIgICAgICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjXG4iLAogICAgIlxuIiwKICAgICIgICAgICAgIHByaW50KFwiIFF1ZXJ5IFZpcnVzVG90YWwgZGlyZWN0bHkgdG8gZ2V0IGZpbGUgZGV0YWlsc1wiKVxuIiwKICAgICIgICAgICAgIHZ0X3VybCA9IFwiaHR0cHM6Ly93d3cudmlydXN0b3RhbC5jb20vYXBpL3YzL2ZpbGVzL3t9XCIuZm9ybWF0KHZhbHVlKVxuIiwKICAgICIgICAgICAgIHJlc3VsdCA9IHJlcXVlc3RzLmdldCh2dF91cmwsIGhlYWRlcnM9aGVhZGVycylcbiIsCiAgICAiICAgICAgICBpZiBcImRhdGFcIiBpbiByZXN1bHQuanNvbigpIGFuZCBsZW4ocmVzdWx0Lmpzb24oKVtcImRhdGFcIl0pID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgcmVzdWx0X2pzb24gPSByZXN1bHQuanNvbigpW1wiZGF0YVwiXVtcImF0dHJpYnV0ZXNcIl1cbiIsCiAgICAiICAgICAgICAgICAgc2FtcGxlc1trZXldW1widnRcIl1bXCJkYXRhXCJdID0gcmVzdWx0X2pzb25cbiIsCiAgICAiICAgICAgICAgICAgc2FtcGxlc1trZXldW1widnRcIl1bXCJwb3B1bGFyX3RocmVhdF9jbGFzc2lmaWNhdGlvblwiXSA9IHJlc3VsdF9qc29uLmdldChcInBvcHVsYXJfdGhyZWF0X2NsYXNzaWZpY2F0aW9uXCIsIFtdKVxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcInNpZ21hX2FuYWx5c2lzX3Jlc3VsdHNcIl0gPSByZXN1bHRfanNvbi5nZXQoXCJzaWdtYV9hbmFseXNpc19yZXN1bHRzXCIsIFtdKVxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcInNhbmRib3hfdmVyZGljdHNcIl0gPSByZXN1bHRfanNvbi5nZXQoXCJzYW5kYm94X3ZlcmRpY3RzXCIsIFtdKVxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcInNhbmRib3hlc1wiXSA9IFtdXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcInZ0XCJdW1wibWFya2Rvd25cIl0gPSBcIlwiXG4iLAogICAgIlxuIiwKICAgICIgICAgICAgICAgICBpZiBsZW4oc2FtcGxlc1trZXldW1widnRcIl1bXCJwb3B1bGFyX3RocmVhdF9jbGFzc2lmaWNhdGlvblwiXSkgPiAwOlxuIiwKICAgICIgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1widnRcIl1bXCJtYXJrZG93blwiXSA9IFwiIyMjIyBQb3B1bGFyIHRocmVhdCBjbGFzc2lmaWNhdGlvbnNcXG5cIlxuIiwKICAgICIgICAgICAgICAgICAgICAgZm9yIGVsIGluIHNhbXBsZXNba2V5XVtcInZ0XCJdW1wicG9wdWxhcl90aHJlYXRfY2xhc3NpZmljYXRpb25cIl06XG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgaWYgZWwgPT0gXCJzdWdnZXN0ZWRfdGhyZWF0X2xhYmVsXCI6XG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcInZ0XCJdW1wic3VnZ2VzdGVkX3RocmVhdF9sYWJlbFwiXSA9IHNhbXBsZXNba2V5XVtcInZ0XCJdW1wicG9wdWxhcl90aHJlYXRfY2xhc3NpZmljYXRpb25cIl1bZWxdXG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1widnRcIl1bXCJtYXJrZG93blwiXSA9IFwie31cXG4tIHt9OiB7fVwiLmZvcm1hdChzYW1wbGVzW2tleV1bXCJ2dFwiXVtcIm1hcmtkb3duXCJdLCBlbCwgc2FtcGxlc1trZXldW1widnRcIl1bXCJwb3B1bGFyX3RocmVhdF9jbGFzc2lmaWNhdGlvblwiXVtlbF0pXG4iLAogICAgIlxuIiwKICAgICIgICAgICAgICAgICBpZiBsZW4oc2FtcGxlc1trZXldW1widnRcIl1bXCJzaWdtYV9hbmFseXNpc19yZXN1bHRzXCJdKSA+IDA6XG4iLAogICAgIiAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcIm1hcmtkb3duXCJdID0gXCJ7fVxcblxcbiMjIyMgU2lnbWEgYW5hbHlzaXMgcmVzdWx0c1xcblwiLmZvcm1hdChzYW1wbGVzW2tleV1bXCJ2dFwiXVtcIm1hcmtkb3duXCJdKVxuIiwKICAgICIgICAgICAgICAgICAgICAgZm9yIGVsIGluIHNhbXBsZXNba2V5XVtcInZ0XCJdW1wic2lnbWFfYW5hbHlzaXNfcmVzdWx0c1wiXTpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcIm1hcmtkb3duXCJdID0gXCJ7fVxcbiAtIHt9XCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcInZ0XCJdW1wibWFya2Rvd25cIl0sIGVsW1wicnVsZV90aXRsZVwiXSlcbiIsCiAgICAiXG4iLAogICAgIiAgICAgICAgICAgIGlmIGxlbihzYW1wbGVzW2tleV1bXCJ2dFwiXVtcInNhbmRib3hfdmVyZGljdHNcIl0pID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcInZ0XCJdW1wibWFya2Rvd25cIl0gPSBcInt9XFxuXFxuIyMjIyBTYW5kYm94IHZlcmRpY3RzXFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcInZ0XCJdW1wibWFya2Rvd25cIl0pXG4iLAogICAgIiAgICAgICAgICAgICAgICBmb3IgZWwgaW4gc2FtcGxlc1trZXldW1widnRcIl1bXCJzYW5kYm94X3ZlcmRpY3RzXCJdOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcInZ0XCJdW1wic2FuZGJveGVzXCJdLmFwcGVuZChlbClcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcIm1hcmtkb3duXCJdID0gXCJ7fVxcbiAtICoqe30qKlwiLmZvcm1hdChzYW1wbGVzW2tleV1bXCJ2dFwiXVtcIm1hcmtkb3duXCJdLCBlbClcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBmb3IgZWxfc2FuZGJveCBpbiBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcInNhbmRib3hfdmVyZGljdHNcIl1bZWxdOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJ2dFwiXVtcIm1hcmtkb3duXCJdID0gXCJ7fVxcbiAgIC0ge306IHt9XCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcInZ0XCJdW1wibWFya2Rvd25cIl0sIGVsX3NhbmRib3gsIHNhbXBsZXNba2V5XVtcInZ0XCJdW1wic2FuZGJveF92ZXJkaWN0c1wiXVtlbF1bZWxfc2FuZGJveF0pXG4iLAogICAgIiAgICAgICAgcHJpbnQoXCIgRmluaXNoZWQgcXVlcnkgVmlydXNUb3RhbCBkaXJlY3RseVwiKVxuIiwKICAgICIgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICBwcmludChcIk5vIHJlc3VsdHMgZm9yIFxcMDMzWzkxbXt9XFwwMzNbOTBtLlwiLmZvcm1hdCh2YWx1ZSkpXG4iLAogICAgIiAgICBzY2FuX2NvdW50ICs9IDFcbiIsCiAgICAiICAgIGlmIHNjYW5fY291bnQgPiA1OlxuIiwKICAgICIgICAgICAgIHByaW50KFwiU2xlZXBpbmcgZm9yIHt9IHNlY29uZHNcIi5mb3JtYXQobWlzcF9tb2R1bGVzX3dhaXQpKVxuIiwKICAgICIgICAgICAgIHRpbWUuc2xlZXAobWlzcF9tb2R1bGVzX3dhaXQpXG4iLAogICAgIiAgICAgICAgc2Nhbl9jb3VudCA9IDBcbiIsCiAgICAicHJpbnQoXCJGaW5pc2hlZCB7fVwiLmZvcm1hdChtb2R1bGVfbmFtZSkpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiZGI5M2Q1OTgtM2Q3NS00N2UzLTg5MGEtNGQ4MjU0NWE0MzExIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgSU46MyBIYXNobG9va3VwXG4iLAogICAgIlxuIiwKICAgICJXZSB1c2UgW0NJUkNMIEhhc2hsb29rdXBdKGh0dHBzOi8vd3d3LmNpcmNsLmx1L3NlcnZpY2VzL2hhc2hsb29rdXAvKSB0byBpZGVudGlmeSBpZiBhbnkgb2YgdGhlIHNhbXBsZXMgY29ycmVzcG9uZCB3aXRoICoqa25vd24gaGFzaGVzKiouIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAiY29kZSIsCiAgICJleGVjdXRpb25fY291bnQiOiBudWxsLAogICAiaWQiOiAiOWY5MDgyYWUtYmExOC00NTMyLWI1MDAtMzU1YzgyNWRmMWYzIiwKICAgIm1ldGFkYXRhIjogewogICAgInRhZ3MiOiBbXQogICB9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogWwogICAgIiMgTG9vcCB0aHJvdWdoIHRoZSBzYW1wbGVzXG4iLAogICAgIlxuIiwKICAgICJtb2R1bGVfbmFtZSA9IFwiaGFzaGxvb2t1cFwiXG4iLAogICAgInByaW50KFwiTG9va3VwIHRoZSBmaWxlIGluIHt9XCIuZm9ybWF0KG1vZHVsZV9uYW1lKSlcbiIsCiAgICAiZm9yIGtleSwgc2FtcGxlIGluIHNhbXBsZXMuaXRlbXMoKTpcbiIsCiAgICAiICAgIGF0dHJpYnV0ZV90eXBlID0gXCJzaGEyNTZcIlxuIiwKICAgICIgICAgdmFsdWUgPSBzYW1wbGUuZ2V0KFwic2hhMjU2XCIpXG4iLAogICAgIiAgICBtb2R1bGVfY29tbWVudCA9IFwiRnJvbSB7fSBmb3Ige31cIi5mb3JtYXQobW9kdWxlX25hbWUsIGtleSlcbiIsCiAgICAiICAgIGRhdGEgPSB7XG4iLAogICAgIiAgICAgICAgXCJhdHRyaWJ1dGVcIjoge1xuIiwKICAgICIgICAgICAgICAgICBcInR5cGVcIjogZlwie2F0dHJpYnV0ZV90eXBlfVwiLFxuIiwKICAgICIgICAgICAgICAgICBcInV1aWRcIjogc3RyKHV1aWQudXVpZDQoKSksXG4iLAogICAgIiAgICAgICAgICAgIFwidmFsdWVcIjogZlwie3ZhbHVlfVwiLFxuIiwKICAgICIgICAgICAgIH0sXG4iLAogICAgIiAgICAgICAgXCJtb2R1bGVcIjogbW9kdWxlX25hbWUsXG4iLAogICAgIiAgICAgICAgXCJjb25maWdcIjoge1wiY3VzdG9tX0FQSVwiOiBGYWxzZX1cbiIsCiAgICAiICAgIH1cbiIsCiAgICAiICAgIHByaW50KFwiUXVlcnkgXFwwMzNbOTJte31cXDAzM1s5MG0gYXMgXFwwMzNbOTJte31cXDAzM1s5MG1cIi5mb3JtYXQodmFsdWUsIGF0dHJpYnV0ZV90eXBlKSlcbiIsCiAgICAiICAgIHJlc3VsdCA9IHJlcXVlc3RzLnBvc3QoXCJ7fS9xdWVyeVwiLmZvcm1hdChtaXNwX21vZHVsZXNfdXJsKSwgaGVhZGVycz1taXNwX21vZHVsZXNfaGVhZGVycywganNvbj1kYXRhKVxuIiwKICAgICIgICAgaWYgXCJyZXN1bHRzXCIgaW4gcmVzdWx0Lmpzb24oKSBhbmQgbGVuKHJlc3VsdC5qc29uKClbXCJyZXN1bHRzXCJdKSA+IDA6XG4iLAogICAgIiAgICAgICAgcmVzdWx0X2pzb24gPSByZXN1bHQuanNvbigpW1wicmVzdWx0c1wiXVxuIiwKICAgICIgICAgICAgIGhhc2hsb29rdXBfaGl0ID0gRmFsc2VcbiIsCiAgICAiICAgICAgICBoYXNobG9va3VwdGV4dCA9IFwiXCJcbiIsCiAgICAiICAgICAgICBmb3IgbWlzcF9hdHRyaWJ1dGUgaW4gcmVzdWx0X2pzb24uZ2V0KFwiQXR0cmlidXRlXCIsIFtdKTpcbiIsCiAgICAiICAgICAgICAgICAgbWlzcF9hdHRyaWJ1dGVbXCJjb21tZW50XCJdID0gXCJ7fXt9XCIuZm9ybWF0KG1vZHVsZV9jb21tZW50LCBtaXNwX2F0dHJpYnV0ZS5nZXQoXCJjb21tZW50XCIsIFwiXCIpKVxuIiwKICAgICIgICAgICAgICAgICBjcmVhdGVkX2F0dHJpYnV0ZSA9IG1pc3AuYWRkX2F0dHJpYnV0ZShtaXNwX2V2ZW50LnV1aWQsIG1pc3BfYXR0cmlidXRlLCBweXRob25pZnk9VHJ1ZSlcbiIsCiAgICAiICAgICAgICAgICAgaWYgbm90IFwiZXJyb3JzXCIgaW4gY3JlYXRlZF9hdHRyaWJ1dGU6XG4iLAogICAgIiAgICAgICAgICAgICAgICBwcmludChcIiBHb3Qge30gXFwwMzNbOTJte31cXDAzM1s5MG1cIi5mb3JtYXQobWlzcF9hdHRyaWJ1dGVbXCJ0eXBlXCJdLCBtaXNwX2F0dHJpYnV0ZVtcInZhbHVlXCJdKSlcbiIsCiAgICAiICAgICAgICAgICAgICAgIG1pc3AuYWRkX29iamVjdF9yZWZlcmVuY2Uoc2FtcGxlLmdldChcImZpbGVvYmplY3RcIikuYWRkX3JlZmVyZW5jZShjcmVhdGVkX2F0dHJpYnV0ZS51dWlkLCBcInJlbGF0ZWQtdG9cIikpXG4iLAogICAgIiAgICAgICAgICAgIGVsc2U6XG4iLAogICAgIiAgICAgICAgICAgICAgICBwcmludChcIiBVbmFibGUgdG8gYWRkIHt9IFxcMDMzWzkybXt9XFwwMzNbOTBtIHRvIE1JU1AgZXZlbnRcIi5mb3JtYXQobWlzcF9hdHRyaWJ1dGVbXCJ0eXBlXCJdLCBtaXNwX2F0dHJpYnV0ZVtcInZhbHVlXCJdKSlcbiIsCiAgICAiICAgICAgICBmb3IgbWlzcF9vYmplY3QgaW4gcmVzdWx0X2pzb24uZ2V0KFwiT2JqZWN0XCIsIFtdKTpcbiIsCiAgICAiICAgICAgICAgICAgbWlzcF9vYmplY3RbXCJjb21tZW50XCJdID0gXCJ7fXt9XCIuZm9ybWF0KG1vZHVsZV9jb21tZW50LCBtaXNwX29iamVjdC5nZXQoXCJjb21tZW50XCIsIFwiXCIpKVxuIiwKICAgICIgICAgICAgICAgICBpZiBsZW4obWlzcF9vYmplY3RbXCJBdHRyaWJ1dGVcIl0pID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgICAgIGNyZWF0ZWRfb2JqZWN0ID0gbWlzcC5hZGRfb2JqZWN0KG1pc3BfZXZlbnQudXVpZCwgbWlzcF9vYmplY3QsIHB5dGhvbmlmeT1UcnVlKVxuIiwKICAgICIgICAgICAgICAgICAgICAgaWYgbm90IFwiZXJyb3JzXCIgaW4gY3JlYXRlZF9vYmplY3Q6XG4iLAogICAgIlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIHByaW50KFwiIEdvdCBcXDAzM1s5Mm17fVxcMDMzWzkwbSBcIi5mb3JtYXQobWlzcF9vYmplY3RbXCJuYW1lXCJdKSlcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBtaXNwLmFkZF9vYmplY3RfcmVmZXJlbmNlKHNhbXBsZS5nZXQoXCJmaWxlb2JqZWN0XCIpLmFkZF9yZWZlcmVuY2UoY3JlYXRlZF9vYmplY3QudXVpZCwgXCJyZWxhdGVkLXRvXCIpKVxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIGZvciBhdHRyaWJ1dGUgaW4gbWlzcF9vYmplY3QuZ2V0KFwiQXR0cmlidXRlXCIsIFtdKTpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgaWYgYXR0cmlidXRlW1wib2JqZWN0X3JlbGF0aW9uXCJdIG5vdCBpbiBbXCJNRDVcIiwgXCJTSEEtMVwiLCBcIlNIQS0yNTZcIiwgXCJTU0RFRVBcIl06XG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNobG9va3VwdGV4dCA9IFwie306IHt9XFxue31cIi5mb3JtYXQoYXR0cmlidXRlW1wib2JqZWN0X3JlbGF0aW9uXCJdLCBhdHRyaWJ1dGVbXCJ2YWx1ZVwiXSwgaGFzaGxvb2t1cHRleHQpXG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgICAgIGlmIGF0dHJpYnV0ZS5nZXQoXCJvYmplY3RfcmVsYXRpb25cIikgPT0gXCJLbm93bk1hbGljaW91c1wiOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzaGxvb2t1cF9oaXQgPSBUcnVlXG4iLAogICAgIiAgICAgICAgICAgICAgICBlbHNlOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIHByaW50KFwiIFVuYWJsZSB0byBhZGQgXFwwMzNbOTJte31cXDAzM1s5MG0gdG8gTUlTUCBldmVudFwiLmZvcm1hdChtaXNwX29iamVjdFtcIm5hbWVcIl0pKVxuIiwKICAgICJcbiIsCiAgICAiICAgICAgICBpZiBoYXNobG9va3VwX2hpdDpcbiIsCiAgICAiICAgICAgICAgICAgbWlzcC50YWcoc2FtcGxlLmdldChcInNoYTI1Nl91dWlkXCIpLCBcIm1pc3Atd29ya2Zsb3c6YW5hbHlzaXM9XFxcImtub3duLWZpbGUtaGFzaFxcXCJcIilcbiIsCiAgICAiICAgICAgICAgICAgbWlzcC50YWcoc2FtcGxlLmdldChcIm1hbHdhcmUtc2FtcGxlX3V1aWRcIiksIFwibWlzcC13b3JrZmxvdzphbmFseXNpcz1cXFwia25vd24tZmlsZS1oYXNoXFxcIlwiKVxuIiwKICAgICJcbiIsCiAgICAiICAgICAgICBzYW1wbGUuZ2V0KFwiZmlsZW9iamVjdFwiKS5hZGRfYXR0cmlidXRlKFwidGV4dFwiLCBoYXNobG9va3VwdGV4dClcbiIsCiAgICAiICAgICAgICBzYW1wbGVzW2tleV1bXCJoYXNobG9va3VwXCJdW1wiZGF0YVwiXSA9IHJlc3VsdF9qc29uXG4iLAogICAgIiAgICAgICAgc2FtcGxlc1trZXldW1wiaGFzaGxvb2t1cFwiXVtcIm1hcmtkb3duXCJdID0gaGFzaGxvb2t1cHRleHRcbiIsCiAgICAiICAgICAgICBtaXNwLnVwZGF0ZV9vYmplY3Qoc2FtcGxlLmdldChcImZpbGVvYmplY3RcIikpXG4iLAogICAgIiAgICBlbHNlOlxuIiwKICAgICIgICAgICAgIHByaW50KFwiTm8gcmVzdWx0cyBmb3IgXFwwMzNbOTFte31cXDAzM1s5MG0uXCIuZm9ybWF0KHZhbHVlKSlcbiIsCiAgICAicHJpbnQoXCJGaW5pc2hlZCB7fVwiLmZvcm1hdChtb2R1bGVfbmFtZSkpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiZmM0OTZmYWUtOGNlNi00NWI1LWI5YWItOWU1NjFiYTk5MzEyIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgSU46NCBNYWx3YXJlQmF6YWFyXG4iLAogICAgIlxuIiwKICAgICJOb3cgd2UgcXVlcnkgW01hbHdhcmVCYXphYXJdKGh0dHBzOi8vYmF6YWFyLmFidXNlLmNoLykuIFNpbWlsYXIgYXMgd2l0aCBWaXJ1c1RvdGFsLCB3ZSB1c2UgdGhlIE1JU1AgbW9kdWxlIHRvIGdldCB1c2VmdWwgYXR0cmlidXRlcyBhbmQgb2JqZWN0cy4gQWZ0ZXJ3YXJkcyB3ZSBxdWVyeSBNYWx3YXJlQmF6YWFyIGRpcmVjdGx5IHRvIGdldCBtb3JlIGRldGFpbHMgc3VjaCBhcyB2ZW5kb3IgaW50ZWwgYW5kIHRhZ3MuIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAiY29kZSIsCiAgICJleGVjdXRpb25fY291bnQiOiBudWxsLAogICAiaWQiOiAiZmEzZTIzNmEtOTRjZi00MWZmLTg4YjAtNmI1NWFlYjE4NjU1IiwKICAgIm1ldGFkYXRhIjogewogICAgInRhZ3MiOiBbXQogICB9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogWwogICAgIiMgTG9vcCB0aHJvdWdoIHRoZSBzYW1wbGVzXG4iLAogICAgIlxuIiwKICAgICJtb2R1bGVfbmFtZSA9IFwibWFsd2FyZWJhemFhclwiXG4iLAogICAgInByaW50KFwiTG9va3VwIHRoZSBmaWxlIGluIHt9XCIuZm9ybWF0KG1vZHVsZV9uYW1lKSlcbiIsCiAgICAiZm9yIGtleSwgc2FtcGxlIGluIHNhbXBsZXMuaXRlbXMoKTpcbiIsCiAgICAiICAgIGF0dHJpYnV0ZV90eXBlID0gXCJzaGEyNTZcIlxuIiwKICAgICIgICAgdmFsdWUgPSBzYW1wbGUuZ2V0KFwic2hhMjU2XCIpXG4iLAogICAgIiAgICBtb2R1bGVfY29tbWVudCA9IFwiRnJvbSB7fSBmb3Ige31cIi5mb3JtYXQobW9kdWxlX25hbWUsIGtleSlcbiIsCiAgICAiICAgIGRhdGEgPSB7XG4iLAogICAgIiAgICAgICAgXCJhdHRyaWJ1dGVcIjoge1xuIiwKICAgICIgICAgICAgICAgICBcInR5cGVcIjogZlwie2F0dHJpYnV0ZV90eXBlfVwiLFxuIiwKICAgICIgICAgICAgICAgICBcInV1aWRcIjogc3RyKHV1aWQudXVpZDQoKSksXG4iLAogICAgIiAgICAgICAgICAgIFwidmFsdWVcIjogZlwie3ZhbHVlfVwiLFxuIiwKICAgICIgICAgICAgIH0sXG4iLAogICAgIiAgICAgICAgXCJtb2R1bGVcIjogbW9kdWxlX25hbWUsXG4iLAogICAgIiAgICB9XG4iLAogICAgIiAgICBwcmludChcIlF1ZXJ5IFxcMDMzWzkybXt9XFwwMzNbOTBtIGFzIFxcMDMzWzkybXt9XFwwMzNbOTBtXCIuZm9ybWF0KHZhbHVlLCBhdHRyaWJ1dGVfdHlwZSkpXG4iLAogICAgIiAgICByZXN1bHQgPSByZXF1ZXN0cy5wb3N0KFwie30vcXVlcnlcIi5mb3JtYXQobWlzcF9tb2R1bGVzX3VybCksIGhlYWRlcnM9bWlzcF9tb2R1bGVzX2hlYWRlcnMsIGpzb249ZGF0YSlcbiIsCiAgICAiICAgIGlmIFwicmVzdWx0c1wiIGluIHJlc3VsdC5qc29uKCkgYW5kIGxlbihyZXN1bHQuanNvbigpW1wicmVzdWx0c1wiXSkgPiAwOlxuIiwKICAgICIgICAgICAgIHJlc3VsdF9qc29uID0gcmVzdWx0Lmpzb24oKVtcInJlc3VsdHNcIl1cbiIsCiAgICAiICAgICAgICBmb3IgbWlzcF9hdHRyaWJ1dGUgaW4gcmVzdWx0X2pzb24uZ2V0KFwiQXR0cmlidXRlXCIsIFtdKTpcbiIsCiAgICAiICAgICAgICAgICAgbWlzcF9hdHRyaWJ1dGVbXCJjb21tZW50XCJdID0gXCJ7fXt9XCIuZm9ybWF0KG1vZHVsZV9jb21tZW50LCBtaXNwX2F0dHJpYnV0ZS5nZXQoXCJjb21tZW50XCIsIFwiXCIpKVxuIiwKICAgICIgICAgICAgICAgICBjcmVhdGVkX2F0dHJpYnV0ZSA9IG1pc3AuYWRkX2F0dHJpYnV0ZShtaXNwX2V2ZW50LnV1aWQsIG1pc3BfYXR0cmlidXRlLCBweXRob25pZnk9VHJ1ZSlcbiIsCiAgICAiICAgICAgICAgICAgaWYgbm90IFwiZXJyb3JzXCIgaW4gY3JlYXRlZF9hdHRyaWJ1dGU6XG4iLAogICAgIiAgICAgICAgICAgICAgICBwcmludChcIiBHb3Qge30gXFwwMzNbOTJte31cXDAzM1s5MG1cIi5mb3JtYXQobWlzcF9hdHRyaWJ1dGVbXCJ0eXBlXCJdLCBtaXNwX2F0dHJpYnV0ZVtcInZhbHVlXCJdKSlcbiIsCiAgICAiICAgICAgICAgICAgICAgIG1pc3AuYWRkX29iamVjdF9yZWZlcmVuY2Uoc2FtcGxlLmdldChcImZpbGVvYmplY3RcIikuYWRkX3JlZmVyZW5jZShjcmVhdGVkX2F0dHJpYnV0ZS51dWlkLCBcInJlbGF0ZWQtdG9cIikpXG4iLAogICAgIiAgICAgICAgICAgIGVsc2U6XG4iLAogICAgIiAgICAgICAgICAgICAgICBwcmludChcIiBVbmFibGUgdG8gYWRkIHt9IFxcMDMzWzkybXt9XFwwMzNbOTBtIHRvIE1JU1AgZXZlbnRcIi5mb3JtYXQobWlzcF9hdHRyaWJ1dGVbXCJ0eXBlXCJdLCBtaXNwX2F0dHJpYnV0ZVtcInZhbHVlXCJdKSlcbiIsCiAgICAiICAgICAgICBmb3IgbWlzcF9vYmplY3QgaW4gcmVzdWx0X2pzb24uZ2V0KFwiT2JqZWN0XCIsIFtdKTpcbiIsCiAgICAiICAgICAgICAgICAgbWlzcF9vYmplY3RbXCJjb21tZW50XCJdID0gXCJ7fXt9XCIuZm9ybWF0KG1vZHVsZV9jb21tZW50LCBtaXNwX29iamVjdC5nZXQoXCJjb21tZW50XCIsIFwiXCIpKVxuIiwKICAgICIgICAgICAgICAgICBpZiBsZW4obWlzcF9vYmplY3RbXCJBdHRyaWJ1dGVcIl0pID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgICAgIGNyZWF0ZWRfb2JqZWN0ID0gbWlzcC5hZGRfb2JqZWN0KG1pc3BfZXZlbnQudXVpZCwgbWlzcF9vYmplY3QsIHB5dGhvbmlmeT1UcnVlKVxuIiwKICAgICIgICAgICAgICAgICAgICAgaWYgbm90IFwiZXJyb3JzXCIgaW4gY3JlYXRlZF9vYmplY3Q6XG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgcHJpbnQoXCIgR290IFxcMDMzWzkybXt9XFwwMzNbOTBtIFwiLmZvcm1hdChtaXNwX29iamVjdFtcIm5hbWVcIl0pKVxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIG1pc3AuYWRkX29iamVjdF9yZWZlcmVuY2Uoc2FtcGxlLmdldChcImZpbGVvYmplY3RcIikuYWRkX3JlZmVyZW5jZShjcmVhdGVkX29iamVjdC51dWlkLCBcInJlbGF0ZWQtdG9cIikpXG4iLAogICAgIiAgICAgICAgICAgICAgICBlbHNlOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIHByaW50KFwiIFVuYWJsZSB0byBhZGQgXFwwMzNbOTJte31cXDAzM1s5MG0gdG8gTUlTUCBldmVudFwiLmZvcm1hdChtaXNwX29iamVjdFtcIm5hbWVcIl0pKVxuIiwKICAgICJcbiIsCiAgICAiICAgICAgICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI1xuIiwKICAgICJcbiIsCiAgICAiICAgICAgICBwcmludChcIiBRdWVyeSBNYWx3YXJlQmF6YWFyIGRpcmVjdGx5IHRvIGdldCBmaWxlIGRldGFpbHNcIilcbiIsCiAgICAiICAgICAgICB1cmwgPSBcImh0dHBzOi8vbWItYXBpLmFidXNlLmNoL2FwaS92MS9cIlxuIiwKICAgICIgICAgICAgIHJlc3VsdCA9IHJlcXVlc3RzLnBvc3QodXJsLCBkYXRhPXtcInF1ZXJ5XCI6IFwiZ2V0X2luZm9cIiwgXCJoYXNoXCI6IHZhbHVlfSlcbiIsCiAgICAiICAgICAgICBpZiBcImRhdGFcIiBpbiByZXN1bHQuanNvbigpIGFuZCBsZW4ocmVzdWx0Lmpzb24oKVtcImRhdGFcIl0pID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgcmVzdWx0X2pzb24gPSByZXN1bHQuanNvbigpW1wiZGF0YVwiXVswXVxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJtYWx3YXJlYmF6YWFyXCJdW1wibWFya2Rvd25cIl0gPSBcIlwiXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcIm1hbHdhcmViYXphYXJcIl1bXCJkYXRhXCJdID0gcmVzdWx0X2pzb25cbiIsCiAgICAiICAgICAgICAgICAgc2FtcGxlc1trZXldW1wibWFsd2FyZWJhemFhclwiXVtcInRhZ3NcIl0gPSByZXN1bHRfanNvbi5nZXQoXCJ0YWdzXCIsIFwiXCIpXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcIm1hbHdhcmViYXphYXJcIl1bXCJzaWduYXR1cmVcIl0gPSByZXN1bHRfanNvbi5nZXQoXCJzaWduYXR1cmVcIiwgXCJcIilcbiIsCiAgICAiXG4iLAogICAgIiAgICAgICAgICAgIGlmIGxlbihzYW1wbGVzW2tleV1bXCJtYWx3YXJlYmF6YWFyXCJdW1widGFnc1wiXSkgPiAwOlxuIiwKICAgICIgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wibWFsd2FyZWJhemFhclwiXVtcIm1hcmtkb3duXCJdID0gXCJ7fVxcbioqVGFncyoqXFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcIm1hbHdhcmViYXphYXJcIl1bXCJtYXJrZG93blwiXSlcbiIsCiAgICAiICAgICAgICAgICAgICAgIGZvciB0YWcgaW4gc2FtcGxlc1trZXldW1wibWFsd2FyZWJhemFhclwiXVtcInRhZ3NcIl06XG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wibWFsd2FyZWJhemFhclwiXVtcIm1hcmtkb3duXCJdID0gXCJ7fVxcbiAtIHt9XFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcIm1hbHdhcmViYXphYXJcIl1bXCJtYXJrZG93blwiXSwgdGFnKVxuIiwKICAgICJcbiIsCiAgICAiICAgICAgICAgICAgaWYgbGVuKHJlc3VsdF9qc29uLmdldChcInZlbmRvcl9pbnRlbFwiLCBbXSkpID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgICAgIGlmIGxlbihyZXN1bHRfanNvbi5nZXQoXCJ2ZW5kb3JfaW50ZWxcIiwgW10pLmdldChcIlRyaWFnZVwiLCBbXSkpID4gMDpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJtYWx3YXJlYmF6YWFyXCJdW1wibWFya2Rvd25cIl0gPSBcInt9XFxuKipUcmlhZ2UgdGFncyBhbmQgc2lnbmF0dXJlcyoqXFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcIm1hbHdhcmViYXphYXJcIl1bXCJtYXJrZG93blwiXSlcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICBmb3IgdGFnIGluIHJlc3VsdF9qc29uLmdldChcInZlbmRvcl9pbnRlbFwiLCBbXSkuZ2V0KFwiVHJpYWdlXCIsIFtdKS5nZXQoXCJ0YWdzXCIsIFtdKTpcbiIsCiAgICAiICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wibWFsd2FyZWJhemFhclwiXVtcIm1hcmtkb3duXCJdID0gXCJ7fVxcbiAtIHt9XFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcIm1hbHdhcmViYXphYXJcIl1bXCJtYXJrZG93blwiXSwgdGFnKVxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgIGZvciBzaWduYXR1cmUgaW4gcmVzdWx0X2pzb24uZ2V0KFwidmVuZG9yX2ludGVsXCIsIFtdKS5nZXQoXCJUcmlhZ2VcIiwgW10pLmdldChcInNpZ25hdHVyZXNcIiwgW10pOlxuIiwKICAgICIgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJtYWx3YXJlYmF6YWFyXCJdW1wibWFya2Rvd25cIl0gPSBcInt9XFxuIC0ge31cXG5cIi5mb3JtYXQoc2FtcGxlc1trZXldW1wibWFsd2FyZWJhemFhclwiXVtcIm1hcmtkb3duXCJdLCBzaWduYXR1cmVbXCJzaWduYXR1cmVcIl0pXG4iLAogICAgIiAgICAgICAgcHJpbnQoXCIgRmluaXNoZWQgcXVlcnkgTWFsd2FyZUJhemFhciBkaXJlY3RseVwiKVxuIiwKICAgICIgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICBwcmludChcIk5vIHJlc3VsdHMgZm9yIFxcMDMzWzkxbXt9XFwwMzNbOTBtLlwiLmZvcm1hdCh2YWx1ZSkpXG4iLAogICAgInByaW50KFwiRmluaXNoZWQge31cIi5mb3JtYXQobW9kdWxlX25hbWUpKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjczY2E4OTdhLTUyZjItNDNhNS04ZTliLWUyNmQzN2EzNjI5OCIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIElOOjUgUEUgaW1wb3J0cyBhbmQgZXhwb3J0c1xuIiwKICAgICJcbiIsCiAgICAiTmV4dCB3ZSB1c2UgYHBlZmlsZWAgdG8gYW5hbHlzZSB0aGUgKippbXBvcnRzIGFuZCBleHBvcnRzKiouIFRoZSByZXN1bHRzIGFyZSBhZGRlZCBhcyBhICoqTUlTUCByZXBvcnQqKi4iCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJjb2RlIiwKICAgImV4ZWN1dGlvbl9jb3VudCI6IG51bGwsCiAgICJpZCI6ICIxNWVhNjlmMS1lZTMyLTQyNDMtYjAzZS04M2M3ZmQxNTVmY2YiLAogICAibWV0YWRhdGEiOiB7CiAgICAidGFncyI6IFtdCiAgIH0sCiAgICJvdXRwdXRzIjogW10sCiAgICJzb3VyY2UiOiBbCiAgICAic3VtbWFyeV9wZSA9IFwiIyMgUEVGaWxlIHN1bW1hcnlcXG5cXG5cIlxuIiwKICAgICJwcmludChcIlVzaW5nIHBlZmlsZVwiKVxuIiwKICAgICJmb3Iga2V5LCBzYW1wbGUgaW4gc2FtcGxlcy5pdGVtcygpOlxuIiwKICAgICIgICAgc3VtbWFyeV9wZSArPSBcIiMjIHt9XFxuXFxuXCIuZm9ybWF0KHNhbXBsZVtcInBhdGhcIl0pXG4iLAogICAgIlxuIiwKICAgICIgICAgdHJ5OlxuIiwKICAgICIgICAgICAgIHBlID0gcGVmaWxlLlBFKHNhbXBsZVtcInBhdGhcIl0pXG4iLAogICAgIiAgICAgICAgc2FtcGxlc1trZXldW1wicGVcIl1bXCJpbXBvcnRzXCJdID0gXCIjIyMgSW1wb3J0c1xcblxcblwiXG4iLAogICAgIiAgICAgICAgc2FtcGxlc1trZXldW1wicGVcIl1bXCJleHBvcnRzXCJdID0gXCIjIyMgRXhwb3J0c1xcblxcblwiXG4iLAogICAgIiAgICAgICAgcGUucGFyc2VfZGF0YV9kaXJlY3RvcmllcygpXG4iLAogICAgIlxuIiwKICAgICIgICAgICAgIHByaW50KFwiIFJlYWRpbmcgaW1wb3J0cyBmb3Ige31cIi5mb3JtYXQoc2FtcGxlW1wicGF0aFwiXSkpXG4iLAogICAgIiAgICAgICAgdHJ5OlxuIiwKICAgICIgICAgICAgICAgICBmb3IgZW50cnkgaW4gcGUuRElSRUNUT1JZX0VOVFJZX0lNUE9SVDpcbiIsCiAgICAiICAgICAgICAgICAgICAgICNwcmludChcIiAge31cIi5mb3JtYXQoZW50cnkuZGxsKSlcbiIsCiAgICAiICAgICAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcInBlXCJdW1wiaW1wb3J0c1wiXSA9IFwie31cXG4qKnt9KipcXG5cIi5mb3JtYXQoc2FtcGxlc1trZXldW1wicGVcIl1bXCJpbXBvcnRzXCJdLCBlbnRyeS5kbGwpXG4iLAogICAgIiAgICAgICAgICAgICAgICBmb3IgaW1wIGluIGVudHJ5LmltcG9ydHM6XG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wicGVcIl1bXCJpbXBvcnRzXCJdID0gXCJ7fVxcbiAtIHt9IHt9XFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcInBlXCJdW1wiaW1wb3J0c1wiXSwgaGV4KGltcC5hZGRyZXNzKSwgaW1wLm5hbWUpXG4iLAogICAgIiAgICAgICAgZXhjZXB0OlxuIiwKICAgICIgICAgICAgICAgICBwcmludChcIiAgTm8gaW1wb3J0c1wiKVxuIiwKICAgICIgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJwZVwiXVtcImltcG9ydHNcIl0gPSBcInt9XFxuICpObyBpbXBvcnRzKlxcblwiLmZvcm1hdChzYW1wbGVzW2tleV1bXCJwZVwiXVtcImltcG9ydHNcIl0pXG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9wZSArPSBzYW1wbGVzW2tleV1bXCJwZVwiXVtcImltcG9ydHNcIl1cbiIsCiAgICAiXG4iLAogICAgIiAgICAgICAgcHJpbnQoXCIgUmVhZGluZyBleHBvcnRzIGZvciB7fVwiLmZvcm1hdChzYW1wbGVbXCJwYXRoXCJdKSlcbiIsCiAgICAiICAgICAgICB0cnk6XG4iLAogICAgIiAgICAgICAgICAgIGZvciBleHAgaW4gcGUuRElSRUNUT1JZX0VOVFJZX0VYUE9SVC5zeW1ib2xzOlxuIiwKICAgICIgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wicGVcIl1bXCJleHBvcnRzXCJdID0gXCJ7fVxcbiAtIHt9IHt9IHt9XFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcInBlXCJdW1wiZXhwb3J0c1wiXSwgaGV4KHBlLk9QVElPTkFMX0hFQURFUi5JbWFnZUJhc2UgKyBleHAuYWRkcmVzcyksIGV4cC5uYW1lLCBleHAub3JkaW5hbClcbiIsCiAgICAiICAgICAgICBleGNlcHQ6XG4iLAogICAgIiAgICAgICAgICAgIHByaW50KFwiICBObyBleHBvcnRzXCIpXG4iLAogICAgIiAgICAgICAgICAgIHNhbXBsZXNba2V5XVtcInBlXCJdW1wiZXhwb3J0c1wiXSA9IFwie31cXG4gKk5vIGV4cG9ydHMqXFxuXCIuZm9ybWF0KHNhbXBsZXNba2V5XVtcInBlXCJdW1wiZXhwb3J0c1wiXSlcbiIsCiAgICAiICAgICAgICBzdW1tYXJ5X3BlICs9IHNhbXBsZXNba2V5XVtcInBlXCJdW1wiaW1wb3J0c1wiXVxuIiwKICAgICIgICAgZXhjZXB0OlxuIiwKICAgICIgICAgICAgIHByaW50KFwiIFxcMDMzWzkxbVBFRm9ybWF0RXJyb3JcXDAzM1s5MG0gZm9yIHt9XFxuXCIuZm9ybWF0KHNhbXBsZVtcInBhdGhcIl0pKVxuIiwKICAgICIgICAgICAgIHN1bW1hcnlfcGUgKz0gXCJcXG4qUEVGb3JtYXRFcnJvcipcXG5cIlxuIiwKICAgICJcbiIsCiAgICAiZXZlbnRfdGl0bGUgPSBcIlBFRmlsZSBhbmFseXNpc1wiXG4iLAogICAgInByaW50KFwiXFxuQ3JlYXRpbmcgTUlTUCByZXBvcnQgXFwwMzNbOTJte31cXDAzM1s5MG1cIi5mb3JtYXQoZXZlbnRfdGl0bGUpKVxuIiwKICAgICJjaHVua19zaXplID0gNjE1MDBcbiIsCiAgICAiZm9yIGkgaW4gcmFuZ2UoMCwgbGVuKHN1bW1hcnlfcGUpLCBjaHVua19zaXplKTpcbiIsCiAgICAiICAgIGNodW5rID0gc3VtbWFyeV9wZVtpOmkgKyBjaHVua19zaXplXVxuIiwKICAgICIgICAgZXZlbnRfcmVwb3J0ID0gTUlTUEV2ZW50UmVwb3J0KClcbiIsCiAgICAiICAgIGV2ZW50X3RpdGxlX2VkaXQgPSBldmVudF90aXRsZVxuIiwKICAgICIgICAgaWYgaSA+IDA6XG4iLAogICAgIiAgICAgICAgZXZlbnRfdGl0bGVfZWRpdCA9IFwie30gKHt9ID4ge30pXCIuZm9ybWF0KGV2ZW50X3RpdGxlLCBpLCBpICsgY2h1bmtfc2l6ZSlcbiIsCiAgICAiICAgIGV2ZW50X3JlcG9ydC5uYW1lID0gZXZlbnRfdGl0bGVfZWRpdFxuIiwKICAgICIgICAgZXZlbnRfcmVwb3J0LmNvbnRlbnQgPSBjaHVua1xuIiwKICAgICIgICAgcmVzdWx0ID0gbWlzcC5hZGRfZXZlbnRfcmVwb3J0KG1pc3BfZXZlbnQuaWQsIGV2ZW50X3JlcG9ydClcbiIsCiAgICAiICAgIGlmIFwiRXZlbnRSZXBvcnRcIiBpbiByZXN1bHQ6XG4iLAogICAgIiAgICAgICAgcHJpbnQoXCIgUmVwb3J0IElEOiBcXDAzM1s5Mm17fVxcMDMzWzkwbVwiLmZvcm1hdChyZXN1bHQuZ2V0KFwiRXZlbnRSZXBvcnRcIiwgW10pLmdldChcImlkXCIsIDApKSlcbiIsCiAgICAiICAgIGVsc2U6XG4iLAogICAgIiAgICAgICAgcHJpbnQoXCJGYWlsZWQgdG8gY3JlYXRlIHJlcG9ydCBmb3IgXFwwMzNbOTFte31cXDAzM1s5MG0uXCIuZm9ybWF0KGV2ZW50X3RpdGxlKSkiCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJtYXJrZG93biIsCiAgICJpZCI6ICI4YWM5M2RhOC00MmI0LTQ2YTctYTAyZC02MDllZDkyY2U3MTUiLAogICAibWV0YWRhdGEiOiB7fSwKICAgInNvdXJjZSI6IFsKICAgICIjIyBJTjo2IE1JU1AgcmVwb3J0IGZvciBpbnZlc3RpZ2F0aW9uXG4iLAogICAgIlxuIiwKICAgICJBcGFydCBmcm9tIHRoZSByZXBvcnQgb24gUEUgZGF0YSwgd2UgYWxzbyBjcmVhdGUgYSByZXBvcnQgb24gdGhlIHByZXZpb3VzIGludmVzdGlnYXRpb24gc3RlcHMuIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAiY29kZSIsCiAgICJleGVjdXRpb25fY291bnQiOiBudWxsLAogICAiaWQiOiAiMTE2ZmE5MTgtMDNiNi00YjE4LWJhNGItNDI4MTRjOTQyYmNjIiwKICAgIm1ldGFkYXRhIjogewogICAgInRhZ3MiOiBbXQogICB9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogWwogICAgInN1bW1hcnlfaXYgPSBcIiMjIEludmVzdGlnYXRpb24gcmVwb3J0XFxuXFxuXCJcbiIsCiAgICAiY3VycmVudF9kYXRlID0gZGF0ZXRpbWUubm93KClcbiIsCiAgICAiZm9ybWF0dGVkX2RhdGUgPSBjdXJyZW50X2RhdGUuc3RyZnRpbWUoXCIlWS0lbS0lZFwiKVxuIiwKICAgICJmb3Iga2V5LCBzYW1wbGUgaW4gc2FtcGxlcy5pdGVtcygpOlxuIiwKICAgICIgICAgc3VtbWFyeV9pdiArPSBcIiMjIEFuYWx5c2lzIGZvciB7fVxcblwiLmZvcm1hdChrZXkpXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiLSBEYXRlOiAqKnt9KipcXG5cIi5mb3JtYXQoZm9ybWF0dGVkX2RhdGUpXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiLSBNSVNQIGV2ZW50OiAqKnt9KiogKHt9KVxcblwiLmZvcm1hdChtaXNwX2V2ZW50LmluZm8sIG1pc3BfZXZlbnQuaWQpXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiIyMjIEZpbGUgZGV0YWlsc1xcblwiXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiIC0gUGF0aDoge31cXG5cIi5mb3JtYXQoc2FtcGxlW1wicGF0aFwiXSlcbiIsCiAgICAiICAgIHN1bW1hcnlfaXYgKz0gXCIgLSBNRDU6IHt9XFxuXCIuZm9ybWF0KHNhbXBsZVtcIm1kNVwiXSlcbiIsCiAgICAiICAgIHN1bW1hcnlfaXYgKz0gXCIgLSBTSEEyNTY6IHt9XFxuXCIuZm9ybWF0KHNhbXBsZVtcInNoYTI1NlwiXSlcbiIsCiAgICAiICAgIHN1bW1hcnlfaXYgKz0gXCIgLSBFbnRyb3B5OiB7fVxcblwiLmZvcm1hdChzYW1wbGVbXCJlbnRyb3B5XCJdKVxuIiwKICAgICIgICAgc3VtbWFyeV9pdiArPSBcIiAtIE1pbWUtdHlwZToge31cXG5cIi5mb3JtYXQoc2FtcGxlW1wibWltZXR5cGVcIl0pXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiIyMjIFJpc2tcXG5cIlxuIiwKICAgICIgICAgaWYgc2FtcGxlLmdldChcImRldGVjdGlvbl9yYXRpb1wiLCBGYWxzZSk6XG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9pdiArPSBcIiAtIERldGVjdGlvbiByYXRpbzogKip7fSoqXFxuXCIuZm9ybWF0KHNhbXBsZVtcImRldGVjdGlvbl9yYXRpb1wiXSlcbiIsCiAgICAiICAgICAgICBzdW1tYXJ5X2l2ICs9IFwiIC0gRGV0ZWN0aW9uIHJhdGlvIHBlcmNlbnRhZ2U6ICoqe30qKlxcblwiLmZvcm1hdChzYW1wbGVbXCJkZXRlY3Rpb25fcmF0aW9fcGVyY1wiXSlcbiIsCiAgICAiICAgICAgICBzdW1tYXJ5X2l2ICs9IFwiIC0gRGV0ZWN0aW9uIHJhdGlvIGluZGlyZWN0OiB7fVxcblwiLmZvcm1hdChzYW1wbGVbXCJkZXRlY3Rpb25fcmF0aW9faW5kaXJlY3RcIl0pXG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9pdiArPSBcIiAtIERldGVjdGlvbiByYXRpbyBpbmRpcmVjdCBwZXJjZW50YWdlOiB7fVxcblwiLmZvcm1hdChzYW1wbGVbXCJkZXRlY3Rpb25fcmF0aW9faW5kaXJlY3RfcGVyY1wiXSlcbiIsCiAgICAiICAgIGVsc2U6XG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9pdiArPSBcIipObyBkZXRlY3Rpb24gcmF0aW8gZm91bmQqXFxuXFxuXCJcbiIsCiAgICAiICAgIGlmIHNhbXBsZS5nZXQoXCJyaXNrX3JhdGluZ1wiLCBGYWxzZSk6XG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9pdiArPSBcIiAtIFJpc2sgcmF0aW5nOiAqKnt9KipcXG5cIi5mb3JtYXQoc2FtcGxlW1wicmlza19yYXRpbmdcIl0pXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiIyMjIFZpcnVzVG90YWxcXG5cIlxuIiwKICAgICIgICAgaWYgc2FtcGxlW1widnRcIl0uZ2V0KFwibWFya2Rvd25cIik6XG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9pdiArPSBzYW1wbGVbXCJ2dFwiXVtcIm1hcmtkb3duXCJdXG4iLAogICAgIiAgICBlbHNlOlxuIiwKICAgICIgICAgICAgIHN1bW1hcnlfaXYgKz0gXCIqTm8gcmVzdWx0cypcXG5cIlxuIiwKICAgICIgICAgc3VtbWFyeV9pdiArPSBcIlxcblxcblwiXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiIyMjIEhhc2hsb29rdXBcXG5cIlxuIiwKICAgICIgICAgaWYgc2FtcGxlW1wiaGFzaGxvb2t1cFwiXS5nZXQoXCJtYXJrZG93blwiKTpcbiIsCiAgICAiICAgICAgICBzdW1tYXJ5X2l2ICs9IHNhbXBsZVtcImhhc2hsb29rdXBcIl1bXCJtYXJrZG93blwiXVxuIiwKICAgICIgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICBzdW1tYXJ5X2l2ICs9IFwiKk5vIHJlc3VsdHMqXFxuXCJcbiIsCiAgICAiICAgIHN1bW1hcnlfaXYgKz0gXCJcXG5cXG5cIlxuIiwKICAgICIgICAgc3VtbWFyeV9pdiArPSBcIiMjIyBNYWx3YXJlQmF6YWFyXFxuXCJcbiIsCiAgICAiICAgIGlmIHNhbXBsZVtcIm1hbHdhcmViYXphYXJcIl0uZ2V0KFwibWFya2Rvd25cIik6XG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9pdiArPSBzYW1wbGVbXCJtYWx3YXJlYmF6YWFyXCJdW1wibWFya2Rvd25cIl1cbiIsCiAgICAiICAgIGVsc2U6XG4iLAogICAgIiAgICAgICAgc3VtbWFyeV9pdiArPSBcIipObyByZXN1bHRzKlxcblwiXG4iLAogICAgIiAgICBzdW1tYXJ5X2l2ICs9IFwiXFxuXFxuXCJcbiIsCiAgICAiXG4iLAogICAgImV2ZW50X3RpdGxlID0gXCJNYWx3YXJlIGFuYWx5c2lzXCJcbiIsCiAgICAicHJpbnQoXCJDcmVhdGluZyBNSVNQIHJlcG9ydCBcXDAzM1s5Mm17fVxcMDMzWzkwbVwiLmZvcm1hdChldmVudF90aXRsZSkpXG4iLAogICAgImNodW5rX3NpemUgPSA2MTUwMFxuIiwKICAgICJmb3IgaSBpbiByYW5nZSgwLCBsZW4oc3VtbWFyeV9pdiksIGNodW5rX3NpemUpOlxuIiwKICAgICIgICAgY2h1bmsgPSBzdW1tYXJ5X2l2W2k6aSArIGNodW5rX3NpemVdXG4iLAogICAgIiAgICBldmVudF9yZXBvcnQgPSBNSVNQRXZlbnRSZXBvcnQoKVxuIiwKICAgICIgICAgZXZlbnRfdGl0bGVfZWRpdCA9IGV2ZW50X3RpdGxlXG4iLAogICAgIiAgICBpZiBpID4gMDpcbiIsCiAgICAiICAgICAgICBldmVudF90aXRsZV9lZGl0ID0gXCJ7fSAoe30gPiB7fSlcIi5mb3JtYXQoZXZlbnRfdGl0bGUsIGksIGkgKyBjaHVua19zaXplKVxuIiwKICAgICIgICAgZXZlbnRfcmVwb3J0Lm5hbWUgPSBldmVudF90aXRsZV9lZGl0XG4iLAogICAgIiAgICBldmVudF9yZXBvcnQuY29udGVudCA9IGNodW5rXG4iLAogICAgIiAgICByZXN1bHQgPSBtaXNwLmFkZF9ldmVudF9yZXBvcnQobWlzcF9ldmVudC5pZCwgZXZlbnRfcmVwb3J0KVxuIiwKICAgICIgICAgaWYgXCJFdmVudFJlcG9ydFwiIGluIHJlc3VsdDpcbiIsCiAgICAiICAgICAgICBwcmludChcIiBSZXBvcnQgSUQ6IFxcMDMzWzkybXt9XFwwMzNbOTBtXCIuZm9ybWF0KHJlc3VsdC5nZXQoXCJFdmVudFJlcG9ydFwiLCBbXSkuZ2V0KFwiaWRcIiwgMCkpKVxuIiwKICAgICIgICAgZWxzZTpcbiIsCiAgICAiICAgICAgICBwcmludChcIkZhaWxlZCB0byBjcmVhdGUgcmVwb3J0IGZvciBcXDAzM1s5MW17fVxcMDMzWzkwbS5cIi5mb3JtYXQoZXZlbnRfdGl0bGUpKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjI4ODJjODdiLTRmZTYtNGJlZC1iMGEyLTU5NDhiNTQ2M2ZjNCIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMgQ29ycmVsYXRpb25cbiIsCiAgICAiXG4iLAogICAgIiMjIENSOjEgQ29ycmVsYXRpb24gd2l0aCBNSVNQIGV2ZW50c1xuIiwKICAgICJcbiIsCiAgICAiVGhpcyBjZWxsIHNlYXJjaGVzIHRoZSAqKk1JU1Agc2VydmVyKiogZm9yIGV2ZW50cyB0aGF0IGhhdmUgYSBtYXRjaCB3aXRoIHRoZSBhbmFseXNlZCBzYW1wbGVzLlxuIiwKICAgICJcbiIsCiAgICAiT25seSAqKnB1Ymxpc2hlZCoqIGV2ZW50cyAoYGNvcnJlbGF0aW9uX3B1Ymxpc2hlZGApIGFuZCBhdHRyaWJ1dGVzIHRoYXQgaGF2ZSB0aGUgKip0b19pZHMqKiBmbGFnIChgY29ycmVsYXRpb25fdG9faWRzYCkgc2V0IGFyZSB0YWtlIGludG8gYWNjb3VudC4gVGhlcmUgaXMgYSBkZWZhdWx0IGxpbWl0IG9mICoqMTAwMCBoaXRzKiogKGBjb3JyZWxhdGlvbl9saW1pdGApIGFuZCB5b3UgY2FuIGxpbWl0IHRoZSBzZWFyY2ggd2l0aCB0YWdzIChgY29ycmVsYXRpb25fbWF0Y2hfdGFnc2ApLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogImQzMTYwYzllLWZmZjMtNDNkMC1iMjBhLTRjNjkxZWFiNmE2MSIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICIjIE9ubHkgcXVlcnkgZm9yIHB1Ymxpc2hlZCBNSVNQIGV2ZW50c1xuIiwKICAgICJjb3JyZWxhdGlvbl9wdWJsaXNoZWQgPSBGYWxzZVxuIiwKICAgICJcbiIsCiAgICAiIyBPbmx5IGNvbnNpZGVyIHRob3NlIHZhbHVlcyB0aGF0IGhhdmUgdGhlIHRvX2lkcyBmaWVsZCBzZXQgdG8gVHJ1ZVxuIiwKICAgICJjb3JyZWxhdGlvbl90b19pZHMgPSBUcnVlXG4iLAogICAgIlxuIiwKICAgICIjIExpbWl0IHRoZSByZXR1cm5lZCByZXN1bHRzIHRvIDEwMDAgYXR0cmlidXRlc1xuIiwKICAgICJjb3JyZWxhdGlvbl9saW1pdCA9IDEwMDBcbiIsCiAgICAiXG4iLAogICAgIiMgT25seSByZXR1cm4gcmVzdWx0cyBjb3JyZXNwb25kaW5nIHdpdGggdGhlc2UgdGFnc1xuIiwKICAgICJjb3JyZWxhdGlvbl9tYXRjaF90YWdzID0gW1widGxwOmFtYmVyXCIsIFwidGxwOndoaXRlXCJdIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAiY29kZSIsCiAgICJleGVjdXRpb25fY291bnQiOiBudWxsLAogICAiaWQiOiAiNGQ5ZjNmN2UtNGU4ZC00NWQ3LWEwNTctMzNlZDFlODA1MzM4IiwKICAgIm1ldGFkYXRhIjogewogICAgInRhZ3MiOiBbXQogICB9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogWwogICAgInByaW50KFwiU2VhcmNoIGZvciBjb3JyZWxhdGluZyBNSVNQIGV2ZW50c1wiKVxuIiwKICAgICIjIENvZGUgYmxvY2sgdG8gcXVlcnkgTUlTUCBhbmQgZmluZCB0aGUgY29ycmVsYXRpb25zXG4iLAogICAgImZvciBrZXksIHNhbXBsZSBpbiBzYW1wbGVzLml0ZW1zKCk6XG4iLAogICAgIiAgICB2YWx1ZSA9IFtzYW1wbGUuZ2V0KFwic2hhMjU2XCIpLCBzYW1wbGUuZ2V0KFwibWQ1XCIpXVxuIiwKICAgICIgICAgc2VhcmNoX21hdGNoID0gbWlzcC5zZWFyY2goXCJhdHRyaWJ1dGVzXCIsIHRvX2lkcz1jb3JyZWxhdGlvbl90b19pZHMsIHZhbHVlPXZhbHVlLCB0YWdzPWNvcnJlbGF0aW9uX21hdGNoX3RhZ3MsXG4iLAogICAgIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVibGlzaGVkPWNvcnJlbGF0aW9uX3B1Ymxpc2hlZCwgbGltaXQ9Y29ycmVsYXRpb25fbGltaXQsIHB5dGhvbmlmeT1UcnVlKVxuIiwKICAgICIgICAgaWYgbGVuKHNlYXJjaF9tYXRjaCkgPiAwOiAgICAgICAgXG4iLAogICAgIiAgICAgICAgZm9yIGF0dHJpYnV0ZSBpbiBzZWFyY2hfbWF0Y2g6XG4iLAogICAgIiAgICAgICAgICAgIGlmIGF0dHJpYnV0ZS5FdmVudC5pZCAhPSBtaXNwX2V2ZW50LmlkOiAgICMgU2tpcCB0aGUgZXZlbnQgd2UganVzdCBjcmVhdGVkIGZvciB0aGlzIHBsYXlib29rXG4iLAogICAgIiAgICAgICAgICAgICAgICBwcmludChcIiBGb3VuZCBcXDAzM1s5Mm17fVxcMDMzWzkwbSBpbiBcXDAzM1s5Mm17fVxcMDMzWzkwbSAoe30pXCIuZm9ybWF0KGF0dHJpYnV0ZS52YWx1ZSwgYXR0cmlidXRlLkV2ZW50LmluZm8sIGF0dHJpYnV0ZS5FdmVudC5pZCApKVxuIiwKICAgICIgICAgICAgICAgICAgICAgZW50cnkgPSB7XCJzb3VyY2VcIjogXCJNSVNQXCIsIFwiY2F0ZWdvcnlcIjogYXR0cmlidXRlLmNhdGVnb3J5LCBcInR5cGVcIjogYXR0cmlidXRlLnR5cGUsIFwiZXZlbnRfaWRcIjogYXR0cmlidXRlLkV2ZW50LmlkLCBcImV2ZW50X2luZm9cIjogYXR0cmlidXRlLkV2ZW50LmluZm99XG4iLAogICAgIiAgICAgICAgICAgICAgICBzYW1wbGVzW2tleV1bXCJNSVNQXCJdLmFwcGVuZChlbnRyeSlcbiIsCiAgICAicHJpbnQoXCJGaW5pc2hlZCBzZWFyY2hpbmcgZm9yIGNvcnJlbGF0aW9uc1wiKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogImUxMTNmMzQwLTc2MWItNGZjZS1iMjdlLWQwZGZmYWJmOGE2OSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIyBNSVNQIGV2ZW50cyBjb3JyZWxhdGlvbiB0YWJsZVxuIiwKICAgICJcbiIsCiAgICAiVGhlIGNvcnJlbGF0aW9uIHJlc3VsdHMgYXJlIG5vdyBzdG9yZWQgaW4gYHNhbXBsZXNgLiBFeGVjdXRlIHRoZSBuZXh0IGNlbGwgdG8gZGlzcGxheSB0aGVtIGluIGEgdGFibGUgZm9ybWF0LiBUaGUgdGFibGUgaXMgYWxzbyBpbmNsdWRlZCBpbiB0aGUgc3VtbWFyeSBzZW50IHRvIE1hdHRlcm1vc3QgYW5kIFRoZUhpdmUuIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAiY29kZSIsCiAgICJleGVjdXRpb25fY291bnQiOiBudWxsLAogICAiaWQiOiAiMjhjMzM2MDAtNDdjNy00ZThkLWJjMTAtNjMzM2FkZWQzY2Y0IiwKICAgIm1ldGFkYXRhIjogewogICAgInRhZ3MiOiBbXQogICB9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogWwogICAgIiMgUHV0IHRoZSBjb3JyZWxhdGlvbnMgaW4gYSBwcmV0dHkgdGFibGUuIFdlIGNhbiB1c2UgdGhpcyB0YWJsZSBsYXRlciBhbHNvIGZvciB0aGUgc3VtbWFyeVxuIiwKICAgICJ0YWJsZSA9IFByZXR0eVRhYmxlKClcbiIsCiAgICAidGFibGUuZmllbGRfbmFtZXMgPSBbXCJTb3VyY2VcIiwgXCJWYWx1ZVwiLCBcIkNhdGVnb3J5XCIsIFwiVHlwZVwiLCBcIkV2ZW50XCIsIFwiRXZlbnQgSURcIl1cbiIsCiAgICAidGFibGUuYWxpZ25bXCJWYWx1ZVwiXSA9IFwibFwiXG4iLAogICAgInRhYmxlLmFsaWduW1wiQ2F0ZWdvcnlcIl0gPSBcImxcIlxuIiwKICAgICJ0YWJsZS5hbGlnbltcIlR5cGVcIl0gPSBcImxcIlxuIiwKICAgICJ0YWJsZS5hbGlnbltcIkV2ZW50XCJdID0gXCJsXCJcbiIsCiAgICAidGFibGUuYWxpZ25bXCJFdmVudCBJRFwiXSA9IFwibFwiXG4iLAogICAgInRhYmxlLl9tYXhfd2lkdGggPSB7XCJFdmVudFwiOiA1MH1cbiIsCiAgICAiZm9yIGtleSwgc2FtcGxlIGluIHNhbXBsZXMuaXRlbXMoKTpcbiIsCiAgICAiICAgIGZvciBtYXRjaCBpbiBzYW1wbGVbXCJNSVNQXCJdOlxuIiwKICAgICIgICAgICAgIHRhYmxlLmFkZF9yb3coW21hdGNoW1wic291cmNlXCJdLCBrZXksIG1hdGNoW1wiY2F0ZWdvcnlcIl0sIG1hdGNoW1widHlwZVwiXSwgbWF0Y2hbXCJldmVudF9pbmZvXCJdLCBtYXRjaFtcImV2ZW50X2lkXCJdXSlcbiIsCiAgICAicHJpbnQodGFibGUuZ2V0X3N0cmluZyhzb3J0Ynk9XCJWYWx1ZVwiKSlcbiIsCiAgICAidGFibGVfbWlzcGV2ZW50cyA9IHRhYmxlIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiNGMzMjY2YjQtOTI4OC00MmE1LWI2MTAtYzUwZWM0YzFjYTkwIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgQ1I6MiBDb3JyZWxhdGlvbiB3aXRoIE1JU1AgZmVlZHNcbiIsCiAgICAiXG4iLAogICAgIlRoaXMgY2VsbCBzZWFyY2hlcyB0aGUgKipNSVNQIGZlZWRzKiogZm9yIGV2ZW50cyB0aGF0IGhhdmUgYSBtYXRjaCB3aXRoIHRoZSBhbmFseXNlZCBzYW1wbGVzLiBUaGUgb3V0cHV0IG9mIHRoaXMgY2VsbCBpcyBhIHRhYmxlIHdpdGggYWxsIHRoZSBtYXRjaGVzLiBUaGUgb3V0cHV0IGlzIGFsc28gcmVwZWF0ZWQgYXQgdGhlIGVuZCBvZiB0aGUgcGxheWJvb2suXG4iLAogICAgIlxuIiwKICAgICJOb3RlIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGxvb2t1cCBpbiB0aGUgTUlTUCBmZWVkcyBkb2VzIG5vdCByZXR1cm4gdGhlIG5hbWUgb2YgdGhlIE1JU1AgZXZlbnQsIGl0IHJldHVybnMgdGhlIFVVSUQgb2YgdGhlIGV2ZW50IGFzIHRpdGxlLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjZhNzg1Y2VkLTgyMTAtNDA5Ny05NDA4LWU1NjM4MDIyMWE0ZiIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICJwcmludChcIlNlYXJjaCBpbiBNSVNQIGZlZWRzXCIpXG4iLAogICAgIm1pc3BfY2FjaGVfdXJsID0gXCJ7fS9mZWVkcy9zZWFyY2hDYWNoZXMvXCIuZm9ybWF0KG1pc3BfdXJsKVxuIiwKICAgICJtYXRjaCA9IEZhbHNlXG4iLAogICAgImZvciBrZXksIHNhbXBsZSBpbiBzYW1wbGVzLml0ZW1zKCk6XG4iLAogICAgIiAgICAjIEluc3RlYWQgb2YgR0VULCB1c2UgUE9TVCAoaHR0cHM6Ly9naXRodWIuY29tL01JU1AvTUlTUC9pc3N1ZXMvNzQ3OClcbiIsCiAgICAiICAgIHZhbHVlID0gc2FtcGxlLmdldChcInNoYTI1NlwiKVxuIiwKICAgICIgICAgY2FjaGVfcmVzdWx0cyA9IHJlcXVlc3RzLnBvc3QobWlzcF9jYWNoZV91cmwsIGhlYWRlcnM9bWlzcF9oZWFkZXJzLCB2ZXJpZnk9bWlzcF92ZXJpZnljZXJ0LCBqc29uPXtcInZhbHVlXCI6IHZhbHVlfSlcbiIsCiAgICAiICAgIGZvciByZXN1bHQgaW4gY2FjaGVfcmVzdWx0cy5qc29uKCk6XG4iLAogICAgIiAgICAgICAgaWYgXCJGZWVkXCIgaW4gcmVzdWx0OlxuIiwKICAgICIgICAgICAgICAgICBtYXRjaCA9IFRydWVcbiIsCiAgICAiICAgICAgICAgICAgcHJpbnQoXCIgRm91bmQgXFwwMzNbOTJte31cXDAzM1s5MG0gaW4gXFwwMzNbOTJte31cXDAzM1s5MG1cIi5mb3JtYXQodmFsdWUsIHJlc3VsdFtcIkZlZWRcIl1bXCJuYW1lXCJdKSlcbiIsCiAgICAiICAgICAgICAgICAgZm9yIG1hdGNoIGluIHJlc3VsdFtcIkZlZWRcIl1bXCJkaXJlY3RfdXJsc1wiXTpcbiIsCiAgICAiICAgICAgICAgICAgICAgIGVudHJ5ID0ge1wic291cmNlXCI6IFwiRmVlZHNcIiwgXCJmZWVkX25hbWVcIjogcmVzdWx0W1wiRmVlZFwiXVtcIm5hbWVcIl0sIFwibWF0Y2hfdXJsXCI6IG1hdGNoW1widXJsXCJdfVxuIiwKICAgICIgICAgICAgICAgICAgICAgc2FtcGxlc1trZXldW1wiRmVlZHNcIl0uYXBwZW5kKGVudHJ5KVxuIiwKICAgICJcbiIsCiAgICAicHJpbnQoXCJGaW5pc2hlZCBzZWFyY2hpbmcgaW4gTUlTUCBmZWVkc1wiKVxuIiwKICAgICJpZiBub3QgbWF0Y2g6XG4iLAogICAgIiAgICBwcmludChcIlxcMDMzWzkzbU5vIGNvcnJlbGF0aW5nIGluZm9ybWF0aW9uIGZvdW5kIGluIE1JU1AgZmVlZHMuXCIpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiMDIyYzNjNGYtY2Y1OS00NjliLThjYzYtYjk5MTdmZjVhNmRlIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMjIE1JU1AgZmVlZCBjb3JyZWxhdGlvbnMgdGFibGVcbiIsCiAgICAiXG4iLAogICAgIlRoZSBjb3JyZWxhdGlvbiByZXN1bHRzIGFyZSBub3cgc3RvcmVkIGluIGBzYW1wbGVzYC4gRXhlY3V0ZSB0aGUgbmV4dCBjZWxsIHRvIGRpc3BsYXkgdGhlbSBpbiBhIHRhYmxlIGZvcm1hdC4gVGhlIHRhYmxlIGlzIGFsc28gaW5jbHVkZWQgaW4gdGhlIHN1bW1hcnkgc2VudCB0byBNYXR0ZXJtb3N0IGFuZCBUaGVIaXZlLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjkzZGUxMmVjLTk4OTYtNGFjMC1hYWRhLTkzNjg1YjM5MDU1MyIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICIjIFB1dCB0aGUgY29ycmVsYXRpb25zIGluIGEgcHJldHR5IHRhYmxlLiBXZSBjYW4gdXNlIHRoaXMgdGFibGUgbGF0ZXIgYWxzbyBmb3IgdGhlIHN1bW1hcnlcbiIsCiAgICAidGFibGUgPSBQcmV0dHlUYWJsZSgpXG4iLAogICAgInRhYmxlLmZpZWxkX25hbWVzID0gW1wiU291cmNlXCIsIFwiVmFsdWVcIiwgXCJGZWVkXCIsIFwiVVJMXCJdXG4iLAogICAgInRhYmxlLmFsaWduW1wiVmFsdWVcIl0gPSBcImxcIlxuIiwKICAgICJ0YWJsZS5hbGlnbltcIkZlZWRcIl0gPSBcImxcIlxuIiwKICAgICJ0YWJsZS5hbGlnbltcIkZlZWQgVVJMXCJdID0gXCJsXCJcbiIsCiAgICAidGFibGUuX21heF93aWR0aCA9IHtcIkZlZWRcIjogNTB9XG4iLAogICAgImZvciBrZXksIHNhbXBsZSBpbiBzYW1wbGVzLml0ZW1zKCk6XG4iLAogICAgIiAgICBmb3IgbWF0Y2ggaW4gc2FtcGxlW1wiRmVlZHNcIl06XG4iLAogICAgIiAgICAgICAgdGFibGUuYWRkX3JvdyhbbWF0Y2hbXCJzb3VyY2VcIl0sIGtleSwgbWF0Y2hbXCJmZWVkX25hbWVcIl0sIG1hdGNoW1wibWF0Y2hfdXJsXCJdXSlcbiIsCiAgICAicHJpbnQodGFibGUuZ2V0X3N0cmluZyhzb3J0Ynk9XCJWYWx1ZVwiKSlcbiIsCiAgICAidGFibGVfbWlzcGZlZWRzID0gdGFibGUiCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJtYXJrZG93biIsCiAgICJpZCI6ICJmMDJjNzljYi1lODIwLTQ0YjctODk3Zi0xNTYyNzI2ZWY5MzgiLAogICAibWV0YWRhdGEiOiB7fSwKICAgInNvdXJjZSI6IFsKICAgICIjIFNoYXJlIHRoZSBzYW1wbGVcbiIsCiAgICAiXG4iLAogICAgIiMjIFNBOjEgU3RvcmUgaW4gTVdEQlxuIiwKICAgICJcbiIsCiAgICAiVGhlIE1hbHdhcmUgUmVwb3NpdG9yeSBNV0RCLCBmb3JtZXJseSBrbm93biBhcyBNYWx3YXJlY2FnZSwgaXMgYSBwcm9qZWN0IGZyb20gQ0VSVC5wbCB0aGF0IGlzIGF2YWlsYWJsZSBhcyBhIHNlcnZpY2UgKHZpYSBbTVdEQi1DRVJULnBsXShodHRwczovL213ZGIuY2VydC5wbC9sb2dpbikgYnV0IHlvdSBjYW4gYWxzbyBob3N0IGl0cyBjb3JlIGNvbXBvbmVudCBbTVdEQl0oaHR0cHM6Ly9naXRodWIuY29tL0NFUlQtUG9sc2thL213ZGItY29yZSkgb24geW91ciBvd24gaW5mcmFzdHJ1Y3R1cmUuIEluIHRoaXMgcGxheWJvb2sgdGhlcmUncyB0aGUgb3B0aW9uIHRvIHN0b3JlIHRoZSBzYW1wbGUgaW4geW91ciBpbnN0YW5jZSBvZiBNV0RCLiBGdXR1cmUgdmFyaWFudHMgb2YgdGhlIHBsYXlib29rIGluY2x1ZGUgc2hhcmluZyB0aGUgc2FtcGxlIHdpdGggd2VsbC1rbm93biBtYWx3YXJlIHNhbmRib3hlcy5cbiIsCiAgICAiXG4iLAogICAgIlRoZXJlIGlzIGEgTUlTUCBtb2R1bGUgdGhhdCBhbGxvd3MgdG8gdXBsb2FkIHNhbXBsZXMgZnJvbSBNSVNQIHRvIE1XREIsIGJ1dCBpbiB0aGlzIGNhc2UgdGhlIHBsYXlib29rIHdpbGwgaW50ZXJhY3QgZGlyZWN0bHkgd2l0aCBNV0RCLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjY4Y2IwOGVkLTc2ZGQtNDcwNi04MTljLTU5MjdlYjg1YTllOSIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICJtd2RiX3B1YmxpYyA9IFRydWVcbiIsCiAgICAibXdkYl9tZXRha2V5cyA9IEZhbHNlXG4iLAogICAgIm13ZGIgPSBNV0RCKGFwaV9rZXk9bXdkYl9hcGlrZXksIGFwaV91cmw9bXdkYl9hcGlfdXJsKVxuIiwKICAgICJtd2RiX3RhZ3MgPSBbXCJtaXNwXCIsIFwicGxheWJvb2tcIl1cbiIsCiAgICAiXG4iLAogICAgInN1bW1hcnlfbXdkYiA9IFwiIyMgU2FtcGxlcyBzdG9yZWQgaW4gTVdEQlxcblwiXG4iLAogICAgInByaW50KFwiU3RhcnQgc2hhcmluZyB3aXRoIE1XREJcIilcbiIsCiAgICAiZm9yIGtleSwgc2FtcGxlIGluIHNhbXBsZXMuaXRlbXMoKTpcbiIsCiAgICAiICAgIHNhbXBsZV9maWxlbmFtZSA9IGtleVxuIiwKICAgICIgICAgd2l0aCBvcGVuKHNhbXBsZVtcInBhdGhcIl0sICdyYicpIGFzIGZpbGU6XG4iLAogICAgIiAgICAgICAgZGF0YSA9IGZpbGUucmVhZCgpXG4iLAogICAgIiAgICBmaWxlX29iamVjdCA9IG13ZGIudXBsb2FkX2ZpbGUoc2FtcGxlX2ZpbGVuYW1lLCBkYXRhLCBtZXRha2V5cz1td2RiX21ldGFrZXlzLCBwdWJsaWM9bXdkYl9wdWJsaWMpXG4iLAogICAgIiAgICBmb3IgdGFnIGluIG13ZGJfdGFnczpcbiIsCiAgICAiICAgICAgICBmaWxlX29iamVjdC5hZGRfdGFnKHRhZylcbiIsCiAgICAiICAgIGZpbGVfb2JqZWN0LmFkZF9jb21tZW50KFwiVXBsb2FkZWQgZnJvbSBNSVNQIHBsYXlib29rIGZvciBtYWx3YXJlIHRyaWFnZSwgdmlhIGV2ZW50IHt9XCIuZm9ybWF0KG1pc3BfZXZlbnQuaWQpKVxuIiwKICAgICIgICAgbXdkYl9saW5rID0gXCJ7fXt9XCIuZm9ybWF0KG13ZGJfYXBpX3VybC5yZXBsYWNlKFwiL2FwaVwiLCBcIi9maWxlL1wiKSwgZmlsZV9vYmplY3QubWQ1KVxuIiwKICAgICIgICAgYXR0cmlidXRlID0gTUlTUEF0dHJpYnV0ZSgpXG4iLAogICAgIiAgICBhdHRyaWJ1dGUudmFsdWUgPSBtd2RiX2xpbmtcbiIsCiAgICAiICAgIGF0dHJpYnV0ZS50b19pZHMgPSBGYWxzZVxuIiwKICAgICIgICAgYXR0cmlidXRlLnR5cGUgPSBcImxpbmtcIlxuIiwKICAgICIgICAgYXR0cmlidXRlLmRpc2FibGVfY29ycmVsYXRpb24gPSBUcnVlXG4iLAogICAgIiAgICBhdHRyaWJ1dGUuY29tbWVudCA9IFwiTVdEQiBsaW5rIGZvciBzYW1wbGUge31cIi5mb3JtYXQoa2V5KVxuIiwKICAgICIgICAgYXR0cmlidXRlX213ZGIgPSBtaXNwLmFkZF9hdHRyaWJ1dGUobWlzcF9ldmVudC51dWlkLCBhdHRyaWJ1dGUsIHB5dGhvbmlmeT1UcnVlKVxuIiwKICAgICIgICAgc3VtbWFyeV9td2RiICs9IFwiIHt9IGluIFt7fV0oe30pXFxuXCIuZm9ybWF0KGtleSwgbXdkYl9saW5rLCBtd2RiX2xpbmspXG4iLAogICAgIiAgICBpZiBub3QgXCJlcnJvcnNcIiBpbiBhdHRyaWJ1dGVfbXdkYjpcbiIsCiAgICAiICAgICAgICBtaXNwLmFkZF9vYmplY3RfcmVmZXJlbmNlKHNhbXBsZVtcImZpbGVvYmplY3RcIl0uYWRkX3JlZmVyZW5jZShhdHRyaWJ1dGVfbXdkYi51dWlkLCBcInJlbGF0ZWQtdG9cIikpXG4iLAogICAgIiAgICBlbHNlOlxuIiwKICAgICIgICAgICAgIHByaW50KFwiIFVuYWJsZSB0byBhZGQgYXR0cmlidXRlIHdpdGggbGluayB0byBNV0RCIHRvIE1JU1BcIilcbiIsCiAgICAiICAgIHByaW50KFwiIFNhbXBsZSB7fSBhdCBcXDAzM1s5Mm17fVxcMDMzWzkwbVwiLmZvcm1hdChrZXksIG13ZGJfbGluaykpXG4iLAogICAgInN1bW1hcnlfbXdkYiArPSBcIlxcblwiXG4iLAogICAgInByaW50KFwiRmluaXNoZWQgc2hhcmluZ1wiKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogImM4YmNlMDdlLTcxMDktNGFlMi1iMGMxLWMwNDAzODNiNWRlZSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMgQ2xvc3VyZVxuIiwKICAgICJcbiIsCiAgICAiSW4gdGhpcyAqKmNsb3N1cmUqKiBvciBlbmQgc3RlcCB3ZSBjcmVhdGUgYSAqKnN1bW1hcnkqKiBvZiB0aGUgYWN0aW9ucyB0aGF0IHdlcmUgcGVyZm9ybWVkIGJ5IHRoZSBwbGF5Ym9vay4gVGhlIHN1bW1hcnkgaXMgcHJpbnRlZCBpbiB0aGUgcGxheWJvb2sgYW5kIGNhbiBhbHNvIGJlIHNlbmQgdG8gYSBjaGF0IGNoYW5uZWwuICIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjllY2U2Y2JhLTU4YmQtNDIzOC05MjA0LTQ0ZTNhNTBjZDc1OSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIEVOOjEgTUlTUCBpbmRpY2F0b3JzXG4iLAogICAgIlxuIiwKICAgICJUaGUgbmV4dCBzZWN0aW9uIGZpcnN0ICoqcXVlcmllcyBNSVNQIGZvciB0aGUgaW5kaWNhdG9ycyBhZGRlZCB0byB0aGUgTUlTUCBldmVudCoqIHRoYXQgaXMgbGlua2VkIHRvIHRoZSBleGVjdXRpb24gb2YgdGhpcyBwbGF5Ym9vay5cbiIsCiAgICAiXG4iLAogICAgIlRoZSBpbmRpY2F0b3JzIGFyZSBzdG9yZWQgaW4gdGhlIHZhcmlhYmxlIGBpbmRpY2F0b3JfdGFibGVgICh0YWJsZSBmb3JtYXQpIGFuZCBgaW5kaWNhdG9yX3Jhd19saXN0YCAoaW4gcmF3IGZvcm1hdCkgd2hpY2ggaXMgdXNlZCBpbiBhIGxhdGVyIHNlY3Rpb24gdG8gY3JlYXRlIHRoZSBwbGF5Ym9vayBzdW1tYXJ5LiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogImVkOGVjM2QyLTAxZGEtNGUxYS1hYjVmLTUxMWE0NmU1ZGFlOCIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICIjIEdldCBhbGwgdGhlIGluZGljYXRvcnMgZm9yIG91ciBldmVudCBhbmQgc3RvcmUgdGhpcyBpcyBpbiBhIHRhYmxlLiBXZSBjYW4gYWxzbyB1c2UgdGhpcyBmb3IgdGhlIHN1bW1hcnkuXG4iLAogICAgImluZGljYXRvcl9zZWFyY2ggPSBtaXNwLnNlYXJjaChcImF0dHJpYnV0ZXNcIiwgdXVpZD1taXNwX2V2ZW50LnV1aWQsIHRvX2lkcz1UcnVlLCBweXRob25pZnk9VHJ1ZSlcbiIsCiAgICAiaW5kaWNhdG9yX3Jhd19saXN0ID0gW11cbiIsCiAgICAiaW5kaWNhdG9yX3RhYmxlID0gUHJldHR5VGFibGUoKVxuIiwKICAgICJpZiBsZW4oaW5kaWNhdG9yX3NlYXJjaCkgPiAwOlxuIiwKICAgICIgICAgaW5kaWNhdG9yX3RhYmxlLmZpZWxkX25hbWVzID0gW1wiVHlwZVwiLCBcIkNhdGVnb3J5XCIsIFwiSW5kaWNhdG9yXCIsIFwiQ29tbWVudFwiXVxuIiwKICAgICIgICAgaW5kaWNhdG9yX3RhYmxlLmFsaWduW1wiVHlwZVwiXSA9IFwibFwiXG4iLAogICAgIiAgICBpbmRpY2F0b3JfdGFibGUuYWxpZ25bXCJDYXRlZ29yeVwiXSA9IFwibFwiXG4iLAogICAgIiAgICBpbmRpY2F0b3JfdGFibGUuYWxpZ25bXCJJbmRpY2F0b3JcIl0gPSBcImxcIlxuIiwKICAgICIgICAgaW5kaWNhdG9yX3RhYmxlLmFsaWduW1wiQ29tbWVudFwiXSA9IFwibFwiXG4iLAogICAgIiAgICBpbmRpY2F0b3JfdGFibGUuYm9yZGVyID0gVHJ1ZVxuIiwKICAgICIgICAgZm9yIGluZGljYXRvciBpbiBpbmRpY2F0b3Jfc2VhcmNoOlxuIiwKICAgICIgICAgICAgIGlmIGluZGljYXRvci52YWx1ZSBub3QgaW4gaW5kaWNhdG9yX3Jhd19saXN0OlxuIiwKICAgICIgICAgICAgICAgICBjb21tZW50ID0gaW5kaWNhdG9yLmNvbW1lbnRcbiIsCiAgICAiICAgICAgICAgICAgaWYgaGFzYXR0cihpbmRpY2F0b3IsICdvYmplY3RfcmVsYXRpb24nKTpcbiIsCiAgICAiICAgICAgICAgICAgICAgIG9iamVjdF9pbmQgPSBtaXNwLmdldF9vYmplY3QoaW5kaWNhdG9yLm9iamVjdF9pZCwgcHl0aG9uaWZ5PVRydWUpXG4iLAogICAgIiAgICAgICAgICAgICAgICBjb21tZW50ID0gXCJGcm9tICd7fScgb2JqZWN0IHt9IHt9XCIuZm9ybWF0KG9iamVjdF9pbmQubmFtZSwgb2JqZWN0X2luZC5jb21tZW50Lmxvd2VyKCksIGNvbW1lbnQubG93ZXIoKSlcbiIsCiAgICAiICAgICAgICAgICAgaW5kaWNhdG9yX3RhYmxlLmFkZF9yb3coW2luZGljYXRvci50eXBlLCBpbmRpY2F0b3IuY2F0ZWdvcnksIGluZGljYXRvci52YWx1ZSwgY29tbWVudF0pXG4iLAogICAgIiAgICAgICAgICAgIGluZGljYXRvcl9yYXdfbGlzdC5hcHBlbmQoaW5kaWNhdG9yLnZhbHVlKVxuIiwKICAgICIgICAgcHJpbnQoXCJHb3QgXFwwMzNbOTJte31cXDAzM1s5MG0gaW5kaWNhdG9yKHMpIGZyb20gdGhlIGV2ZW50IFxcMDMzWzkybXt9XFwwMzNbOTBtICh7fSkuXFxuXCIuZm9ybWF0KGxlbihpbmRpY2F0b3JfcmF3X2xpc3QpLCBtaXNwX2V2ZW50LmluZm8sIG1pc3BfZXZlbnQuaWQpKVxuIiwKICAgICJlbHNlOlxuIiwKICAgICIgICAgcHJpbnQoXCJcXDAzM1s5M21ObyBpbmRpY2F0b3JzIGZvdW5kIGluIHRoZSBldmVudCBcXDAzM1s5Mm17fVxcMDMzWzkwbSAoe30pXCIuZm9ybWF0KG1pc3BfZXZlbnQuaW5mbywgbWlzcF9ldmVudC5pZCkpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiODU4ODM2NjYtNzE3Mi00NmQ1LWI2YzUtZmZlMmRjMjk2ZGY0IiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMjIFJhdyBsaXN0IG9mIE1JU1AgaW5kaWNhdG9yc1xuIiwKICAgICJcbiIsCiAgICAiVGhlIGluZGljYXRvcnMgYXJlIG5vdyBzdG9yZWQgaW4gYGluZGljYXRvcl9zZWFyY2hgIChhcyBQeXRob24gb2JqZWN0cykgYW5kIGBpbmRpY2F0b3JfcmF3X2xpc3RgIChpbiByYXcgZm9ybWF0LCBvbmx5IHRoZSBpbmRpY2F0b3JzKS4gRXhlY3V0ZSB0aGUgbmV4dCBjZWxsIHRvIGRpc3BsYXkgdGhlbSBpbiBhIHRhYmxlIGZvcm1hdC4gVGhlIHRhYmxlIGlzIGFsc28gaW5jbHVkZWQgaW4gdGhlIHN1bW1hcnkgc2VudCB0byBNYXR0ZXJtb3N0IGFuZCBUaGVIaXZlLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogImEwNWUxMzI2LTg0NzMtNGMyNS04YjQwLTQ4MjVlNzI3MDQ1YSIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICJpZiBsZW4oaW5kaWNhdG9yX3Jhd19saXN0KSA+IDA6XG4iLAogICAgIiAgICBwcmludChpbmRpY2F0b3JfdGFibGUuZ2V0X3N0cmluZyhzb3J0Ynk9XCJUeXBlXCIpKVxuIiwKICAgICIgICAgcHJpbnQoXCJcXG5cXG5JbmRpY2F0b3IgbGlzdCBpbiByYXcgZm9ybWF0OlwiKVxuIiwKICAgICIgICAgcHJpbnQoXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIilcbiIsCiAgICAiICAgIGZvciBlbCBpbiBpbmRpY2F0b3JfcmF3X2xpc3Q6XG4iLAogICAgIiAgICAgICAgcHJpbnQoXCJ7fVwiLmZvcm1hdChlbCkpXG4iLAogICAgIiAgICBwcmludChcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogIjA4ZWQ3NmNmLTZlYmYtNDI1Yi04M2EzLWJhZTFhY2Y0MTc3MSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIEVOOjIgQ3JlYXRlIHRoZSBzdW1tYXJ5IG9mIHRoZSBwbGF5Ym9va1xuIiwKICAgICJcbiIsCiAgICAiVGhlIG5leHQgc2VjdGlvbiBjcmVhdGVzIGEgc3VtbWFyeSBhbmQgc3RvcmVzIHRoZSBvdXRwdXQgaW4gdGhlIHZhcmlhYmxlIGBzdW1tYXJ5YCBpbiBNYXJrZG93biBmb3JtYXQuIEl0IGFsc28gc3RvcmVzIGFuIGludHJvIHRleHQgaW4gdGhlIHZhcmlhYmxlIGBpbnRyb2AuIFRoZXNlIHZhcmlhYmxlcyBhcmUgbGF0ZXIgdXNlZCB3aGVuIHNlbmRpbmcgaW5mb3JtYXRpb24gdG8gTWF0dGVybW9zdCBvciBUaGVIaXZlLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjNiNTViZDA5LWI0NDAtNDkyNS1hM2FmLWJlNjJlYzdjMWMzOSIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICJzdW1tYXJ5ID0gXCIjIE1JU1AgUGxheWJvb2sgc3VtbWFyeVxcbk1hbHdhcmUgdHJpYWdlIHdpdGggTUlTUCBldmVudDogKip7fSoqICh7fS9ldmVudHMvdmlldy97fSkuIFwiLmZvcm1hdChtaXNwX2V2ZW50LmluZm8sIG1pc3BfdXJsLCBtaXNwX2V2ZW50LmlkKVxuIiwKICAgICJcbiIsCiAgICAic3VtbWFyeSArPSBcIlxcblwiXG4iLAogICAgInN1bW1hcnkgKz0gc3VtbWFyeV9pdlxuIiwKICAgICJzdW1tYXJ5ICs9IFwiXFxuXCJcbiIsCiAgICAiaW50cm8gPSBzdW1tYXJ5XG4iLAogICAgIlxuIiwKICAgICJzdW1tYXJ5ICs9IFwiIyMgSW5kaWNhdG9yc1xcblxcblwiXG4iLAogICAgInN1bW1hcnkgKz0gXCIjIyMgSW5kaWNhdG9ycyB0YWJsZVxcblxcblwiXG4iLAogICAgImlmIGxlbihpbmRpY2F0b3JfcmF3X2xpc3QpID4gMDpcbiIsCiAgICAiICAgIGluZGljYXRvcl90YWJsZS5zZXRfc3R5bGUoTUFSS0RPV04pXG4iLAogICAgIiAgICBzdW1tYXJ5ICs9IGluZGljYXRvcl90YWJsZS5nZXRfc3RyaW5nKHNvcnRieT1cIlR5cGVcIilcbiIsCiAgICAiICAgIHN1bW1hcnkgKz0gXCJcXG5cXG5cXG5cIiBcbiIsCiAgICAiICAgIHN1bW1hcnkgKz0gXCIjIyMgSW5kaWNhdG9ycyBpbiAqKnJhdyBmb3JtYXQqKlxcblxcblwiXG4iLAogICAgIiAgICBmb3IgaW5kaWNhdG9yIGluIGluZGljYXRvcl9yYXdfbGlzdDpcbiIsCiAgICAiICAgICAgICBzdW1tYXJ5ICs9IFwie31cXG5cXG5cIi5mb3JtYXQoaW5kaWNhdG9yKVxuIiwKICAgICIgICAgc3VtbWFyeSArPSBcIlxcblwiIFxuIiwKICAgICJlbHNlOlxuIiwKICAgICIgICAgc3VtbWFyeSArPSBcIlRoZXJlIGFyZSBubyBpbmRpY2F0b3JzXCJcbiIsCiAgICAic3VtbWFyeSArPSBcIlxcblxcblwiXG4iLAogICAgIlxuIiwKICAgICJzdW1tYXJ5ICs9IFwiIyMgQ29ycmVsYXRpb25zXFxuXFxuXCJcbiIsCiAgICAic3VtbWFyeSArPSBcIiMjIyBNSVNQIGV2ZW50IG1hdGNoZXNcXG5cXG5cIlxuIiwKICAgICJ0YWJsZV9taXNwZXZlbnRzLnNldF9zdHlsZShNQVJLRE9XTilcbiIsCiAgICAic3VtbWFyeSArPSB0YWJsZV9taXNwZXZlbnRzLmdldF9zdHJpbmcoKVxuIiwKICAgICJzdW1tYXJ5ICs9IFwiXFxuXFxuXCJcbiIsCiAgICAiXG4iLAogICAgInN1bW1hcnkgKz0gXCIjIyMgTUlTUCBmZWVkIG1hdGNoZXNcXG5cXG5cIlxuIiwKICAgICJ0YWJsZV9taXNwZmVlZHMuc2V0X3N0eWxlKE1BUktET1dOKVxuIiwKICAgICJzdW1tYXJ5ICs9IHRhYmxlX21pc3BmZWVkcy5nZXRfc3RyaW5nKClcbiIsCiAgICAic3VtbWFyeSArPSBcIlxcblxcblwiXG4iLAogICAgIlxuIiwKICAgICJzdW1tYXJ5ICs9IHN1bW1hcnlfcGVcbiIsCiAgICAiXG4iLAogICAgInN1bW1hcnkgKz0gXCJcXG5cXG5cIlxuIiwKICAgICJcbiIsCiAgICAicHJpbnQoXCJUaGUgXFwwMzNbOTJtc3VtbWFyeVxcMDMzWzkwbSBvZiB0aGUgcGxheWJvb2sgaXMgYXZhaWxhYmxlLlxcblwiKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogImU5YWE1OTBkLTU2MGEtNDRmNy1iZDc4LWMyZTBlOTY1MGJiYSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAic291cmNlIjogWwogICAgIiMjIEVOOjMgUHJpbnQgdGhlIGlucHV0IGZvciBtYWx3YXJlIHRyaWFnZVxuIiwKICAgICJcbiIsCiAgICAiQXBhcnQgZnJvbSB0aGUgZnVsbCBzdW1tYXJ5IG9mIHRoZSBpbnZlc3RpZ2F0aW9uLCB0aGUgbWFsd2FyZSB0cmlhZ2Ugc3VtbWFyeSBwcm92aWRlcyB0aGUgbmVjZXNzYXJ5IGlucHV0IGZvciB0aGUgYW5hbHlzdC4gVGhpcyBzdW1tYXJ5IHdhcyBwcmV2aW91c2x5IGFsc28gYWRkZWQgYXMgYSBNSVNQIHJlcG9ydC4iCiAgIF0KICB9LAogIHsKICAgImNlbGxfdHlwZSI6ICJjb2RlIiwKICAgImV4ZWN1dGlvbl9jb3VudCI6IG51bGwsCiAgICJpZCI6ICJmNDAxMzViMC02NjgyLTQ4YjgtYjVjOC0zNjkyYTIwZDU4ODciLAogICAibWV0YWRhdGEiOiB7CiAgICAidGFncyI6IFtdCiAgIH0sCiAgICJvdXRwdXRzIjogW10sCiAgICJzb3VyY2UiOiBbCiAgICAicHJpbnQoc3VtbWFyeV9pdilcbiIsCiAgICAiIyBPciBwcmludCB3aXRoIHBhcnNlZCBtYXJrZG93blxuIiwKICAgICIjIGRpc3BsYXlfbWFya2Rvd24oc3VtbWFyeV9pdiwgcmF3PVRydWUpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiZWJhOTYwNjItZGVhYS00ZmI5LTgzMDItN2IzZWY4MjkyMDFlIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgRU46NCBTZW5kIGEgc3VtbWFyeSB0byBNYXR0ZXJtb3N0XG4iLAogICAgIlxuIiwKICAgICJOb3cgeW91IGNhbiBzZW5kIHRoZSBzdW1tYXJ5IHRvIE1hdHRlcm1vc3QuIFlvdSBjYW4gc2VuZCB0aGUgc3VtbWFyeSBpbiB0d28gd2F5cyBieSBzZWxlY3Rpbmcgb25lIG9mIHRoZSBvcHRpb25zIGZvciB0aGUgdmFyaWFibGUgYHNlbmRfdG9fbWF0dGVybW9zdF9vcHRpb25gIGluIHRoZSBuZXh0IGNlbGwuXG4iLAogICAgIlxuIiwKICAgICItIFRoZSBkZWZhdWx0IG9wdGlvbiB3aGVyZSB0aGUgZW50aXJlIHN1bW1hcnkgaXMgaW4gdGhlICoqY2hhdCoqLCBvclxuIiwKICAgICItIGEgc2hvcnQgaW50cm8gYW5kIHRoZSBzdW1tYXJ5IGluIGEgKipjYXJkKipcbiIsCiAgICAiXG4iLAogICAgIkZvciB0aGlzIHBsYXlib29rIHdlIHJlbHkgb24gYSB3ZWJob29rIGluIE1hdHRlcm1vc3QuIFlvdSBjYW4gYWRkIGEgd2ViaG9vayBieSBjaG9vc2luZyB0aGUgZ2VhciBpY29uIGluIE1hdHRlcm1vc3QsIHRoZW4gY2hvb3NlIEludGVncmF0aW9ucyBhbmQgdGhlbiAqKkluY29taW5nIFdlYmhvb2tzKiouIFNldCBhIGNoYW5uZWwgZm9yIHRoZSB3ZWJob29rIGFuZCBsb2NrIHRoZSB3ZWJob29rIHRvIHRoaXMgY2hhbm5lbCB3aXRoICpcIkxvY2sgdG8gdGhpcyBjaGFubmVsXCIqLiIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjhjNDU1YmMzLTM1Y2MtNDM2ZC04MjM3LTk1YzgxYjU3MjA4ZiIsCiAgICJtZXRhZGF0YSI6IHsKICAgICJ0YWdzIjogW10KICAgfSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICJzZW5kX3RvX21hdHRlcm1vc3Rfb3B0aW9uID0gXCJ2aWEgYSBjaGF0IG1lc3NhZ2VcIlxuIiwKICAgICIjc2VuZF90b19tYXR0ZXJtb3N0X29wdGlvbiA9IFwidmlhIGEgY2hhdCBtZXNzYWdlIHdpdGggY2FyZFwiIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAiY29kZSIsCiAgICJleGVjdXRpb25fY291bnQiOiBudWxsLAogICAiaWQiOiAiY2E0OWYzM2UiLAogICAibWV0YWRhdGEiOiB7fSwKICAgIm91dHB1dHMiOiBbXSwKICAgInNvdXJjZSI6IFsKICAgICJtZXNzYWdlID0gRmFsc2VcbiIsCiAgICAiaWYgc2VuZF90b19tYXR0ZXJtb3N0X29wdGlvbiA9PSBcInZpYSBhIGNoYXQgbWVzc2FnZVwiOlxuIiwKICAgICIgICAgbWVzc2FnZSA9IHtcInVzZXJuYW1lXCI6IG1hdHRlcm1vc3RfcGxheWJvb2tfdXNlciwgXCJ0ZXh0XCI6IHN1bW1hcnl9XG4iLAogICAgImVsaWYgc2VuZF90b19tYXR0ZXJtb3N0X29wdGlvbiA9PSBcInZpYSBhIGNoYXQgbWVzc2FnZSB3aXRoIGNhcmRcIjpcbiIsCiAgICAiICAgIG1lc3NhZ2UgPSB7XCJ1c2VybmFtZVwiOiBtYXR0ZXJtb3N0X3BsYXlib29rX3VzZXIsIFwidGV4dFwiOiBpbnRybywgXCJwcm9wc1wiOiB7XCJjYXJkXCI6IHN1bW1hcnl9fVxuIiwKICAgICJcbiIsCiAgICAiaWYgbWVzc2FnZTpcbiIsCiAgICAiICAgIHIgPSByZXF1ZXN0cy5wb3N0KG1hdHRlcm1vc3RfaG9vaywgZGF0YT1qc29uLmR1bXBzKG1lc3NhZ2UpKVxuIiwKICAgICIgICAgci5yYWlzZV9mb3Jfc3RhdHVzKClcbiIsCiAgICAiaWYgbWVzc2FnZSBhbmQgci5zdGF0dXNfY29kZSA9PSAyMDA6XG4iLAogICAgIiAgICBwcmludChcIlN1bW1hcnkgaXMgXFwwMzNbOTJtc2VudCB0byBNYXR0ZXJtb3N0LlxcblwiKVxuIiwKICAgICJlbHNlOlxuIiwKICAgICIgICAgcHJpbnQoXCJcXDAzM1s5MW1GYWlsZWQgdG8gc2VudCBzdW1tYXJ5XFwwMzNbOTBtIHRvIE1hdHRlcm1vc3QuXFxuXCIpIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiNDk4YjhlZmYtN2QxYi00N2I3LTkwYzQtZTEzY2M3MzhiMzZjIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgRU46NSBFbmQgb2YgdGhlIHBsYXlib29rICIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjRjMDNiYjMwIiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJvdXRwdXRzIjogW10sCiAgICJzb3VyY2UiOiBbCiAgICAicHJpbnQoXCJcXDAzM1s5Mm0gRW5kIG9mIHRoZSBwbGF5Ym9va1wiKVxuIgogICBdCiAgfSwKICB7CiAgICJjZWxsX3R5cGUiOiAibWFya2Rvd24iLAogICAiaWQiOiAiYjE3YWY5ZjIiLAogICAibWV0YWRhdGEiOiB7fSwKICAgInNvdXJjZSI6IFsKICAgICIjIyBFeHRlcm5hbCByZWZlcmVuY2VzIDxhIG5hbWU9XCJleHRyZWZlcmVuY2VzXCI+PC9hPlxuIiwKICAgICJcbiIsCiAgICAiLSBbVGhlIE1JU1AgUHJvamVjdF0oaHR0cHM6Ly93d3cubWlzcC1wcm9qZWN0Lm9yZy8pXG4iLAogICAgIi0gW01hdHRlcm1vc3RdKGh0dHBzOi8vbWF0dGVybW9zdC5jb20vKVxuIiwKICAgICItIFtNV0RCXShodHRwczovL2dpdGh1Yi5jb20vQ0VSVC1Qb2xza2EvbXdkYi1jb3JlKVxuIiwKICAgICItIFtNYWx3YXJlQmF6YWFyXShodHRwczovL2JhemFhci5hYnVzZS5jaC8pXG4iLAogICAgIi0gW0hhc2hsb29rdXBdKGh0dHBzOi8vd3d3LmNpcmNsLmx1L3NlcnZpY2VzL2hhc2hsb29rdXAvKSIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogIm1hcmtkb3duIiwKICAgImlkIjogImUxYzgxM2Y2IiwKICAgIm1ldGFkYXRhIjoge30sCiAgICJzb3VyY2UiOiBbCiAgICAiIyMgVGVjaG5pY2FsIGRldGFpbHMgXG4iLAogICAgIlxuIiwKICAgICIjIyMgRG9jdW1lbnRhdGlvblxuIiwKICAgICJcbiIsCiAgICAiVGhpcyBwbGF5Ym9vayByZXF1aXJlcyB0aGVzZSBQeXRob24gKipsaWJyYXJpZXMqKiB0byBleGlzdCBpbiB0aGUgZW52aXJvbm1lbnQgd2hlcmUgdGhlIHBsYXlib29rIGlzIGV4ZWN1dGVkLiBZb3UgY2FuIGluc3RhbGwgdGhlbSB3aXRoIGBwaXAgaW5zdGFsbCA8bGlicmFyeT5gLlxuIiwKICAgICJcbiIsCiAgICAiYGBgXG4iLAogICAgInB5ZmF1cFxuIiwKICAgICJjaGFyZGV0XG4iLAogICAgIlByZXR0eVRhYmxlXG4iLAogICAgImlweXdpZGdldHNcbiIsCiAgICAicGVmaWxlXG4iLAogICAgIm13ZGJsaWJcbiIsCiAgICAiYGBgXG4iLAogICAgIlxuIiwKICAgICIjIyMgQ29sb3VyIGNvZGVzXG4iLAogICAgIlxuIiwKICAgICJUaGUgb3V0cHV0IGZyb20gUHl0aG9uIGRpc3BsYXlzIHNvbWUgdGV4dCBpbiBkaWZmZXJlbnQgY29sb3Vycy4gVGhlc2UgYXJlIHRoZSBjb2xvdXIgY29kZXNcbiIsCiAgICAiXG4iLAogICAgImBgYFxuIiwKICAgICJSZWQgPSAnXFwwMzNbOTFtJ1xuIiwKICAgICJHcmVlbiA9ICdcXDAzM1s5Mm0nXG4iLAogICAgIkJsdWUgPSAnXFwwMzNbOTRtJ1xuIiwKICAgICJDeWFuID0gJ1xcMDMzWzk2bSdcbiIsCiAgICAiV2hpdGUgPSAnXFwwMzNbOTdtJ1xuIiwKICAgICJZZWxsb3cgPSAnXFwwMzNbOTNtJ1xuIiwKICAgICJNYWdlbnRhID0gJ1xcMDMzWzk1bSdcbiIsCiAgICAiR3JleSA9ICdcXDAzM1s5MG0nXG4iLAogICAgIkJsYWNrID0gJ1xcMDMzWzkwbSdcbiIsCiAgICAiRGVmYXVsdCA9ICdcXDAzM1s5OW0nXG4iLAogICAgImBgYCIKICAgXQogIH0sCiAgewogICAiY2VsbF90eXBlIjogImNvZGUiLAogICAiZXhlY3V0aW9uX2NvdW50IjogbnVsbCwKICAgImlkIjogIjE0ZGNlODEyLWU0MzItNGMxOC04MzU4LWY4YjY2ZTViOTRhNSIsCiAgICJtZXRhZGF0YSI6IHt9LAogICAib3V0cHV0cyI6IFtdLAogICAic291cmNlIjogW10KICB9CiBdLAogIm1ldGFkYXRhIjogewogICJjZWxsdG9vbGJhciI6ICJBdHRhY2htZW50cyIsCiAgImtlcm5lbHNwZWMiOiB7CiAgICJkaXNwbGF5X25hbWUiOiAiUHl0aG9uIDMgKGlweWtlcm5lbCkiLAogICAibGFuZ3VhZ2UiOiAicHl0aG9uIiwKICAgIm5hbWUiOiAicHl0aG9uMyIKICB9LAogICJsYW5ndWFnZV9pbmZvIjogewogICAiY29kZW1pcnJvcl9tb2RlIjogewogICAgIm5hbWUiOiAiaXB5dGhvbiIsCiAgICAidmVyc2lvbiI6IDMKICAgfSwKICAgImZpbGVfZXh0ZW5zaW9uIjogIi5weSIsCiAgICJtaW1ldHlwZSI6ICJ0ZXh0L3gtcHl0aG9uIiwKICAgIm5hbWUiOiAicHl0aG9uIiwKICAgIm5iY29udmVydF9leHBvcnRlciI6ICJweXRob24iLAogICAicHlnbWVudHNfbGV4ZXIiOiAiaXB5dGhvbjMiLAogICAidmVyc2lvbiI6ICIzLjkuNiIKICB9LAogICJ0b2Mtc2hvd2NvZGUiOiBmYWxzZSwKICAidG9jLXNob3dtYXJrZG93bnR4dCI6IGZhbHNlCiB9LAogIm5iZm9ybWF0IjogNCwKICJuYmZvcm1hdF9taW5vciI6IDUKfQo="
}
],
"agent": "group--95d64ad6-94d0-4368-b6a2-a83a61eda611",
"targets": [
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1"
],
"on_completion": "end--3901ed01-4f4d-423a-a2fe-cec4b9def7c1"
},
"end--3901ed01-4f4d-423a-a2fe-cec4b9def7c1": {
"type": "end",
"name": "End of Playbook"
}
},
"agent_definitions": {
"group--95d64ad6-94d0-4368-b6a2-a83a61eda611": {
"type": "group",
"name": "MISP playbook users",
"description": "Users responsible for executing MISP playbooks"
}
},
"target_definitions": {
"security-category--2e12720a-0d96-4149-b39e-1206b965f0b1": {
"type": "security-category",
"name": "MISP playbooks",
"category": [
"MISP playbook",
"Jupyter Notebook infrastructure"
]
}
},
"external_references": [
{
"name": "MISP",
"url": "https://github.com/MISP/MISP"
},
{
"name": "MISP Playbook GitHub Repository",
"url": "https://github.com/MISP/misp-playbooks"
},
{
"url": "https://www.misp-project.org/)",
"name": "https://www.misp-project.org/)"
},
{
"url": "https://mattermost.com/)",
"name": "https://mattermost.com/)"
},
{
"url": "https://github.com/CERT-Polska/mwdb-core)",
"name": "https://github.com/CERT-Polska/mwdb-core)"
},
{
"url": "https://bazaar.abuse.ch/)",
"name": "https://bazaar.abuse.ch/)"
},
{
"url": "https://www.circl.lu/services/hashlookup/)",
"name": "https://www.circl.lu/services/hashlookup/)"
}
]
}