You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

893 lines
109 KiB

  1. {
  2. "cells": [
  3. {
  4. "cell_type": "markdown",
  5. "metadata": {},
  6. "source": [
  7. "# Pyrocko Notebook\n",
  8. "## Double Couple Waveform Inversion (The 2009 Aquila Earthquake)\n",
  9. "\n",
  10. "In this Jupyter-notebook we look at teleseismic waveforms of the 2009 Aquila Earthquake and setup `pyrocko.gf` forward modelling to invert for the double couple mechanism of the event. We will use `pyrocko` to handle the seismic data and execute the forward modelling based on pre-calculated Green's function stores, `scipy` delivers the optimisation algorithms.\n",
  11. "\n",
  12. "_Authors:_\n",
  13. "Andreas Steinberg, Marius Isken\n",
  14. "\n",
  15. "-Nov. 2017"
  16. ]
  17. },
  18. {
  19. "cell_type": "code",
  20. "execution_count": 1,
  21. "metadata": {},
  22. "outputs": [],
  23. "source": [
  24. "%matplotlib notebook\n",
  25. "import time\n",
  26. "import os\n",
  27. "import scipy\n",
  28. "import numpy as num\n",
  29. "import matplotlib.pyplot as plt\n",
  30. "import plotly.plotly as py\n",
  31. "from collections import OrderedDict\n",
  32. "\n",
  33. "import utils_nb\n",
  34. "\n",
  35. "from pyrocko import gf, trace\n",
  36. "from pyrocko import moment_tensor as mtm\n",
  37. "from pyrocko.gf import ws, LocalEngine, Target, DCSource\n",
  38. "from pyrocko import util, pile, model, config, trace, io, pile, catalog\n",
  39. "\n",
  40. "km = 1000."
  41. ]
  42. },
  43. {
  44. "cell_type": "markdown",
  45. "metadata": {},
  46. "source": [
  47. "### Optimisation Parameters\n",
  48. "Setup of the optimisation parameters, as well as boundaries for the source parameters."
  49. ]
  50. },
  51. {
  52. "cell_type": "code",
  53. "execution_count": 2,
  54. "metadata": {},
  55. "outputs": [],
  56. "source": [
  57. "component = 'Z'\n",
  58. "f_low = 0.05 # Hz, for a lowpass filter\n",
  59. "taper = trace.CosFader(xfade=2.0) # Cosine taper, 2s fade\n",
  60. "\n",
  61. "phase = 'P' # Phase to fit\n",
  62. "tmin_fit = 15. # [s] to fit before synthetic phase onset (from GFStore)\n",
  63. "tmax_fit = 35. # [s] ... after\n",
  64. "\n",
  65. "bounds = OrderedDict([\n",
  66. " ('north_shift', (-20.*km, 20.*km)),\n",
  67. " ('east_shift', (-20.*km, 20.*km)),\n",
  68. " ('depth', (3.*km, 8.*km)),\n",
  69. " ('magnitude', (6.2, 6.4)),\n",
  70. " ('strike', (100., 140.)),\n",
  71. " ('dip', (40., 60.)),\n",
  72. " ('rake', (-100, -150.)),\n",
  73. " ('timeshift', (-20., 20.)),\n",
  74. " ])"
  75. ]
  76. },
  77. {
  78. "cell_type": "markdown",
  79. "metadata": {},
  80. "source": [
  81. "### Load the Waveforms\n",
  82. "We download the instrument-corrected seismic waveforms and use a `pyrocko.pile` to manage the data."
  83. ]
  84. },
  85. {
  86. "cell_type": "code",
  87. "execution_count": 3,
  88. "metadata": {
  89. "scrolled": true
  90. },
  91. "outputs": [
  92. {
  93. "name": "stderr",
  94. "output_type": "stream",
  95. "text": [
  96. "selecting files... done. 58 files selected.\n",
  97. "Looking at files [------------------------------------------------------] 100% \n",
  98. "Scanning files [--------------------------------------------------------] 100% \n",
  99. "Cannot read file '/home/marius/Development/pyrocko-notebooks/data/aquila_realdata/stations_short.txt': No SEED data detected (file: /home/marius/Development/pyrocko-notebooks/data/aquila_realdata/stations_short.txt)\n",
  100. "The following file caused problems and will be ignored:\n",
  101. "/home/marius/Development/pyrocko-notebooks/data/aquila_realdata/stations_short.txt\n"
  102. ]
  103. }
  104. ],
  105. "source": [
  106. "# Download the instrument-corrected 2009 Aquila Earthquake data\n",
  107. "data_path = utils_nb.download_dir('aquila_realdata/')\n",
  108. "data = pile.make_pile([data_path])\n",
  109. "traces = data.all() # retrieves the raw waveform data as a 2D `numpy.array`.\n",
  110. "\n",
  111. "for tr in traces:\n",
  112. " tr.lowpass(4, f_low)"
  113. ]
  114. },
  115. {
  116. "cell_type": "markdown",
  117. "metadata": {},
  118. "source": [
  119. "### Initialize Forward Modelling Engine (Seismosizer)\n",
  120. "We download the precalculated Green's function database (`Store`) *global_2s_25km* from http://kinherd.org"
  121. ]
  122. },
  123. {
  124. "cell_type": "code",
  125. "execution_count": 4,
  126. "metadata": {},
  127. "outputs": [],
  128. "source": [
  129. "store_id = 'global_2s_25km'\n",
  130. "if not os.path.exists(store_id):\n",
  131. " ws.download_gf_store(site='kinherd', store_id=store_id)"
  132. ]
  133. },
  134. {
  135. "cell_type": "markdown",
  136. "metadata": {},
  137. "source": [
  138. "Now we fire up the `engine` to forward model synthetic seismograms on our _global_2s_25km_ GF database."
  139. ]
  140. },
  141. {
  142. "cell_type": "code",
  143. "execution_count": 5,
  144. "metadata": {},
  145. "outputs": [],
  146. "source": [
  147. "engine = gf.LocalEngine(store_superdirs=['.']) # The Path to where the gf_store(s)\n",
  148. "store = engine.get_store(store_id) # Load the store."
  149. ]
  150. },
  151. {
  152. "cell_type": "markdown",
  153. "metadata": {},
  154. "source": [
  155. "### Get GlobalCMT Start Model\n",
  156. "We use the GlobalCMT catalog to search for the 2009 Aquila Earthquake and initalize a source for the starting model."
  157. ]
  158. },
  159. {
  160. "cell_type": "code",
  161. "execution_count": 6,
  162. "metadata": {},
  163. "outputs": [],
  164. "source": [
  165. "tmin = util.str_to_time('2009-04-06 00:00:00') # beginning time of query\n",
  166. "tmax = util.str_to_time('2009-04-06 05:59:59') # ending time of query\n",
  167. "event = catalog.GlobalCMT().get_events(\n",
  168. " time_range=(tmin, tmax),\n",
  169. " magmin=6.)[0]\n",
  170. "\n",
  171. "base_source = gf.MTSource.from_pyrocko_event(event)"
  172. ]
  173. },
  174. {
  175. "cell_type": "markdown",
  176. "metadata": {},
  177. "source": [
  178. "### Station and _Target_ Setup\n",
  179. "We use the term _Target_ for a single component of a single station."
  180. ]
  181. },
  182. {
  183. "cell_type": "code",
  184. "execution_count": 7,
  185. "metadata": {},
  186. "outputs": [],
  187. "source": [
  188. "stations_list = model.load_stations('data/aquila_realdata/stations_short.txt')\n",
  189. "for s in stations_list:\n",
  190. " s.set_channels_by_name(*component.split())"
  191. ]
  192. },
  193. {
  194. "cell_type": "markdown",
  195. "metadata": {},
  196. "source": [
  197. "Next we define the `Target` - where to calculate the synthetic seismogram."
  198. ]
  199. },
  200. {
  201. "cell_type": "code",
  202. "execution_count": 8,
  203. "metadata": {},
  204. "outputs": [],
  205. "source": [
  206. "targets=[]\n",
  207. "for s in stations_list:\n",
  208. " target = Target(\n",
  209. " lat=s.lat,\n",
  210. " lon=s.lon,\n",
  211. " store_id=store_id, # The gf-store to be used for this target,\n",
  212. " interpolation='multilinear', # Interpolation method between GFStore nodes\n",
  213. " quantity='displacement',\n",
  214. " codes=s.nsl() + ('BH' + component,))\n",
  215. " targets.append(target)"
  216. ]
  217. },
  218. {
  219. "cell_type": "markdown",
  220. "metadata": {},
  221. "source": [
  222. "### Objective Function\n",
  223. "Now the objective function that will be called by `scipy.optimize`:"
  224. ]
  225. },
  226. {
  227. "cell_type": "code",
  228. "execution_count": 9,
  229. "metadata": {},
  230. "outputs": [],
  231. "source": [
  232. "source = gf.DCSource(\n",
  233. " lat=event.lat,\n",
  234. " lon=event.lon)\n",
  235. "\n",
  236. "def update_source(params):\n",
  237. " s = source\n",
  238. " s.north_shift = float(params[0])\n",
  239. " s.east_shift = float(params[1])\n",
  240. " s.depth = float(params[2])\n",
  241. " s.magnitude = float(params[3])\n",
  242. " s.strike = float(params[4])\n",
  243. " s.dip = float(params[5])\n",
  244. " s.rake = float(params[6])\n",
  245. " s.time = float(event.time - params[7])\n",
  246. " return source\n",
  247. "\n",
  248. "def process_trace(trace, tmin, tmax, lowpass=False, inplace=True):\n",
  249. " if lowpass:\n",
  250. " trace.lowpass(4, f_low)\n",
  251. " trace = trace.chop(tmin, tmax, inplace=inplace)\n",
  252. " trace.taper(taper)\n",
  253. " return trace\n",
  254. "\n",
  255. "iiter = 0\n",
  256. "\n",
  257. "def trace_fit(params, line=None):\n",
  258. " global iiter\n",
  259. " update_source(params)\n",
  260. "\n",
  261. " # Forward model synthetic seismograms\n",
  262. " response = engine.process(source, targets)\n",
  263. " syn_traces = response.pyrocko_traces()\n",
  264. "\n",
  265. " misfits = 0.\n",
  266. " norms = 0.\n",
  267. "\n",
  268. " for obs, syn, target in zip(traces, syn_traces, targets):\n",
  269. " syn_phs = store.t(phase, base_source, target)\n",
  270. " \n",
  271. " tmin = base_source.time + syn_phs - tmin_fit # start before theor. arrival\n",
  272. " tmax = base_source.time + syn_phs + tmax_fit # end after theor. arrival\n",
  273. " \n",
  274. " syn = process_trace(syn, tmin, tmax)\n",
  275. " obs = process_trace(obs, tmin, tmax, lowpass=False, inplace=True)\n",
  276. "\n",
  277. " misfits += num.sqrt(num.sum((obs.ydata - syn.ydata)**2))\n",
  278. " norms += num.sqrt(num.sum(obs.ydata**2))\n",
  279. " \n",
  280. " misfit = num.sqrt(misfits**2 / norms**2)\n",
  281. " \n",
  282. " iiter += 1\n",
  283. "\n",
  284. " if line:\n",
  285. " data = {\n",
  286. " 'y': [misfit],\n",
  287. " 'x': [iiter],\n",
  288. " }\n",
  289. " line.data_source.stream(data)\n",
  290. "\n",
  291. " return misfit"
  292. ]
  293. },
  294. {
  295. "cell_type": "markdown",
  296. "metadata": {},
  297. "source": [
  298. "### Optimisation with SciPy\n",
  299. "We will use `scipy.optimize.differential_evolution` to find a best fitting model. The method is stochastic in nature (does not use gradient methods) to find the minimium, and can search large areas of candidate space, but often requires larger numbers of function evaluations than conventional gradient based techniques. The scipy solver can easily be exchanged for a method of your favor."
  300. ]
  301. },
  302. {
  303. "cell_type": "code",
  304. "execution_count": 10,
  305. "metadata": {},
  306. "outputs": [],
  307. "source": [
  308. "def solve():\n",
  309. " t = time.time()\n",
  310. "\n",
  311. " result = scipy.optimize.differential_evolution(\n",
  312. " trace_fit,\n",
  313. " args=[p],\n",
  314. " bounds=tuple(bounds.values()),\n",
  315. " maxiter=15000,\n",
  316. " tol=0.01,\n",
  317. " callback=update_plot)\n",
  318. "\n",
  319. " source = update_source(result.x)\n",
  320. " source.regularize()\n",
  321. "\n",
  322. " print(\"Time elapsed: %.1f s\" % (time.time() - t))\n",
  323. " print(\"Best model:\\n - Misfit %f\" % trace_fit(result.x))\n",
  324. " print(source)\n",
  325. " return result, source"
  326. ]
  327. },
  328. {
  329. "cell_type": "markdown",
  330. "metadata": {},
  331. "source": [
  332. "#### Plotting of the Convergence"
  333. ]
  334. },
  335. {
  336. "cell_type": "code",
  337. "execution_count": 11,
  338. "metadata": {},
  339. "outputs": [
  340. {
  341. "data": {
  342. "text/html": [
  343. "\n",
  344. " <div class=\"bk-root\">\n",
  345. " <a href=\"https://bokeh.pydata.org\" target=\"_blank\" class=\"bk-logo bk-logo-small bk-logo-notebook\"></a>\n",
  346. " <span id=\"f9db2f47-8d88-4d15-8f78-5d9f999696ae\">Loading BokehJS ...</span>\n",
  347. " </div>"
  348. ]
  349. },
  350. "metadata": {},
  351. "output_type": "display_data"
  352. },
  353. {
  354. "data": {
  355. "application/javascript": [
  356. "\n",
  357. "(function(root) {\n",
  358. " function now() {\n",
  359. " return new Date();\n",
  360. " }\n",
  361. "\n",
  362. " var force = true;\n",
  363. "\n",
  364. " if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n",
  365. " root._bokeh_onload_callbacks = [];\n",
  366. " root._bokeh_is_loading = undefined;\n",
  367. " }\n",
  368. "\n",
  369. " var JS_MIME_TYPE = 'application/javascript';\n",
  370. " var HTML_MIME_TYPE = 'text/html';\n",
  371. " var EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n",
  372. " var CLASS_NAME = 'output_bokeh rendered_html';\n",
  373. "\n",
  374. " /**\n",
  375. " * Render data to the DOM node\n",
  376. " */\n",
  377. " function render(props, node) {\n",
  378. " var script = document.createElement(\"script\");\n",
  379. " node.appendChild(script);\n",
  380. " }\n",
  381. "\n",
  382. " /**\n",
  383. " * Handle when an output is cleared or removed\n",
  384. " */\n",
  385. " function handleClearOutput(event, handle) {\n",
  386. " var cell = handle.cell;\n",
  387. "\n",
  388. " var id = cell.output_area._bokeh_element_id;\n",
  389. " var server_id = cell.output_area._bokeh_server_id;\n",
  390. " // Clean up Bokeh references\n",
  391. " if (id !== undefined) {\n",
  392. " Bokeh.index[id].model.document.clear();\n",
  393. " delete Bokeh.index[id];\n",
  394. " }\n",
  395. "\n",
  396. " if (server_id !== undefined) {\n",
  397. " // Clean up Bokeh references\n",
  398. " var cmd = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n",
  399. " cell.notebook.kernel.execute(cmd, {\n",
  400. " iopub: {\n",
  401. " output: function(msg) {\n",
  402. " var element_id = msg.content.text.trim();\n",
  403. " Bokeh.index[element_id].model.document.clear();\n",
  404. " delete Bokeh.index[element_id];\n",
  405. " }\n",
  406. " }\n",
  407. " });\n",
  408. " // Destroy server and session\n",
  409. " var cmd = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n",
  410. " cell.notebook.kernel.execute(cmd);\n",
  411. " }\n",
  412. " }\n",
  413. "\n",
  414. " /**\n",
  415. " * Handle when a new output is added\n",
  416. " */\n",
  417. " function handleAddOutput(event, handle) {\n",
  418. " var output_area = handle.output_area;\n",
  419. " var output = handle.output;\n",
  420. "\n",
  421. " // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n",
  422. " if ((output.output_type != \"display_data\") || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
  423. " return\n",
  424. " }\n",
  425. "\n",
  426. " var toinsert = output_area.element.find(`.${CLASS_NAME.split(' ')[0]}`);\n",
  427. "\n",
  428. " if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n",
  429. " toinsert[0].firstChild.textContent = output.data[JS_MIME_TYPE];\n",
  430. " // store reference to embed id on output_area\n",
  431. " output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
  432. " }\n",
  433. " if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n",
  434. " var bk_div = document.createElement(\"div\");\n",
  435. " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n",
  436. " var script_attrs = bk_div.children[0].attributes;\n",
  437. " for (var i = 0; i < script_attrs.length; i++) {\n",
  438. " toinsert[0].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n",
  439. " }\n",
  440. " // store reference to server id on output_area\n",
  441. " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n",
  442. " }\n",
  443. " }\n",
  444. "\n",
  445. " function register_renderer(events, OutputArea) {\n",
  446. "\n",
  447. " function append_mime(data, metadata, element) {\n",
  448. " // create a DOM node to render to\n",
  449. " var toinsert = this.create_output_subarea(\n",
  450. " metadata,\n",
  451. " CLASS_NAME,\n",
  452. " EXEC_MIME_TYPE\n",
  453. " );\n",
  454. " this.keyboard_manager.register_events(toinsert);\n",
  455. " // Render to node\n",
  456. " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
  457. " render(props, toinsert[0]);\n",
  458. " element.append(toinsert);\n",
  459. " return toinsert\n",
  460. " }\n",
  461. "\n",
  462. " /* Handle when an output is cleared or removed */\n",
  463. " events.on('clear_output.CodeCell', handleClearOutput);\n",
  464. " events.on('delete.Cell', handleClearOutput);\n",
  465. "\n",
  466. " /* Handle when a new output is added */\n",
  467. " events.on('output_added.OutputArea', handleAddOutput);\n",
  468. "\n",
  469. " /**\n",
  470. " * Register the mime type and append_mime function with output_area\n",
  471. " */\n",
  472. " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
  473. " /* Is output safe? */\n",
  474. " safe: true,\n",
  475. " /* Index of renderer in `output_area.display_order` */\n",
  476. " index: 0\n",
  477. " });\n",
  478. " }\n",
  479. "\n",
  480. " // register the mime type if in Jupyter Notebook environment and previously unregistered\n",
  481. " if (root.Jupyter !== undefined) {\n",
  482. " var events = require('base/js/events');\n",
  483. " var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
  484. "\n",
  485. " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
  486. " register_renderer(events, OutputArea);\n",
  487. " }\n",
  488. " }\n",
  489. "\n",
  490. " \n",
  491. " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n",
  492. " root._bokeh_timeout = Date.now() + 5000;\n",
  493. " root._bokeh_failed_load = false;\n",
  494. " }\n",
  495. "\n",
  496. " var NB_LOAD_WARNING = {'data': {'text/html':\n",
  497. " \"<div style='background-color: #fdd'>\\n\"+\n",
  498. " \"<p>\\n\"+\n",
  499. " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n",
  500. " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n",
  501. " \"</p>\\n\"+\n",
  502. " \"<ul>\\n\"+\n",
  503. " \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n",
  504. " \"<li>use INLINE resources instead, as so:</li>\\n\"+\n",
  505. " \"</ul>\\n\"+\n",
  506. " \"<code>\\n\"+\n",
  507. " \"from bokeh.resources import INLINE\\n\"+\n",
  508. " \"output_notebook(resources=INLINE)\\n\"+\n",
  509. " \"</code>\\n\"+\n",
  510. " \"</div>\"}};\n",
  511. "\n",
  512. " function display_loaded() {\n",
  513. " var el = document.getElementById(\"f9db2f47-8d88-4d15-8f78-5d9f999696ae\");\n",
  514. " if (el != null) {\n",
  515. " el.textContent = \"BokehJS is loading...\";\n",
  516. " }\n",
  517. " if (root.Bokeh !== undefined) {\n",
  518. " if (el != null) {\n",
  519. " el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n",
  520. " }\n",
  521. " } else if (Date.now() < root._bokeh_timeout) {\n",
  522. " setTimeout(display_loaded, 100)\n",
  523. " }\n",
  524. " }\n",
  525. "\n",
  526. "\n",
  527. " function run_callbacks() {\n",
  528. " try {\n",
  529. " root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n",
  530. " }\n",
  531. " finally {\n",
  532. " delete root._bokeh_onload_callbacks\n",
  533. " }\n",
  534. " console.info(\"Bokeh: all callbacks have finished\");\n",
  535. " }\n",
  536. "\n",
  537. " function load_libs(js_urls, callback) {\n",
  538. " root._bokeh_onload_callbacks.push(callback);\n",
  539. " if (root._bokeh_is_loading > 0) {\n",
  540. " console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n",
  541. " return null;\n",
  542. " }\n",
  543. " if (js_urls == null || js_urls.length === 0) {\n",
  544. " run_callbacks();\n",
  545. " return null;\n",
  546. " }\n",
  547. " console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n",
  548. " root._bokeh_is_loading = js_urls.length;\n",
  549. " for (var i = 0; i < js_urls.length; i++) {\n",
  550. " var url = js_urls[i];\n",
  551. " var s = document.createElement('script');\n",
  552. " s.src = url;\n",
  553. " s.async = false;\n",
  554. " s.onreadystatechange = s.onload = function() {\n",
  555. " root._bokeh_is_loading--;\n",
  556. " if (root._bokeh_is_loading === 0) {\n",
  557. " console.log(\"Bokeh: all BokehJS libraries loaded\");\n",
  558. " run_callbacks()\n",
  559. " }\n",
  560. " };\n",
  561. " s.onerror = function() {\n",
  562. " console.warn(\"failed to load library \" + url);\n",
  563. " };\n",
  564. " console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n",
  565. " document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
  566. " }\n",
  567. " };var element = document.getElementById(\"f9db2f47-8d88-4d15-8f78-5d9f999696ae\");\n",
  568. " if (element == null) {\n",
  569. " console.log(\"Bokeh: ERROR: autoload.js configured with elementid 'f9db2f47-8d88-4d15-8f78-5d9f999696ae' but no matching script tag was found. \")\n",
  570. " return false;\n",
  571. " }\n",
  572. "\n",
  573. " var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.10.min.js\"];\n",
  574. "\n",
  575. " var inline_js = [\n",
  576. " function(Bokeh) {\n",
  577. " Bokeh.set_log_level(\"info\");\n",
  578. " },\n",
  579. " \n",
  580. " function(Bokeh) {\n",
  581. " \n",
  582. " },\n",
  583. " function(Bokeh) {\n",
  584. " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n",
  585. " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n",
  586. " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n",
  587. " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n",
  588. " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n",
  589. " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n",
  590. " }\n",
  591. " ];\n",
  592. "\n",
  593. " function run_inline_js() {\n",
  594. " \n",
  595. " if ((root.Bokeh !== undefined) || (force === true)) {\n",
  596. " for (var i = 0; i < inline_js.length; i++) {\n",
  597. " inline_js[i].call(root, root.Bokeh);\n",
  598. " }if (force === true) {\n",
  599. " display_loaded();\n",
  600. " }} else if (Date.now() < root._bokeh_timeout) {\n",
  601. " setTimeout(run_inline_js, 100);\n",
  602. " } else if (!root._bokeh_failed_load) {\n",
  603. " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n",
  604. " root._bokeh_failed_load = true;\n",
  605. " } else if (force !== true) {\n",
  606. " var cell = $(document.getElementById(\"f9db2f47-8d88-4d15-8f78-5d9f999696ae\")).parents('.cell').data().cell;\n",
  607. " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n",
  608. " }\n",
  609. "\n",
  610. " }\n",
  611. "\n",
  612. " if (root._bokeh_is_loading === 0) {\n",
  613. " console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n",
  614. " run_inline_js();\n",
  615. " } else {\n",
  616. " load_libs(js_urls, function() {\n",
  617. " console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n",
  618. " run_inline_js();\n",
  619. " });\n",
  620. " }\n",
  621. "}(window));"
  622. ],
  623. "application/vnd.bokehjs_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n \n\n \n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n var NB_LOAD_WARNING = {'data': {'text/html':\n \"<div style='background-color: #fdd'>\\n\"+\n \"<p>\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"</p>\\n\"+\n \"<ul>\\n\"+\n \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n \"<li>use INLINE resources instead, as so:</li>\\n\"+\n \"</ul>\\n\"+\n \"<code>\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"</code>\\n\"+\n \"</div>\"}};\n\n function display_loaded() {\n var el = document.getElementById(\"f9db2f47-8d88-4d15-8f78-5d9f999696ae\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n }\n finally {\n delete root._bokeh_onload_callbacks\n }\n console.info(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(js_urls, callback) {\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = js_urls.length;\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n var s = document.createElement('script');\n s.src = url;\n s.async = false;\n s.onreadystatechange = s.onload = function() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.log(\"Bokeh: all BokehJS libraries loaded\");\n run_callbacks()\n }\n };\n s.onerror = function() {\n console.warn(\"failed to load library \" + url);\n };\n console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.getElementsByTagName(\"head\")[0].appendChild(s);\n }\n };var element = document.getElementById(\"f9db2f47-8d88-4d15-8f78-5d9f999696ae\");\n if (element == null) {\n console.log(\"Bokeh: ERROR: autoload.js configured with elementid 'f9db2f47-8d88-4d15-8f78-5d9f999696ae' but no matching script tag was found. \")\n return false;\n }\n\n var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.10.min.js\"];\n\n var inline_js = [\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n \n function(Bokeh) {\n \n },\n function(Bokeh) {\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n }\n ];\n\n function run_inline_js() {\n \n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }if (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n var cell = $(document.getElementById(\"f9db2f47-8d88-4d15-8f78-5d9f999696ae\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n\n }\n\n if (root._bokeh_is_loading === 0) {\n console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(js_urls, function() {\n console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));"
  624. },
  625. "metadata": {},
  626. "output_type": "display_data"
  627. },
  628. {
  629. "data": {
  630. "text/html": [
  631. "\n",
  632. "<div class=\"bk-root\">\n",
  633. " <div class=\"bk-plotdiv\" id=\"3e112633-3534-4715-9c43-f2e6a98123f9\"></div>\n",
  634. "</div>"
  635. ]
  636. },
  637. "metadata": {},
  638. "output_type": "display_data"
  639. },
  640. {
  641. "data": {
  642. "application/javascript": [
  643. "(function(root) {\n",
  644. " function embed_document(root) {\n",
  645. " var docs_json = {\"0d0c4b29-c831-496b-93ff-f023ac0ec217\":{\"roots\":{\"references\":[{\"attributes\":{},\"id\":\"d8795c77-dfe0-469a-9d4b-917fea97222e\",\"type\":\"WheelZoomTool\"},{\"attributes\":{\"overlay\":{\"id\":\"591a3f9c-3bec-4e3d-b1aa-ba18d91613f1\",\"type\":\"BoxAnnotation\"}},\"id\":\"1c2acb3d-5cfc-4a65-b572-ae73c531b203\",\"type\":\"BoxZoomTool\"},{\"attributes\":{\"callback\":null},\"id\":\"43795493-1573-4724-8557-5d4423f3997f\",\"type\":\"DataRange1d\"},{\"attributes\":{\"fill_color\":{\"value\":\"#1f77b4\"},\"line_color\":{\"value\":\"#1f77b4\"},\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"62277b33-498b-4540-851e-2bd5324e973a\",\"type\":\"Circle\"},{\"attributes\":{},\"id\":\"7397e895-5621-4802-b234-63ab24a3068e\",\"type\":\"SaveTool\"},{\"attributes\":{},\"id\":\"296bf993-8722-445c-9cbc-5c02787711fb\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{},\"id\":\"7e40bab9-4e03-4363-a8fe-82ffd0b242a1\",\"type\":\"LinearScale\"},{\"attributes\":{},\"id\":\"7218f21b-918f-4099-a7a0-2906f354f9dc\",\"type\":\"ResetTool\"},{\"attributes\":{\"below\":[{\"id\":\"ef34c75e-7a5f-480c-bb25-d5b8ed0cf19c\",\"type\":\"LinearAxis\"}],\"left\":[{\"id\":\"74ef230f-48f5-4d60-959f-3c5a6afa7c4d\",\"type\":\"LinearAxis\"}],\"plot_height\":300,\"plot_width\":800,\"renderers\":[{\"id\":\"ef34c75e-7a5f-480c-bb25-d5b8ed0cf19c\",\"type\":\"LinearAxis\"},{\"id\":\"f64bd652-25cd-401a-ae5c-b01a026f14a9\",\"type\":\"Grid\"},{\"id\":\"74ef230f-48f5-4d60-959f-3c5a6afa7c4d\",\"type\":\"LinearAxis\"},{\"id\":\"29f02010-e8a6-473e-916b-1cd6ac2e4e07\",\"type\":\"Grid\"},{\"id\":\"591a3f9c-3bec-4e3d-b1aa-ba18d91613f1\",\"type\":\"BoxAnnotation\"},{\"id\":\"1605f826-d8c0-476b-b783-55911bec3344\",\"type\":\"GlyphRenderer\"}],\"title\":{\"id\":\"4d592563-e836-47fe-a815-ccf3364d49d0\",\"type\":\"Title\"},\"toolbar\":{\"id\":\"ea8c9906-ad2f-456d-a66d-08570ff15c4a\",\"type\":\"Toolbar\"},\"x_range\":{\"id\":\"860f57a9-a435-45af-bf8f-bbebac4186ed\",\"type\":\"DataRange1d\"},\"x_scale\":{\"id\":\"7e40bab9-4e03-4363-a8fe-82ffd0b242a1\",\"type\":\"LinearScale\"},\"y_range\":{\"id\":\"43795493-1573-4724-8557-5d4423f3997f\",\"type\":\"DataRange1d\"},\"y_scale\":{\"id\":\"8452e5ca-a00d-47a9-a6e7-ec86fdc1ad2d\",\"type\":\"LinearScale\"}},\"id\":\"bba1f9da-6705-484b-9fd2-ea20b8a43a4a\",\"subtype\":\"Figure\",\"type\":\"Plot\"},{\"attributes\":{},\"id\":\"bb2f3e1c-34ef-45ad-a550-50c579415eef\",\"type\":\"HelpTool\"},{\"attributes\":{},\"id\":\"8452e5ca-a00d-47a9-a6e7-ec86fdc1ad2d\",\"type\":\"LinearScale\"},{\"attributes\":{\"axis_label\":\"# Iteration\",\"formatter\":{\"id\":\"66d53f26-354e-46f4-aa47-20e79e783c74\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"bba1f9da-6705-484b-9fd2-ea20b8a43a4a\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"f7e2ed4f-98c2-4522-8687-c65aa9c46482\",\"type\":\"BasicTicker\"}},\"id\":\"ef34c75e-7a5f-480c-bb25-d5b8ed0cf19c\",\"type\":\"LinearAxis\"},{\"attributes\":{\"source\":{\"id\":\"102e4428-3ff3-43dc-afa6-a75f55966abb\",\"type\":\"ColumnDataSource\"}},\"id\":\"cfc40f94-84a8-4a85-99a0-e91172da0a20\",\"type\":\"CDSView\"},{\"attributes\":{},\"id\":\"66d53f26-354e-46f4-aa47-20e79e783c74\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{},\"id\":\"f7e2ed4f-98c2-4522-8687-c65aa9c46482\",\"type\":\"BasicTicker\"},{\"attributes\":{\"plot\":{\"id\":\"bba1f9da-6705-484b-9fd2-ea20b8a43a4a\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"f7e2ed4f-98c2-4522-8687-c65aa9c46482\",\"type\":\"BasicTicker\"}},\"id\":\"f64bd652-25cd-401a-ae5c-b01a026f14a9\",\"type\":\"Grid\"},{\"attributes\":{\"axis_label\":\"Misfit\",\"formatter\":{\"id\":\"296bf993-8722-445c-9cbc-5c02787711fb\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"bba1f9da-6705-484b-9fd2-ea20b8a43a4a\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"fb9a8d7e-3184-4ab6-897c-269fdb881ed7\",\"type\":\"BasicTicker\"}},\"id\":\"74ef230f-48f5-4d60-959f-3c5a6afa7c4d\",\"type\":\"LinearAxis\"},{\"attributes\":{},\"id\":\"fb9a8d7e-3184-4ab6-897c-269fdb881ed7\",\"type\":\"BasicTicker\"},{\"attributes\":{\"dimension\":1,\"plot\":{\"id\":\"bba1f9da-6705-484b-9fd2-ea20b8a43a4a\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"fb9a8d7e-3184-4ab6-897c-269fdb881ed7\",\"type\":\"BasicTicker\"}},\"id\":\"29f02010-e8a6-473e-916b-1cd6ac2e4e07\",\"type\":\"Grid\"},{\"attributes\":{\"bottom_units\":\"screen\",\"fill_alpha\":{\"value\":0.5},\"fill_color\":{\"value\":\"lightgrey\"},\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":{\"value\":1.0},\"line_color\":{\"value\":\"black\"},\"line_dash\":[4,4],\"line_width\":{\"value\":2},\"plot\":null,\"render_mode\":\"css\",\"right_units\":\"screen\",\"top_units\":\"screen\"},\"id\":\"591a3f9c-3bec-4e3d-b1aa-ba18d91613f1\",\"type\":\"BoxAnnotation\"},{\"attributes\":{\"callback\":null},\"id\":\"860f57a9-a435-45af-bf8f-bbebac4186ed\",\"type\":\"DataRange1d\"},{\"attributes\":{\"fill_alpha\":{\"value\":0.1},\"fill_color\":{\"value\":\"#1f77b4\"},\"line_alpha\":{\"value\":0.1},\"line_color\":{\"value\":\"#1f77b4\"},\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"8f6f54e3-2088-4047-8e6c-e048a03fbd3c\",\"type\":\"Circle\"},{\"attributes\":{\"plot\":null,\"text\":\"SciPy Optimisation Progress\"},\"id\":\"4d592563-e836-47fe-a815-ccf3364d49d0\",\"type\":\"Title\"},{\"attributes\":{\"data_source\":{\"id\":\"102e4428-3ff3-43dc-afa6-a75f55966abb\",\"type\":\"ColumnDataSource\"},\"glyph\":{\"id\":\"62277b33-498b-4540-851e-2bd5324e973a\",\"type\":\"Circle\"},\"hover_glyph\":null,\"muted_glyph\":null,\"nonselection_glyph\":{\"id\":\"8f6f54e3-2088-4047-8e6c-e048a03fbd3c\",\"type\":\"Circle\"},\"selection_glyph\":null,\"view\":{\"id\":\"cfc40f94-84a8-4a85-99a0-e91172da0a20\",\"type\":\"CDSView\"}},\"id\":\"1605f826-d8c0-476b-b783-55911bec3344\",\"type\":\"GlyphRenderer\"},{\"attributes\":{\"active_drag\":\"auto\",\"active_inspect\":\"auto\",\"active_scroll\":\"auto\",\"active_tap\":\"auto\",\"tools\":[{\"id\":\"00425ede-dcd9-489c-9bd4-44c7b8481ee7\",\"type\":\"PanTool\"},{\"id\":\"d8795c77-dfe0-469a-9d4b-917fea97222e\",\"type\":\"WheelZoomTool\"},{\"id\":\"1c2acb3d-5cfc-4a65-b572-ae73c531b203\",\"type\":\"BoxZoomTool\"},{\"id\":\"7397e895-5621-4802-b234-63ab24a3068e\",\"type\":\"SaveTool\"},{\"id\":\"7218f21b-918f-4099-a7a0-2906f354f9dc\",\"type\":\"ResetTool\"},{\"id\":\"bb2f3e1c-34ef-45ad-a550-50c579415eef\",\"type\":\"HelpTool\"}]},\"id\":\"ea8c9906-ad2f-456d-a66d-08570ff15c4a\",\"type\":\"Toolbar\"},{\"attributes\":{\"callback\":null,\"column_names\":[\"x\",\"y\"],\"data\":{\"x\":[],\"y\":[]}},\"id\":\"102e4428-3ff3-43dc-afa6-a75f55966abb\",\"type\":\"ColumnDataSource\"},{\"attributes\":{},\"id\":\"00425ede-dcd9-489c-9bd4-44c7b8481ee7\",\"type\":\"PanTool\"}],\"root_ids\":[\"bba1f9da-6705-484b-9fd2-ea20b8a43a4a\"]},\"title\":\"Bokeh Application\",\"version\":\"0.12.10\"}};\n",
  646. " var render_items = [{\"docid\":\"0d0c4b29-c831-496b-93ff-f023ac0ec217\",\"elementid\":\"3e112633-3534-4715-9c43-f2e6a98123f9\",\"modelid\":\"bba1f9da-6705-484b-9fd2-ea20b8a43a4a\",\"notebook_comms_target\":\"349cb6f0-e892-4ab3-a5cf-9b4f6f5a465d\"}];\n",
  647. "\n",
  648. " root.Bokeh.embed.embed_items(docs_json, render_items);\n",
  649. " }\n",
  650. "\n",
  651. " if (root.Bokeh !== undefined) {\n",
  652. " embed_document(root);\n",
  653. " } else {\n",
  654. " var attempts = 0;\n",
  655. " var timer = setInterval(function(root) {\n",
  656. " if (root.Bokeh !== undefined) {\n",
  657. " embed_document(root);\n",
  658. " clearInterval(timer);\n",
  659. " }\n",
  660. " attempts++;\n",
  661. " if (attempts > 100) {\n",
  662. " console.log(\"Bokeh: ERROR: Unable to embed document because BokehJS library is missing\")\n",
  663. " clearInterval(timer);\n",
  664. " }\n",
  665. " }, 10, root)\n",
  666. " }\n",
  667. "})(window);"
  668. ],
  669. "application/vnd.bokehjs_exec.v0+json": ""
  670. },
  671. "metadata": {
  672. "application/vnd.bokehjs_exec.v0+json": {
  673. "id": "bba1f9da-6705-484b-9fd2-ea20b8a43a4a"
  674. }
  675. },
  676. "output_type": "display_data"
  677. },
  678. {
  679. "name": "stdout",
  680. "output_type": "stream",
  681. "text": [
  682. "Time elapsed: 220.7 s\n",
  683. "Best model:\n",
  684. " - Misfit 1.195396\n",
  685. "--- !pf.DCSource\n",
  686. "lat: 42.29\n",
  687. "lon: 13.35\n",
  688. "north_shift: 18598.647382347528\n",
  689. "east_shift: -12384.974641269735\n",
  690. "depth: 3025.7694885988553\n",
  691. "time: 2009-04-06 01:32:54.999995\n",
  692. "stf_mode: post\n",
  693. "magnitude: 6.200494965363762\n",
  694. "strike: 100.30898362804017\n",
  695. "dip: 59.63065062216228\n",
  696. "rake: -149.96402678887372\n",
  697. "\n"
  698. ]
  699. }
  700. ],
  701. "source": [
  702. "from bokeh.io import push_notebook, show, output_notebook\n",
  703. "from bokeh.plotting import figure\n",
  704. "output_notebook()\n",
  705. "\n",
  706. "f = figure(title='SciPy Optimisation Progress',\n",
  707. " x_axis_label='# Iteration',\n",
  708. " y_axis_label='Misfit',\n",
  709. " plot_width=800,\n",
  710. " plot_height=300)\n",
  711. "p = f.scatter([], [])\n",
  712. "show(f, notebook_handle=True)\n",
  713. "\n",
  714. "def update_plot(*a, **ka):\n",
  715. " push_notebook()\n",
  716. "\n",
  717. "# Start the optimisation\n",
  718. "result, best_source = solve()"
  719. ]
  720. },
  721. {
  722. "cell_type": "markdown",
  723. "metadata": {},
  724. "source": [
  725. "### Plot the Results\n",
  726. "Now we plot the synthetic waveforms produced by our the best model vs. the observed traces."
  727. ]
  728. },
  729. {
  730. "cell_type": "code",
  731. "execution_count": null,
  732. "metadata": {},
  733. "outputs": [],
  734. "source": [
  735. "def plot_traces(result):\n",
  736. " nstations = len(stations_list)\n",
  737. " response = engine.process(source, targets)\n",
  738. " syn_traces = response.pyrocko_traces()\n",
  739. "\n",
  740. " fig, axes = plt.subplots(nstations, squeeze=True, sharex=True)\n",
  741. " fig.subplots_adjust(hspace=0)\n",
  742. " plt.setp([ax.get_xticklabels() for ax in axes[:-1]], visible=False)\n",
  743. "\n",
  744. " for istation, (obs, syn, target) in enumerate(zip(traces, syn_traces, targets)):\n",
  745. " ax = axes[istation]\n",
  746. " tp = store.t(phase, base_source, target)\n",
  747. " tp_onset = base_source.time + tp\n",
  748. " tmin = tp_onset - tmin_fit\n",
  749. " tmax = tp_onset + tmax_fit\n",
  750. " \n",
  751. " syn = process_trace(syn, tmin, tmax)\n",
  752. " obs = process_trace(obs, tmin, tmax, lowpass=False, inplace=False)\n",
  753. " \n",
  754. " s1 = ax.plot(obs.get_xdata(), obs.ydata, color='b')\n",
  755. " s2 = ax.plot(syn.get_xdata(), syn.ydata, color='r')\n",
  756. " s3 = ax.plot([tp_onset, tp_onset], [tr.ydata.min(), tr.ydata.max()], 'k-', lw=2)\n",
  757. "\n",
  758. " ax.text(-.2, 0.5, stations_list[istation].station,\n",
  759. " transform=ax.transAxes)\n",
  760. " ax.set_yticklabels([], visible=False)\n",
  761. "\n",
  762. " axes[-1].set_xlabel('Time [s]')\n",
  763. " plt.suptitle('Waveform fits for %s-Phase and component %s' % (phase, component))\n",
  764. " plt.legend(\n",
  765. " (s1[0], s2[0], s3[0]),\n",
  766. " ('Data', 'Synthetic','%s Phase-onset' % phase),\n",
  767. " loc='upper center',\n",
  768. " bbox_to_anchor=(0.5, -2.),\n",
  769. " fancybox=True, shadow=True, ncol=5)\n",
  770. " \n",
  771. " plt.show()"
  772. ]
  773. },
  774. {
  775. "cell_type": "code",
  776. "execution_count": null,
  777. "metadata": {},
  778. "outputs": [],
  779. "source": [
  780. "def plot_snuffler(result, source):\n",
  781. " engine = gf.get_engine()\n",
  782. " response = engine.process(source, targets)\n",
  783. " syn_traces = response.pyrocko_traces()\n",
  784. " obs_traces = []\n",
  785. " \n",
  786. " for obs, syn, target in zip(traces, syn_traces, targets):\n",
  787. " tp = store.t('P', base_source, target)\n",
  788. " tmin = base_source.time + tp - tmin_fit\n",
  789. " tmax = base_source.time + tp + tmax_fit\n",
  790. "\n",
  791. " syn = process_trace(syn, tmin, tmax)\n",
  792. " obs = process_trace(obs, tmin, tmax, lowpass=False, inplace=False)\n",
  793. "\n",
  794. " obs_traces.append(obs)\n",
  795. "\n",
  796. " trace.snuffle(obs_traces + syn_traces, stations=stations_list, events=events)"
  797. ]
  798. },
  799. {
  800. "cell_type": "markdown",
  801. "metadata": {},
  802. "source": [
  803. "Next we plot the station distribution with https://matplotlib.org/basemap/"
  804. ]
  805. },
  806. {
  807. "cell_type": "code",
  808. "execution_count": 51,
  809. "metadata": {},
  810. "outputs": [
  811. {
  812. "data": {
  813. "text/html": [
  814. "<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><iframe src=\"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVMgPSBmYWxzZTsgTF9OT19UT1VDSCA9IGZhbHNlOyBMX0RJU0FCTEVfM0QgPSBmYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmNzcyIgLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC5taW4uY3NzIiAvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLXRoZW1lLm1pbi5jc3MiIC8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIgLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuY3NzIiAvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL3Jhd2dpdC5jb20vcHl0aG9uLXZpc3VhbGl6YXRpb24vZm9saXVtL21hc3Rlci9mb2xpdW0vdGVtcGxhdGVzL2xlYWZsZXQuYXdlc29tZS5yb3RhdGUuY3NzIiAvPgogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIAogICAgICAgICAgICA8c3R5bGU+ICNtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcgewogICAgICAgICAgICAgICAgcG9zaXRpb24gOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgIHdpZHRoIDogMTAwLjAlOwogICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAuMCU7CiAgICAgICAgICAgICAgICBsZWZ0OiAwLjAlOwogICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3IiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGJvdW5kcyA9IG51bGw7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgdmFyIG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0NyA9IEwubWFwKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0NycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7Y2VudGVyOiBbNDIuMjksMTMuMzVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgem9vbTogMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heEJvdW5kczogYm91bmRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXJzOiBbXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkQ29weUp1bXA6IGZhbHNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JzOiBMLkNSUy5FUFNHMzg1NwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHRpbGVfbGF5ZXJfY2FkNDI5MTU0ZDUxNGEzYTkwMmI3NDhiYTcwYjk2Y2QgPSBMLnRpbGVMYXllcigKICAgICAgICAgICAgICAgICdodHRwczovL3N0YW1lbi10aWxlcy17c30uYS5zc2wuZmFzdGx5Lm5ldC90ZXJyYWluL3t6fS97eH0ve3l9LmpwZycsCiAgICAgICAgICAgICAgICB7CiAgImF0dHJpYnV0aW9uIjogbnVsbCwKICAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsCiAgIm1heFpvb20iOiAxOCwKICAibWluWm9vbSI6IDEsCiAgIm5vV3JhcCI6IGZhbHNlLAogICJzdWJkb21haW5zIjogImFiYyIKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzEzZTVmYjlmZTUxZTQ1MGQ4YmQxMGMzMjI1OTM5ZTViID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDIuMjksMTMuMzVdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fMGU0YzNmNWFkNjkwNDNhOTliYjY0MzJiMTUwYzc3OGMgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICdpbmZvLXNpZ24nLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ3JlZCcsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8xM2U1ZmI5ZmU1MWU0NTBkOGJkMTBjMzIyNTkzOWU1Yi5zZXRJY29uKGljb25fMGU0YzNmNWFkNjkwNDNhOTliYjY0MzJiMTUwYzc3OGMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMWE4OTA1ODZjZjFhNGI3YzkxNTcwN2YxMzk2ZWMzODIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZmJkYzZhOWFmOGM3NDI1ZmJjNTk0MGE1YWIyODdhNzYgPSAkKCc8ZGl2IGlkPSJodG1sX2ZiZGM2YTlhZjhjNzQyNWZiYzU5NDBhNWFiMjg3YTc2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij4yMDA5IEFxdWlsYSBFYXJ0aHF1YWtlPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xYTg5MDU4NmNmMWE0YjdjOTE1NzA3ZjEzOTZlYzM4Mi5zZXRDb250ZW50KGh0bWxfZmJkYzZhOWFmOGM3NDI1ZmJjNTk0MGE1YWIyODdhNzYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8xM2U1ZmI5ZmU1MWU0NTBkOGJkMTBjMzIyNTkzOWU1Yi5iaW5kUG9wdXAocG9wdXBfMWE4OTA1ODZjZjFhNGI3YzkxNTcwN2YxMzk2ZWMzODIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNTk0YTU5ODI1ZDhiNDhkMDk4ZmRmZWU3YmM4YjNiMDMgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs2NS41NTk4LC0xNjcuOTI2N10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzExYjY3ZWY2OWFiZTQ1NWM4NzBmZDg0OWIzMzg2MTgzID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzM3Yzk3ZWU5NGFhNTQ4Y2JhOGMxNTk2M2YzYjg5MzU3ID0gJCgnPGRpdiBpZD0iaHRtbF8zN2M5N2VlOTRhYTU0OGNiYThjMTU5NjNmM2I4OTM1NyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+VE5BPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xMWI2N2VmNjlhYmU0NTVjODcwZmQ4NDliMzM4NjE4My5zZXRDb250ZW50KGh0bWxfMzdjOTdlZTk0YWE1NDhjYmE4YzE1OTYzZjNiODkzNTcpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl81OTRhNTk4MjVkOGI0OGQwOThmZGZlZTdiYzhiM2IwMy5iaW5kUG9wdXAocG9wdXBfMTFiNjdlZjY5YWJlNDU1Yzg3MGZkODQ5YjMzODYxODMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMmIyYTVkMjZhYzg3NGZiZmI0NGE0YjU2NzdmZjg2NGYgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs1NS40Njg5NCwtMTMzLjEyMjk3XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOWVkYmJmYWFlYzU0NDM3YmE1MTIwMGEzYjRlMjQ4NWMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYTQ4M2MwMDcxNDhhNDUwODljYzc4NzI0NjdhMzVhYzQgPSAkKCc8ZGl2IGlkPSJodG1sX2E0ODNjMDA3MTQ4YTQ1MDg5Y2M3ODcyNDY3YTM1YWM0IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5DUkFHPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF85ZWRiYmZhYWVjNTQ0MzdiYTUxMjAwYTNiNGUyNDg1Yy5zZXRDb250ZW50KGh0bWxfYTQ4M2MwMDcxNDhhNDUwODljYzc4NzI0NjdhMzVhYzQpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8yYjJhNWQyNmFjODc0ZmJmYjQ0YTRiNTY3N2ZmODY0Zi5iaW5kUG9wdXAocG9wdXBfOWVkYmJmYWFlYzU0NDM3YmE1MTIwMGEzYjRlMjQ4NWMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNmUwMGY5YTlkYWRhNDgxY2IwZWVjNjJkZjY3NzI0MjUgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0OS4yNTYsLTU3LjUwNDJdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8wMWQ2NzI1YzBiZTU0ZjZlYmE4MWQxMGZjMTkxNDNiNSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9mNzZkMjEwMzEyMmU0YmE5OWI0YTk3NmYxNjFjNzhkYiA9ICQoJzxkaXYgaWQ9Imh0bWxfZjc2ZDIxMDMxMjJlNGJhOTliNGE5NzZmMTYxYzc4ZGIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkRSTE48L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzAxZDY3MjVjMGJlNTRmNmViYTgxZDEwZmMxOTE0M2I1LnNldENvbnRlbnQoaHRtbF9mNzZkMjEwMzEyMmU0YmE5OWI0YTk3NmYxNjFjNzhkYik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzZlMDBmOWE5ZGFkYTQ4MWNiMGVlYzYyZGY2NzcyNDI1LmJpbmRQb3B1cChwb3B1cF8wMWQ2NzI1YzBiZTU0ZjZlYmE4MWQxMGZjMTkxNDNiNSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl83NDFiZTc1M2ExMjQ0YThlYTJhNTAxNDliYWEzMWY5ZSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzY4LjMwNjUsLTEzMy41MjU0XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNzMwMDZiYjAzOWNhNDNhMDhjYjg5ZGRjMGM1MDA4YzIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYWNiZGVhMGMxMWM0NDAyMDgyNzcwMGJiYjZmYjA5MjUgPSAkKCc8ZGl2IGlkPSJodG1sX2FjYmRlYTBjMTFjNDQwMjA4Mjc3MDBiYmI2ZmIwOTI1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5JTks8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzczMDA2YmIwMzljYTQzYTA4Y2I4OWRkYzBjNTAwOGMyLnNldENvbnRlbnQoaHRtbF9hY2JkZWEwYzExYzQ0MDIwODI3NzAwYmJiNmZiMDkyNSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzc0MWJlNzUzYTEyNDRhOGVhMmE1MDE0OWJhYTMxZjllLmJpbmRQb3B1cChwb3B1cF83MzAwNmJiMDM5Y2E0M2EwOGNiODlkZGMwYzUwMDhjMik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl83YWE4Y2U2MWY2MzQ0NDY5OGQ3ZDU0Y2RiOTRiNzVkMCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzc0LjY4OTIsLTk0Ljg5NjJdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hYWQyYTVmOTRlMjI0ZTM5YTlmMWE1ZTQ3MTQ5MzI1NiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF84MTczYmY2MmU5MTM0YzJjOTdjYzJkYTllNjM4N2I1ZCA9ICQoJzxkaXYgaWQ9Imh0bWxfODE3M2JmNjJlOTEzNGMyYzk3Y2MyZGE5ZTYzODdiNWQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlJFUzwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYWFkMmE1Zjk0ZTIyNGUzOWE5ZjFhNWU0NzE0OTMyNTYuc2V0Q29udGVudChodG1sXzgxNzNiZjYyZTkxMzRjMmM5N2NjMmRhOWU2Mzg3YjVkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfN2FhOGNlNjFmNjM0NDQ2OThkN2Q1NGNkYjk0Yjc1ZDAuYmluZFBvcHVwKHBvcHVwX2FhZDJhNWY5NGUyMjRlMzlhOWYxYTVlNDcxNDkzMjU2KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzU0YjQ1MTQ5M2EzMTQ2ODU4MjgyMTRiY2IxNGQ4Mjk4ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbMTcuNjY4NTMsLTYxLjc4NTU3XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZmQ4NjVmNmU3ZmM4NDhkMDgxYzdlY2U2YzA0NTY5YjggPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMmE1OGI1N2I4NmJhNDdkMDg3ZGI0NTQzMDU2MjQ1YTYgPSAkKCc8ZGl2IGlkPSJodG1sXzJhNThiNTdiODZiYTQ3ZDA4N2RiNDU0MzA1NjI0NWE2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5BTldCPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9mZDg2NWY2ZTdmYzg0OGQwODFjN2VjZTZjMDQ1NjliOC5zZXRDb250ZW50KGh0bWxfMmE1OGI1N2I4NmJhNDdkMDg3ZGI0NTQzMDU2MjQ1YTYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl81NGI0NTE0OTNhMzE0Njg1ODI4MjE0YmNiMTRkODI5OC5iaW5kUG9wdXAocG9wdXBfZmQ4NjVmNmU3ZmM4NDhkMDgxYzdlY2U2YzA0NTY5YjgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfYjlkY2YzNzg4OWQ0NDViN2E3OGZlYjJjYTVmOGQ3MmUgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFsyMS41MTE0OSwtNzEuMTMyN10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzJhYWY4NmMwYjAyMTRlZWY5MzgyNTBlOWZjNWFkOTdlID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzRiZjE5NjhkZWQ5NzRjNGU4OTU1MDI0M2NmMWRlMzA3ID0gJCgnPGRpdiBpZD0iaHRtbF80YmYxOTY4ZGVkOTc0YzRlODk1NTAyNDNjZjFkZTMwNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+R1JUSzwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMmFhZjg2YzBiMDIxNGVlZjkzODI1MGU5ZmM1YWQ5N2Uuc2V0Q29udGVudChodG1sXzRiZjE5NjhkZWQ5NzRjNGU4OTU1MDI0M2NmMWRlMzA3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfYjlkY2YzNzg4OWQ0NDViN2E3OGZlYjJjYTVmOGQ3MmUuYmluZFBvcHVwKHBvcHVwXzJhYWY4NmMwYjAyMTRlZWY5MzgyNTBlOWZjNWFkOTdlKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2ZmNjdkNzRjMzY3OTQ2OWJiMmZkOTM0ZTQ4OTE3YzdiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbMTguMjI2MDUsLTc3LjUzNDU0XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNmE5MDIxZmI1OWY1NGU3NWFkYjVlMzM2ZjFlODUxYmUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZGVjNDY4YzhmMmE4NGQxYTg2MGY5NjIwZGJjM2NlZjkgPSAkKCc8ZGl2IGlkPSJodG1sX2RlYzQ2OGM4ZjJhODRkMWE4NjBmOTYyMGRiYzNjZWY5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5NVERKPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF82YTkwMjFmYjU5ZjU0ZTc1YWRiNWUzMzZmMWU4NTFiZS5zZXRDb250ZW50KGh0bWxfZGVjNDY4YzhmMmE4NGQxYTg2MGY5NjIwZGJjM2NlZjkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9mZjY3ZDc0YzM2Nzk0NjliYjJmZDkzNGU0ODkxN2M3Yi5iaW5kUG9wdXAocG9wdXBfNmE5MDIxZmI1OWY1NGU3NWFkYjVlMzM2ZjFlODUxYmUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMWQ4YTFlZWU2M2Y4NDZjZDgxOTg5ZWUyMTIwNTViZDMgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFsxNC4zOTIwMiwtMTYuOTU1NDddLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mZDM2NTE2OWVmZmE0NzA3YWVhMWRmY2RjY2Q2YTE5NyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81MzY3ZmI5YThlNTc0MGE5OGQ4OTI0MjA5ZTRjYTUxZCA9ICQoJzxkaXYgaWQ9Imh0bWxfNTM2N2ZiOWE4ZTU3NDBhOThkODkyNDIwOWU0Y2E1MWQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPk1CTzwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZmQzNjUxNjllZmZhNDcwN2FlYTFkZmNkY2NkNmExOTcuc2V0Q29udGVudChodG1sXzUzNjdmYjlhOGU1NzQwYTk4ZDg5MjQyMDllNGNhNTFkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMWQ4YTFlZWU2M2Y4NDZjZDgxOTg5ZWUyMTIwNTViZDMuYmluZFBvcHVwKHBvcHVwX2ZkMzY1MTY5ZWZmYTQ3MDdhZWExZGZjZGNjZDZhMTk3KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzkyMDRmZTlkYzAyMzRmZGRiYTNmZDMwMjllZGE4MzI2ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNzguOTE1NCwxMS45Mzg1XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNjUyZjYxYmZhYzMzNDk1ZDkyYzc2YmZjN2RkZGU0YWQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMWE1MTRiZmRhOGE4NGY4NmE2NDQxZThiZjE4NTAwZmIgPSAkKCc8ZGl2IGlkPSJodG1sXzFhNTE0YmZkYThhODRmODZhNjQ0MWU4YmYxODUwMGZiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5LQlM8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzY1MmY2MWJmYWMzMzQ5NWQ5MmM3NmJmYzdkZGRlNGFkLnNldENvbnRlbnQoaHRtbF8xYTUxNGJmZGE4YTg0Zjg2YTY0NDFlOGJmMTg1MDBmYik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzkyMDRmZTlkYzAyMzRmZGRiYTNmZDMwMjllZGE4MzI2LmJpbmRQb3B1cChwb3B1cF82NTJmNjFiZmFjMzM0OTVkOTJjNzZiZmM3ZGRkZTRhZCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8zZmZlZDIwNmZhNGY0NjI2OGY3ZjMzOWQxNzc1M2QyZCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWy0xLjEyNjgsMzcuMjUyM10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzU1MDhmMWYwOWZlYjQwMWNiNDNhZTNkZTIzOTQ0ZmRlID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzU3NTg4OWU3YzE3ZDRkNmY5MzZmNTcwYmM1Mzg2NDU1ID0gJCgnPGRpdiBpZD0iaHRtbF81NzU4ODllN2MxN2Q0ZDZmOTM2ZjU3MGJjNTM4NjQ1NSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+S01CTzwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNTUwOGYxZjA5ZmViNDAxY2I0M2FlM2RlMjM5NDRmZGUuc2V0Q29udGVudChodG1sXzU3NTg4OWU3YzE3ZDRkNmY5MzZmNTcwYmM1Mzg2NDU1KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfM2ZmZWQyMDZmYTRmNDYyNjhmN2YzMzlkMTc3NTNkMmQuYmluZFBvcHVwKHBvcHVwXzU1MDhmMWYwOWZlYjQwMWNiNDNhZTNkZTIzOTQ0ZmRlKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzVjNGZmNGY4NDBlYTQwOGM5ODRmMzBmZDE0ZmUzODUyID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNS4yMjg4LDk2Ljk0NzJdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jNjdlMGY3OWViZjA0MGJhOTg1YzA0M2U2OTEyMTNjYyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF80ZTk1MjhiNWU5OTA0NjI0YmJlNDYxNTMzNjdhNmQzZSA9ICQoJzxkaXYgaWQ9Imh0bWxfNGU5NTI4YjVlOTkwNDYyNGJiZTQ2MTUzMzY3YTZkM2UiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkxITUk8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2M2N2UwZjc5ZWJmMDQwYmE5ODVjMDQzZTY5MTIxM2NjLnNldENvbnRlbnQoaHRtbF80ZTk1MjhiNWU5OTA0NjI0YmJlNDYxNTMzNjdhNmQzZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzVjNGZmNGY4NDBlYTQwOGM5ODRmMzBmZDE0ZmUzODUyLmJpbmRQb3B1cChwb3B1cF9jNjdlMGY3OWViZjA0MGJhOTg1YzA0M2U2OTEyMTNjYyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl80MjRjMDZiZGU4NTc0NzBlYmE2ZWY3NGZjYzc3MGUxNSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWy0yNi4zMzA2NiwtNTcuMzMwOTVdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jN2FhZGFhYWE2NDk0ZmZhOTE5NGRlMjA4OWUwNzJlNyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kMWMzNGU5MmI5NGI0ZTg5YmMzMDMyZjdiOTY5M2UzZiA9ICQoJzxkaXYgaWQ9Imh0bWxfZDFjMzRlOTJiOTRiNGU4OWJjMzAzMmY3Yjk2OTNlM2YiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkNQVVA8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2M3YWFkYWFhYTY0OTRmZmE5MTk0ZGUyMDg5ZTA3MmU3LnNldENvbnRlbnQoaHRtbF9kMWMzNGU5MmI5NGI0ZTg5YmMzMDMyZjdiOTY5M2UzZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzQyNGMwNmJkZTg1NzQ3MGViYTZlZjc0ZmNjNzcwZTE1LmJpbmRQb3B1cChwb3B1cF9jN2FhZGFhYWE2NDk0ZmZhOTE5NGRlMjA4OWUwNzJlNyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9kMzIwOTIwMzc0NzU0NjU0OWE1MzQ2MWFkNjFmZGI5MCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzYuNjcwMTYsLTQuODU2NTZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9kMmE4NzYyNjhhMGQ0NDQ5YjgzNjg0ZjBmZGUyMGU2MCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85YzEzY2UyYmFhMWY0OWRhODQ5M2ZiYjczMzY5OTVlZCA9ICQoJzxkaXYgaWQ9Imh0bWxfOWMxM2NlMmJhYTFmNDlkYTg0OTNmYmI3MzM2OTk1ZWQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkRCSUM8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2QyYTg3NjI2OGEwZDQ0NDliODM2ODRmMGZkZTIwZTYwLnNldENvbnRlbnQoaHRtbF85YzEzY2UyYmFhMWY0OWRhODQ5M2ZiYjczMzY5OTVlZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2QzMjA5MjAzNzQ3NTQ2NTQ5YTUzNDYxYWQ2MWZkYjkwLmJpbmRQb3B1cChwb3B1cF9kMmE4NzYyNjhhMGQ0NDQ5YjgzNjg0ZjBmZGUyMGU2MCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9lNzFiNjVkZjMwZDM0MDQwOGNjYjU0ZGQzNjFiODY5MyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQwLjAxODMsMTE2LjE2NzldLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mMTQ4MzBkNGRmNTI0YjgzOTZmN2YzZTY5MGY2NjAxYyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82Nzg0ZGNkZjk4ZDA0MWYwOGI5ZTYzZmU2YjQwOGFkYyA9ICQoJzxkaXYgaWQ9Imh0bWxfNjc4NGRjZGY5OGQwNDFmMDhiOWU2M2ZlNmI0MDhhZGMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkJKVDwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZjE0ODMwZDRkZjUyNGI4Mzk2ZjdmM2U2OTBmNjYwMWMuc2V0Q29udGVudChodG1sXzY3ODRkY2RmOThkMDQxZjA4YjllNjNmZTZiNDA4YWRjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZTcxYjY1ZGYzMGQzNDA0MDhjY2I1NGRkMzYxYjg2OTMuYmluZFBvcHVwKHBvcHVwX2YxNDgzMGQ0ZGY1MjRiODM5NmY3ZjNlNjkwZjY2MDFjKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzQ3NzcwMjlmMzVjZjQ4NGFhOWUxMjQ0OTY4OTlhMWRhID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDkuMjcwNCwxMTkuNzQxNF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzhlZTI3NDVhYTQ0ODQ0NWM4NDk1M2QyYjAyMTc4NjE3ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzk3NmI4OGRmYTc5ZTRjMWFhZDliY2E5ZDAxNjhhZjA2ID0gJCgnPGRpdiBpZD0iaHRtbF85NzZiODhkZmE3OWU0YzFhYWQ5YmNhOWQwMTY4YWYwNiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+SElBPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84ZWUyNzQ1YWE0NDg0NDVjODQ5NTNkMmIwMjE3ODYxNy5zZXRDb250ZW50KGh0bWxfOTc2Yjg4ZGZhNzllNGMxYWFkOWJjYTlkMDE2OGFmMDYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl80Nzc3MDI5ZjM1Y2Y0ODRhYTllMTI0NDk2ODk5YTFkYS5iaW5kUG9wdXAocG9wdXBfOGVlMjc0NWFhNDQ4NDQ1Yzg0OTUzZDJiMDIxNzg2MTcpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfZWViMjNmZjEwMTI5NDE5Yjg1NmI1N2EyYzJiYzhiZGQgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFsyNS4xMjMzLDEwMi43NF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2U4NDM2YmFkYjc1ODRlZWM4ZGFmM2JlOGFmZjFlMGE1ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzJhMTc5NGZjMDM5NTQ2ZmRiMjYzZGE3NzA0ZTY2ZDA4ID0gJCgnPGRpdiBpZD0iaHRtbF8yYTE3OTRmYzAzOTU0NmZkYjI2M2RhNzcwNGU2NmQwOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+S01JPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lODQzNmJhZGI3NTg0ZWVjOGRhZjNiZThhZmYxZTBhNS5zZXRDb250ZW50KGh0bWxfMmExNzk0ZmMwMzk1NDZmZGIyNjNkYTc3MDRlNjZkMDgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9lZWIyM2ZmMTAxMjk0MTliODU2YjU3YTJjMmJjOGJkZC5iaW5kUG9wdXAocG9wdXBfZTg0MzZiYWRiNzU4NGVlYzhkYWYzYmU4YWZmMWUwYTUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfOGIzNmI5YzhhODVmNDMxNmFjODhiZTZmNTQxYWMwMmIgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFsxOS4wMjkxLDEwOS44NDQ1XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYjU3Nzg5Mzc1Y2QyNDc1MTg0YjRhMWRlYTA5YjYyNDggPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOWM3ZmNmNjRhMmJiNGFkNGFlNDViNWM4ODQ0OWNkOTUgPSAkKCc8ZGl2IGlkPSJodG1sXzljN2ZjZjY0YTJiYjRhZDRhZTQ1YjVjODg0NDljZDk1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5RSVo8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2I1Nzc4OTM3NWNkMjQ3NTE4NGI0YTFkZWEwOWI2MjQ4LnNldENvbnRlbnQoaHRtbF85YzdmY2Y2NGEyYmI0YWQ0YWU0NWI1Yzg4NDQ5Y2Q5NSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzhiMzZiOWM4YTg1ZjQzMTZhYzg4YmU2ZjU0MWFjMDJiLmJpbmRQb3B1cChwb3B1cF9iNTc3ODkzNzVjZDI0NzUxODRiNGExZGVhMDliNjI0OCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9jYTc4ZDRiZmZiN2M0MGFjOTQyY2UwYzZlNDYxODQ5NyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzMxLjA5NDgsMTIxLjE5MDhdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF84MGI1MDU0ZGQ0YTQ0ZDk5Yjk2ODQ3MTk2ODMwZDYyNCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wN2YyYzlkODgyY2Y0OTRmYTE2ZjBiODE4MmZiZTUxZSA9ICQoJzxkaXYgaWQ9Imh0bWxfMDdmMmM5ZDg4MmNmNDk0ZmExNmYwYjgxODJmYmU1MWUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlNTRTwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfODBiNTA1NGRkNGE0NGQ5OWI5Njg0NzE5NjgzMGQ2MjQuc2V0Q29udGVudChodG1sXzA3ZjJjOWQ4ODJjZjQ5NGZhMTZmMGI4MTgyZmJlNTFlKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfY2E3OGQ0YmZmYjdjNDBhYzk0MmNlMGM2ZTQ2MTg0OTcuYmluZFBvcHVwKHBvcHVwXzgwYjUwNTRkZDRhNDRkOTliOTY4NDcxOTY4MzBkNjI0KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzU3NGQ2YTJkMjU4ODRiNjM4ODRkZWQ1NzIzMTY5MDExID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuODEzOCw4Ny43MDQ5XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYjM3NTFiMTU5YzJlNDY0ZWI2YjkwYzNhMzY1ZTlkMzIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMGUzZTEwZjEwOWVlNDU1MmEzNjY5MDFkOGM4NzRlYjIgPSAkKCc8ZGl2IGlkPSJodG1sXzBlM2UxMGYxMDllZTQ1NTJhMzY2OTAxZDhjODc0ZWIyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5XTVE8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2IzNzUxYjE1OWMyZTQ2NGViNmI5MGMzYTM2NWU5ZDMyLnNldENvbnRlbnQoaHRtbF8wZTNlMTBmMTA5ZWU0NTUyYTM2NjkwMWQ4Yzg3NGViMik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzU3NGQ2YTJkMjU4ODRiNjM4ODRkZWQ1NzIzMTY5MDExLmJpbmRQb3B1cChwb3B1cF9iMzc1MWIxNTljMmU0NjRlYjZiOTBjM2EzNjVlOWQzMik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9lN2M1ODY3YjkwMmU0YzFjYjZjMTBmZjE3NDlhNTkyMyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzM0LjAzMTMsMTA4LjkyMzddLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yMGIzYWU5OGNhZmM0ZjQ5OTAxNDIzMDZhOGY2NzhiZCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wMzc2ZDU2ZTY3N2Y0MTRiYTNjNzg1Y2E2YTcwYmRhMiA9ICQoJzxkaXYgaWQ9Imh0bWxfMDM3NmQ1NmU2NzdmNDE0YmEzYzc4NWNhNmE3MGJkYTIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlhBTjwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjBiM2FlOThjYWZjNGY0OTkwMTQyMzA2YThmNjc4YmQuc2V0Q29udGVudChodG1sXzAzNzZkNTZlNjc3ZjQxNGJhM2M3ODVjYTZhNzBiZGEyKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZTdjNTg2N2I5MDJlNGMxY2I2YzEwZmYxNzQ5YTU5MjMuYmluZFBvcHVwKHBvcHVwXzIwYjNhZTk4Y2FmYzRmNDk5MDE0MjMwNmE4ZjY3OGJkKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzlhN2MzYTFiMTI4YTRjNWI4YzViNWNiMDhlZWZlNDdjID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDIuNjM3NSw3NC40OTQyXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYThmMzA3OWU1NjMzNGNiNjkyOTllOWU4ODI4ZjJjMDQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZWFhZTM5MzNiNWI0NDQ0NGIzNGIxMmFmNTBkYzBiN2UgPSAkKCc8ZGl2IGlkPSJodG1sX2VhYWUzOTMzYjViNDQ0NDRiMzRiMTJhZjUwZGMwYjdlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5BQUs8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2E4ZjMwNzllNTYzMzRjYjY5Mjk5ZTllODgyOGYyYzA0LnNldENvbnRlbnQoaHRtbF9lYWFlMzkzM2I1YjQ0NDQ0YjM0YjEyYWY1MGRjMGI3ZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzlhN2MzYTFiMTI4YTRjNWI4YzViNWNiMDhlZWZlNDdjLmJpbmRQb3B1cChwb3B1cF9hOGYzMDc5ZTU2MzM0Y2I2OTI5OWU5ZTg4MjhmMmMwNCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8yOWU1M2U5Yjg0ZmI0OTc4ODBiMTZkNWIwZDc3ZDQ5MyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzM3LjkzMDQsNTguMTE4OV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzZmMDRlYzg4OGNkNTRjNzI5MDAzMjYzM2Y4MmIzM2ExID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzMzZTZmNTdkYWQ0YzRmYjhiOWFkMzkyYzVmMGRjZWE3ID0gJCgnPGRpdiBpZD0iaHRtbF8zM2U2ZjU3ZGFkNGM0ZmI4YjlhZDM5MmM1ZjBkY2VhNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+QUJLVDwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNmYwNGVjODg4Y2Q1NGM3MjkwMDMyNjMzZjgyYjMzYTEuc2V0Q29udGVudChodG1sXzMzZTZmNTdkYWQ0YzRmYjhiOWFkMzkyYzVmMGRjZWE3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMjllNTNlOWI4NGZiNDk3ODgwYjE2ZDViMGQ3N2Q0OTMuYmluZFBvcHVwKHBvcHVwXzZmMDRlYzg4OGNkNTRjNzI5MDAzMjYzM2Y4MmIzM2ExKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzMzNTY3OGNjYTdlYjQ2MDA5OThlMGE5NzM0N2U1YzhiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbLTE5LjAxOCw0Ny4yMjldLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yZTNjMzI3YjU0Zjg0MTg5YWZjZDJlZDk4ZThjNzA2OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9lY2U0MGI4MWM0OWE0NTc0OGQzM2U3Nzg4ZjIwNDI3ZSA9ICQoJzxkaXYgaWQ9Imh0bWxfZWNlNDBiODFjNDlhNDU3NDhkMzNlNzc4OGYyMDQyN2UiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkFCUE88L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzJlM2MzMjdiNTRmODQxODlhZmNkMmVkOThlOGM3MDY4LnNldENvbnRlbnQoaHRtbF9lY2U0MGI4MWM0OWE0NTc0OGQzM2U3Nzg4ZjIwNDI3ZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzMzNTY3OGNjYTdlYjQ2MDA5OThlMGE5NzM0N2U1YzhiLmJpbmRQb3B1cChwb3B1cF8yZTNjMzI3YjU0Zjg0MTg5YWZjZDJlZDk4ZThjNzA2OCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9lYTVhOGJmODI4ZTc0Y2RiYTQ5ZTE3ZTkxZTczNTMxMiA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzgyLjUwMzMsLTYyLjM1XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfM2U1ODdjOGI5MjgzNDczMTljNDIyNjgwN2MzNGYyM2UgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNDllZGU4MjNlNzUxNDE0MDliODI0NWFlMDQwYWI4MGQgPSAkKCc8ZGl2IGlkPSJodG1sXzQ5ZWRlODIzZTc1MTQxNDA5YjgyNDVhZTA0MGFiODBkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5BTEU8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzNlNTg3YzhiOTI4MzQ3MzE5YzQyMjY4MDdjMzRmMjNlLnNldENvbnRlbnQoaHRtbF80OWVkZTgyM2U3NTE0MTQwOWI4MjQ1YWUwNDBhYjgwZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2VhNWE4YmY4MjhlNzRjZGJhNDllMTdlOTFlNzM1MzEyLmJpbmRQb3B1cChwb3B1cF8zZTU4N2M4YjkyODM0NzMxOWM0MjI2ODA3YzM0ZjIzZSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9iYzMzN2Q3MjI3NjE0NWQwOGFmYjAzNWRjYzJhMjQ3NSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzU2LjQzMDIsNTguNTYyNV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2QzMzEwOWZjNGI2ODRjNzY5YTE4YTFkN2RlMmQ0ODBmID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2FjODU4MDkzODIwNDQ0NGQ5NzI4ZjI4ZTNlMjU3MWZmID0gJCgnPGRpdiBpZD0iaHRtbF9hYzg1ODA5MzgyMDQ0NDRkOTcyOGYyOGUzZTI1NzFmZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+QVJVPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9kMzMxMDlmYzRiNjg0Yzc2OWExOGExZDdkZTJkNDgwZi5zZXRDb250ZW50KGh0bWxfYWM4NTgwOTM4MjA0NDQ0ZDk3MjhmMjhlM2UyNTcxZmYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9iYzMzN2Q3MjI3NjE0NWQwOGFmYjAzNWRjYzJhMjQ3NS5iaW5kUG9wdXAocG9wdXBfZDMzMTA5ZmM0YjY4NGM3NjlhMThhMWQ3ZGUyZDQ4MGYpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMDQ5YjZiMjllMzE0NDg1MmFkMjg2NDBjNDYxYTQyZTAgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs1NC43MjUsLTEwMS45NzgzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNDZlZDRmMTk1MmM5NGU5NmExNjhhYTM5YjFhMWE3MmMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYjE0N2VmMDkwYTcwNDBjYTkyZjI0ODQxOTAwYzU2NTcgPSAkKCc8ZGl2IGlkPSJodG1sX2IxNDdlZjA5MGE3MDQwY2E5MmYyNDg0MTkwMGM1NjU3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5GRkM8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzQ2ZWQ0ZjE5NTJjOTRlOTZhMTY4YWEzOWIxYTFhNzJjLnNldENvbnRlbnQoaHRtbF9iMTQ3ZWYwOTBhNzA0MGNhOTJmMjQ4NDE5MDBjNTY1Nyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzA0OWI2YjI5ZTMxNDQ4NTJhZDI4NjQwYzQ2MWE0MmUwLmJpbmRQb3B1cChwb3B1cF80NmVkNGYxOTUyYzk0ZTk2YTE2OGFhMzliMWExYTcyYyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8wNTQxZDJkYzY5NzQ0ZDg4YTFlZTc5Nzg5MTg5MzU2NyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzEwLjI5MDgsLTg0Ljk1MjVdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83NGRlNWVmNDYwMzQ0MzVkYTM2NGE0Y2NkODhhYjA0YyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9jN2FhYjg4YzRhYWE0NjA2YjcyOTUyYmEyMDIzZGQ5NSA9ICQoJzxkaXYgaWQ9Imh0bWxfYzdhYWI4OGM0YWFhNDYwNmI3Mjk1MmJhMjAyM2RkOTUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkpUUzwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNzRkZTVlZjQ2MDM0NDM1ZGEzNjRhNGNjZDg4YWIwNGMuc2V0Q29udGVudChodG1sX2M3YWFiODhjNGFhYTQ2MDZiNzI5NTJiYTIwMjNkZDk1KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMDU0MWQyZGM2OTc0NGQ4OGExZWU3OTc4OTE4OTM1NjcuYmluZFBvcHVwKHBvcHVwXzc0ZGU1ZWY0NjAzNDQzNWRhMzY0YTRjY2Q4OGFiMDRjKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2JmNzgyOTIzN2I0YjQxYjg5M2U0NGM1MmI0NDBkNjdlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNTAuNzE1NCw3OC42MjAyXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOGUxNzNhMDIzZGFhNGIwMThmZmU3OWQxN2RhMjE3NDIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOTEwODgwMzA3YmQzNDZkZDhjNmM1ZmJmNGVkOGYwMzkgPSAkKCc8ZGl2IGlkPSJodG1sXzkxMDg4MDMwN2JkMzQ2ZGQ4YzZjNWZiZjRlZDhmMDM5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5LVVJLPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84ZTE3M2EwMjNkYWE0YjAxOGZmZTc5ZDE3ZGEyMTc0Mi5zZXRDb250ZW50KGh0bWxfOTEwODgwMzA3YmQzNDZkZDhjNmM1ZmJmNGVkOGYwMzkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9iZjc4MjkyMzdiNGI0MWI4OTNlNDRjNTJiNDQwZDY3ZS5iaW5kUG9wdXAocG9wdXBfOGUxNzNhMDIzZGFhNGIwMThmZmU3OWQxN2RhMjE3NDIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfZGJjZTQ0ZDhiNTRhNGVhOWI1MWE0MjIwODNjODZiYzggPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFstNC42NzM3LDU1LjQ3OTJdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mZTQxYzc0ZWQzZDQ0MzI3YTQ2NGIxMzc5MjVhOTk2YyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85ZTA1N2FlMDU2ZWI0ZGMzYmY5NTM0Y2RmMDg0NGNlZiA9ICQoJzxkaXYgaWQ9Imh0bWxfOWUwNTdhZTA1NmViNGRjM2JmOTUzNGNkZjA4NDRjZWYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPk1TRVk8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2ZlNDFjNzRlZDNkNDQzMjdhNDY0YjEzNzkyNWE5OTZjLnNldENvbnRlbnQoaHRtbF85ZTA1N2FlMDU2ZWI0ZGMzYmY5NTM0Y2RmMDg0NGNlZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2RiY2U0NGQ4YjU0YTRlYTliNTFhNDIyMDgzYzg2YmM4LmJpbmRQb3B1cChwb3B1cF9mZTQxYzc0ZWQzZDQ0MzI3YTQ2NGIxMzc5MjVhOTk2Yyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9lZWUwMmYwMzUwM2Q0ZjcyOWMyNzNjZjlhNmI1ODJjOSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzUxLjY4MDcsMTAzLjY0MzhdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hYTU0MDVlYTA3ZWY0ZDBhOGJjNDFkNjJhYTNiMWZiNSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9hMGZlYzdmZDI1MWE0Y2Y2YjdkZmY4Y2E4YzcwZGMyNyA9ICQoJzxkaXYgaWQ9Imh0bWxfYTBmZWM3ZmQyNTFhNGNmNmI3ZGZmOGNhOGM3MGRjMjciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlRMWTwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYWE1NDA1ZWEwN2VmNGQwYThiYzQxZDYyYWEzYjFmYjUuc2V0Q29udGVudChodG1sX2EwZmVjN2ZkMjUxYTRjZjZiN2RmZjhjYThjNzBkYzI3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZWVlMDJmMDM1MDNkNGY3MjljMjczY2Y5YTZiNTgyYzkuYmluZFBvcHVwKHBvcHVwX2FhNTQwNWVhMDdlZjRkMGE4YmM0MWQ2MmFhM2IxZmI1KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzMyZTg0ZmY5OTExNjQ4ZjA4NmU0MGE1NGM5YWZlZGU3ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbMzIuMzcxMywtNjQuNjk2M10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzRlYmYzYjllNWYwYjQzOWFiYWIzYzNkNzFiMDNhNzRmID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzQ0OWJjMTFkM2U4NTQ1N2Y4NDEyYjVlOTc3MTBiM2U4ID0gJCgnPGRpdiBpZD0iaHRtbF80NDliYzExZDNlODU0NTdmODQxMmI1ZTk3NzEwYjNlOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+QkJTUjwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNGViZjNiOWU1ZjBiNDM5YWJhYjNjM2Q3MWIwM2E3NGYuc2V0Q29udGVudChodG1sXzQ0OWJjMTFkM2U4NTQ1N2Y4NDEyYjVlOTc3MTBiM2U4KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMzJlODRmZjk5MTE2NDhmMDg2ZTQwYTU0YzlhZmVkZTcuYmluZFBvcHVwKHBvcHVwXzRlYmYzYjllNWYwYjQzOWFiYWIzYzNkNzFiMDNhNzRmKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2UyZjgyMTI1ODgwYzQxNTVhMjE5ODI0MzNjMTI4NmM1ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbMTguODE0MSw5OC45NDQzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZDkwMDE2MjQyMDI2NDJkMWJkNmQ1OTczMWFiMWQ4MTkgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMmI2NGExMDQ4MDkwNGZiZTg5N2EyOTBhNjNlMDYyYzkgPSAkKCc8ZGl2IGlkPSJodG1sXzJiNjRhMTA0ODA5MDRmYmU4OTdhMjkwYTYzZTA2MmM5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5DSFRPPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9kOTAwMTYyNDIwMjY0MmQxYmQ2ZDU5NzMxYWIxZDgxOS5zZXRDb250ZW50KGh0bWxfMmI2NGExMDQ4MDkwNGZiZTg5N2EyOTBhNjNlMDYyYzkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9lMmY4MjEyNTg4MGM0MTU1YTIxOTgyNDMzYzEyODZjNS5iaW5kUG9wdXAocG9wdXBfZDkwMDE2MjQyMDI2NDJkMWJkNmQ1OTczMWFiMWQ4MTkpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNzU3MGQ4NmQxMzE1NDRmM2JiZjQ1NGY0NWE1YzUyOGMgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC41ODU1LC0xMjMuMzA0Nl0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzFhNzc4NzAxYmVhNzRhYWVhN2MzOGFhZGU3NGE1MjU2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzMxZDhkNDJmMWUxMTQ5MmQ5YWM0M2Q2YTU2MzIyZWRhID0gJCgnPGRpdiBpZD0iaHRtbF8zMWQ4ZDQyZjFlMTE0OTJkOWFjNDNkNmE1NjMyMmVkYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+Q09SPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xYTc3ODcwMWJlYTc0YWFlYTdjMzhhYWRlNzRhNTI1Ni5zZXRDb250ZW50KGh0bWxfMzFkOGQ0MmYxZTExNDkyZDlhYzQzZDZhNTYzMjJlZGEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl83NTcwZDg2ZDEzMTU0NGYzYmJmNDU0ZjQ1YTVjNTI4Yy5iaW5kUG9wdXAocG9wdXBfMWE3Nzg3MDFiZWE3NGFhZWE3YzM4YWFkZTc0YTUyNTYpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNzZmMjM1NDQyMGJiNDQwYjhkNmQxMmM1ZDM3Yjg0MDIgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFsyOC4xMTAzLC04MS40MzI3XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfODFiOGMzYzRlNTAzNDdjNTg1NWY5YWM2NzAwNTk3NTEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMThlNDIwMTAxNTAwNGU5MWE1YTY5M2U2NGQzZDZkOGEgPSAkKCc8ZGl2IGlkPSJodG1sXzE4ZTQyMDEwMTUwMDRlOTFhNWE2OTNlNjRkM2Q2ZDhhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5EV1BGPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84MWI4YzNjNGU1MDM0N2M1ODU1ZjlhYzY3MDA1OTc1MS5zZXRDb250ZW50KGh0bWxfMThlNDIwMTAxNTAwNGU5MWE1YTY5M2U2NGQzZDZkOGEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl83NmYyMzU0NDIwYmI0NDBiOGQ2ZDEyYzVkMzdiODQwMi5iaW5kUG9wdXAocG9wdXBfODFiOGMzYzRlNTAzNDdjNTg1NWY5YWM2NzAwNTk3NTEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfZTY4YzdjNjE0NTEwNDg1ZTg4ODE4ZTMzMDc0YjhmNzMgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFszNy40Nzc2LDEyNi42MjM5XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNDZiN2Y0YzBmNGY5NGMyMGIxMTA2N2NhZDhhYjUxMWYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMDQ3ZWRkZmM5NDcwNGRhZmIyMzIyOGRjN2EwMTc2NmMgPSAkKCc8ZGl2IGlkPSJodG1sXzA0N2VkZGZjOTQ3MDRkYWZiMjMyMjhkYzdhMDE3NjZjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5JTkNOPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF80NmI3ZjRjMGY0Zjk0YzIwYjExMDY3Y2FkOGFiNTExZi5zZXRDb250ZW50KGh0bWxfMDQ3ZWRkZmM5NDcwNGRhZmIyMzIyOGRjN2EwMTc2NmMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9lNjhjN2M2MTQ1MTA0ODVlODg4MThlMzMwNzRiOGY3My5iaW5kUG9wdXAocG9wdXBfNDZiN2Y0YzBmNGY5NGMyMGIxMTA2N2NhZDhhYjUxMWYpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfZjhlMGQyNzA2NzhjNDdjOGJiZjMzMzJhMzUzN2NiMDEgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFszNC41NDA4LDY5LjA0MzJdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jNjc2NGUzMTdmNmI0NzJhOWY3YzZlMWMwZjEyN2E4MSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85YmY5OGVhYzcxNjI0Njc4ODE0ZTg0MjBkZGExOWQxNSA9ICQoJzxkaXYgaWQ9Imh0bWxfOWJmOThlYWM3MTYyNDY3ODgxNGU4NDIwZGRhMTlkMTUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPktCTDwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYzY3NjRlMzE3ZjZiNDcyYTlmN2M2ZTFjMGYxMjdhODEuc2V0Q29udGVudChodG1sXzliZjk4ZWFjNzE2MjQ2Nzg4MTRlODQyMGRkYTE5ZDE1KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZjhlMGQyNzA2NzhjNDdjOGJiZjMzMzJhMzUzN2NiMDEuYmluZFBvcHVwKHBvcHVwX2M2NzY0ZTMxN2Y2YjQ3MmE5ZjdjNmUxYzBmMTI3YTgxKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2IyMTgyNDE2Yzk5MzQ4ZmVhOGM0ZjMwZjZiNzQ3Mjk1ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbLTE1LjI3NzksMjguMTg4Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzM4NTk3Nzk3Mzg4ODQ4Njc4MDQxMTNjMDhjNzllOWI3ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzgyNzBkMDg3YTU3ZDQ1NTM4NDc2NmM3NmQyMmNiNzE5ID0gJCgnPGRpdiBpZD0iaHRtbF84MjcwZDA4N2E1N2Q0NTUzODQ3NjZjNzZkMjJjYjcxOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+TFNaPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8zODU5Nzc5NzM4ODg0ODY3ODA0MTEzYzA4Yzc5ZTliNy5zZXRDb250ZW50KGh0bWxfODI3MGQwODdhNTdkNDU1Mzg0NzY2Yzc2ZDIyY2I3MTkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9iMjE4MjQxNmM5OTM0OGZlYThjNGYzMGY2Yjc0NzI5NS5iaW5kUG9wdXAocG9wdXBfMzg1OTc3OTczODg4NDg2NzgwNDExM2MwOGM3OWU5YjcpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMjgwN2EwODQ3NGE1NDJlOGFjOGFlMzg4OGJiNDUzMjAgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFswLjIzNzYsLTc4LjQ1MDhdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8zMjdiNjI1OWI0NjE0ZWQwOWY0YjgxOTg3NzcxY2Q5NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82MjNjMjE2MjlkZGI0N2FlYTNmMTJkZmZlNDcyY2JlMiA9ICQoJzxkaXYgaWQ9Imh0bWxfNjIzYzIxNjI5ZGRiNDdhZWEzZjEyZGZmZTQ3MmNiZTIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPk9UQVY8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzMyN2I2MjU5YjQ2MTRlZDA5ZjRiODE5ODc3NzFjZDk0LnNldENvbnRlbnQoaHRtbF82MjNjMjE2MjlkZGI0N2FlYTNmMTJkZmZlNDcyY2JlMik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzI4MDdhMDg0NzRhNTQyZThhYzhhZTM4ODhiYjQ1MzIwLmJpbmRQb3B1cChwb3B1cF8zMjdiNjI1OWI0NjE0ZWQwOWY0YjgxOTg3NzcxY2Q5NCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9kZWZjYmU3Yjc0M2U0MTdjYmQ5MzI1ODVjYTY1OGNkNCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzUzLjAyMzMsMTU4LjY0OTldLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jY2EyMjBlNWQ2OWM0ODVhOGE2MzkzNWQ2ZGI4M2Q1OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xM2IwNjY0MTE4ZDA0MjM3YjAyY2E3ZDBiNDU0MjUyNyA9ICQoJzxkaXYgaWQ9Imh0bWxfMTNiMDY2NDExOGQwNDIzN2IwMmNhN2QwYjQ1NDI1MjciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlBFVDwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfY2NhMjIwZTVkNjljNDg1YThhNjM5MzVkNmRiODNkNTguc2V0Q29udGVudChodG1sXzEzYjA2NjQxMThkMDQyMzdiMDJjYTdkMGI0NTQyNTI3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZGVmY2JlN2I3NDNlNDE3Y2JkOTMyNTg1Y2E2NThjZDQuYmluZFBvcHVwKHBvcHVwX2NjYTIyMGU1ZDY5YzQ4NWE4YTYzOTM1ZDZkYjgzZDU4KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzI2ZWY0NTUzNjcxODQ5YTZhNWYwZTBmY2UwZmFlOWJiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbLTUuODI3NCwtMzUuOTAxNF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzU1NWM3YjgwZTYwNDRlNmU5ZTNhMjVhMzZkZGMzMGI4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzY3YmVlNTY0MjljNTRjOGQ5YzE2NDc0NjcwM2M0NTNlID0gJCgnPGRpdiBpZD0iaHRtbF82N2JlZTU2NDI5YzU0YzhkOWMxNjQ3NDY3MDNjNDUzZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+UkNCUjwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNTU1YzdiODBlNjA0NGU2ZTllM2EyNWEzNmRkYzMwYjguc2V0Q29udGVudChodG1sXzY3YmVlNTY0MjljNTRjOGQ5YzE2NDc0NjcwM2M0NTNlKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMjZlZjQ1NTM2NzE4NDlhNmE1ZjBlMGZjZTBmYWU5YmIuYmluZFBvcHVwKHBvcHVwXzU1NWM3YjgwZTYwNDRlNmU5ZTNhMjVhMzZkZGMzMGI4KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2ZhYjVkMzg2MTUyZTQ1Nzk4YWVlZjM4ZjdjZmUxZjRlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbLTguOTQ4OSwtNjMuMTgzMV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzlhZmQwZDAzNjMzODQ3MTNhNzgxZGViOGQ1MDA1ODI3ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzlhMjgyNWNkZjgyMjQ5OWQ5NTdiMjEyYzI2MmUyYTU4ID0gJCgnPGRpdiBpZD0iaHRtbF85YTI4MjVjZGY4MjI0OTlkOTU3YjIxMmMyNjJlMmE1OCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+U0FNTDwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfOWFmZDBkMDM2MzM4NDcxM2E3ODFkZWI4ZDUwMDU4Mjcuc2V0Q29udGVudChodG1sXzlhMjgyNWNkZjgyMjQ5OWQ5NTdiMjEyYzI2MmUyYTU4KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZmFiNWQzODYxNTJlNDU3OThhZWVmMzhmN2NmZTFmNGUuYmluZFBvcHVwKHBvcHVwXzlhZmQwZDAzNjMzODQ3MTNhNzgxZGViOGQ1MDA1ODI3KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2JiNmVjY2FjM2Y5MTQzNjk5MWVlYThhOGJhZmM5ZTI3ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbOC44ODM5LC03MC42MzRdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yMzc3Y2I3Yzg1MGM0MmMyOTI2MjRiN2RlNWMzZGNjYSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zOGEzZjNiMDEzZmM0MjI2ODc1ZTZjZGJmYTcyZGZhYSA9ICQoJzxkaXYgaWQ9Imh0bWxfMzhhM2YzYjAxM2ZjNDIyNjg3NWU2Y2RiZmE3MmRmYWEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlNEVjwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjM3N2NiN2M4NTBjNDJjMjkyNjI0YjdkZTVjM2RjY2Euc2V0Q29udGVudChodG1sXzM4YTNmM2IwMTNmYzQyMjY4NzVlNmNkYmZhNzJkZmFhKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfYmI2ZWNjYWMzZjkxNDM2OTkxZWVhOGE4YmFmYzllMjcuYmluZFBvcHVwKHBvcHVwXzIzNzdjYjdjODUwYzQyYzI5MjYyNGI3ZGU1YzNkY2NhKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2RkNDRmYzIwZjAzZTQ5MTk4ZjY1YWNjYWE0NDIyMWY2ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNjYuOTk2MSwtNTAuNjIwNzZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jNjE4YmJlNjM2NDU0ODFmYmY5MGE4ZmU1ODk0MzNhNiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kMTljOWUwNjViODM0ZjY5ODRkMWUxOGUwNWFhNGIzZCA9ICQoJzxkaXYgaWQ9Imh0bWxfZDE5YzllMDY1YjgzNGY2OTg0ZDFlMThlMDVhYTRiM2QiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlNGSkQ8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2M2MThiYmU2MzY0NTQ4MWZiZjkwYThmZTU4OTQzM2E2LnNldENvbnRlbnQoaHRtbF9kMTljOWUwNjViODM0ZjY5ODRkMWUxOGUwNWFhNGIzZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2RkNDRmYzIwZjAzZTQ5MTk4ZjY1YWNjYWE0NDIyMWY2LmJpbmRQb3B1cChwb3B1cF9jNjE4YmJlNjM2NDU0ODFmYmY5MGE4ZmU1ODk0MzNhNik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl83ZDJjODliODBlMjA0MDQ5YWJiOTFlMjNhMThkYWFmMyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQwLjYzNTgsLTc3Ljg4NzZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8zYzk5Nzc2ODllMDk0OTEzOTM4ZWUwOWFkZjVkZjBlMSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wZmFlNTAwYmY5ZDM0MmE4OTBmMzcyMmRiMGI3N2JlNiA9ICQoJzxkaXYgaWQ9Imh0bWxfMGZhZTUwMGJmOWQzNDJhODkwZjM3MjJkYjBiNzdiZTYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlNTUEE8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzNjOTk3NzY4OWUwOTQ5MTM5MzhlZTA5YWRmNWRmMGUxLnNldENvbnRlbnQoaHRtbF8wZmFlNTAwYmY5ZDM0MmE4OTBmMzcyMmRiMGI3N2JlNik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzdkMmM4OWI4MGUyMDQwNDlhYmI5MWUyM2ExOGRhYWYzLmJpbmRQb3B1cChwb3B1cF8zYzk5Nzc2ODllMDk0OTEzOTM4ZWUwOWFkZjVkZjBlMSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl80YzU0MmVmYjA3NWU0MTdjYWI5NTJkZDNmMDVlNzQ3NSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzIwLjIyNjMsLTg4LjI3NjNdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9kMDY1YWQ1ZDk2ZDk0YWM5YjdjMmIxNzBhYTczOWE1NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF83Y2NkNGU5ZDRkYzE0NmIxOWNhNTg0NzUwMjY2MjY4NyA9ICQoJzxkaXYgaWQ9Imh0bWxfN2NjZDRlOWQ0ZGMxNDZiMTljYTU4NDc1MDI2NjI2ODciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlRFSUc8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2QwNjVhZDVkOTZkOTRhYzliN2MyYjE3MGFhNzM5YTU0LnNldENvbnRlbnQoaHRtbF83Y2NkNGU5ZDRkYzE0NmIxOWNhNTg0NzUwMjY2MjY4Nyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzRjNTQyZWZiMDc1ZTQxN2NhYjk1MmRkM2YwNWU3NDc1LmJpbmRQb3B1cChwb3B1cF9kMDY1YWQ1ZDk2ZDk0YWM5YjdjMmIxNzBhYTczOWE1NCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9kZjU5NTY0ZGUyYTc0ZDAzYTkwYjg0Y2FmMTc1MzYwNSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWy0xOS4yMDIyLDE3LjU4MzhdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF81M2I4MjlhMzQ2YmE0ZGYwOWM1NzA0NDMwMzdiYzZjMCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82OGQ1Mzk4MTBiMjI0MTA3OWU5OWRiN2EwYWJiODc1NSA9ICQoJzxkaXYgaWQ9Imh0bWxfNjhkNTM5ODEwYjIyNDEwNzllOTlkYjdhMGFiYjg3NTUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlRTVU08L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzUzYjgyOWEzNDZiYTRkZjA5YzU3MDQ0MzAzN2JjNmMwLnNldENvbnRlbnQoaHRtbF82OGQ1Mzk4MTBiMjI0MTA3OWU5OWRiN2EwYWJiODc1NSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2RmNTk1NjRkZTJhNzRkMDNhOTBiODRjYWYxNzUzNjA1LmJpbmRQb3B1cChwb3B1cF81M2I4MjlhMzQ2YmE0ZGYwOWM1NzA0NDMwMzdiYzZjMCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl81NjNlMjUzMmQxMTU0MGE3YjA0NGQ4NzA1ZTUxODVhMSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ3Ljg2NTEsMTA3LjA1MzJdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83ZjBlZTc2ODMxZGU0Y2RkYTAxZjM1NDVjNWY1M2U5NyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9iZjBjZTAwODk3MTE0YzcyYWUyN2ZjYjMxMjlmNTc5YSA9ICQoJzxkaXYgaWQ9Imh0bWxfYmYwY2UwMDg5NzExNGM3MmFlMjdmY2IzMTI5ZjU3OWEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPlVMTjwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfN2YwZWU3NjgzMWRlNGNkZGEwMWYzNTQ1YzVmNTNlOTcuc2V0Q29udGVudChodG1sX2JmMGNlMDA4OTcxMTRjNzJhZTI3ZmNiMzEyOWY1NzlhKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNTYzZTI1MzJkMTE1NDBhN2IwNDRkODcwNWU1MTg1YTEuYmluZFBvcHVwKHBvcHVwXzdmMGVlNzY4MzFkZTRjZGRhMDFmMzU0NWM1ZjUzZTk3KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2FlZGQ2YTgzOGFiYTRmOGViMmMyYWRmZWM4ZDY0ZTM4ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbMzguMjI4OSwtODYuMjkzOV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzJhNzEyZmNkOTAzZTQzNGNhZWY4NTMxOTZjNmY4OGJiID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzkzMzdlYjJmZmU1ODRkOTk5NTk0NmI4NzMzY2M2MTZlID0gJCgnPGRpdiBpZD0iaHRtbF85MzM3ZWIyZmZlNTg0ZDk5OTU5NDZiODczM2NjNjE2ZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+V0NJPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8yYTcxMmZjZDkwM2U0MzRjYWVmODUzMTk2YzZmODhiYi5zZXRDb250ZW50KGh0bWxfOTMzN2ViMmZmZTU4NGQ5OTk1OTQ2Yjg3MzNjYzYxNmUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9hZWRkNmE4MzhhYmE0ZjhlYjJjMmFkZmVjOGQ2NGUzOC5iaW5kUG9wdXAocG9wdXBfMmE3MTJmY2Q5MDNlNDM0Y2FlZjg1MzE5NmM2Zjg4YmIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfOTBiM2Q1ZDA2ZDIzNDdhNGI5ZDdiYjRjM2FiZDYzZDAgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs2Mi4wMzEsMTI5LjY4MDVdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF84MzliNDI5NWRjOGE0MzBmOWUyNDUzYmZjZDNiMWZkYiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kZTg4OGI1YmUxYjE0NzA0YmQzMDA5M2I5MWIzODFjMCA9ICQoJzxkaXYgaWQ9Imh0bWxfZGU4ODhiNWJlMWIxNDcwNGJkMzAwOTNiOTFiMzgxYzAiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPllBSzwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfODM5YjQyOTVkYzhhNDMwZjllMjQ1M2JmY2QzYjFmZGIuc2V0Q29udGVudChodG1sX2RlODg4YjViZTFiMTQ3MDRiZDMwMDkzYjkxYjM4MWMwKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfOTBiM2Q1ZDA2ZDIzNDdhNGI5ZDdiYjRjM2FiZDYzZDAuYmluZFBvcHVwKHBvcHVwXzgzOWI0Mjk1ZGM4YTQzMGY5ZTI0NTNiZmNkM2IxZmRiKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2Y0ZWNkNzYwMmQyNTQyNjdhYjg1ZTdjZTcyZmYxZmI2ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuMTE4OCwxNDIuNTkzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZTgzZjc1ODBhMTg3NDc2ZTliNjNlMzg3ODAxODZkNjEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYzBmYmQ1YjdkYWQ5NDYwNTk0OTg5NjQwM2VkY2Q2NTMgPSAkKCc8ZGl2IGlkPSJodG1sX2MwZmJkNWI3ZGFkOTQ2MDU5NDk4OTY0MDNlZGNkNjUzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5BU0FKPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lODNmNzU4MGExODc0NzZlOWI2M2UzODc4MDE4NmQ2MS5zZXRDb250ZW50KGh0bWxfYzBmYmQ1YjdkYWQ5NDYwNTk0OTg5NjQwM2VkY2Q2NTMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9mNGVjZDc2MDJkMjU0MjY3YWI4NWU3Y2U3MmZmMWZiNi5iaW5kUG9wdXAocG9wdXBfZTgzZjc1ODBhMTg3NDc2ZTliNjNlMzg3ODAxODZkNjEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfZGRhYTE0NDZiMDYyNDkzYzhlODE2NWJjNjMzMmE1Y2YgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs1MC40MzQ4LDU4LjAxNjRdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hYjI2ZWRhZDFkODA0YWNlYTVlMTRiZTBjMTNhMzc1OCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9jM2EzNzhmMmIyYzQ0ZmY1YTJkMDFlYzlmNjg2YTY5YiA9ICQoJzxkaXYgaWQ9Imh0bWxfYzNhMzc4ZjJiMmM0NGZmNWEyZDAxZWM5ZjY4NmE2OWIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkFLVE88L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2FiMjZlZGFkMWQ4MDRhY2VhNWUxNGJlMGMxM2EzNzU4LnNldENvbnRlbnQoaHRtbF9jM2EzNzhmMmIyYzQ0ZmY1YTJkMDFlYzlmNjg2YTY5Yik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2RkYWExNDQ2YjA2MjQ5M2M4ZTgxNjViYzYzMzJhNWNmLmJpbmRQb3B1cChwb3B1cF9hYjI2ZWRhZDFkODA0YWNlYTVlMTRiZTBjMTNhMzc1OCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl84ZjcxZTM5OTM3NTY0OTA2OTMxNmJhNmM3MmRlOWFkYyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzEuMzYwOCwxMDMuNzcyOV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2JhYmE2N2RhNzE0OTQwODRiZDk4N2ZhZTY2N2MyMTIzID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2IxZDE0ZGM3MGE0YjRhZDI5NjI2MWM2NjNmZmJhNGNiID0gJCgnPGRpdiBpZD0iaHRtbF9iMWQxNGRjNzBhNGI0YWQyOTYyNjFjNjYzZmZiYTRjYiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+QlRERjwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYmFiYTY3ZGE3MTQ5NDA4NGJkOTg3ZmFlNjY3YzIxMjMuc2V0Q29udGVudChodG1sX2IxZDE0ZGM3MGE0YjRhZDI5NjI2MWM2NjNmZmJhNGNiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfOGY3MWUzOTkzNzU2NDkwNjkzMTZiYTZjNzJkZTlhZGMuYmluZFBvcHVwKHBvcHVwX2JhYmE2N2RhNzE0OTQwODRiZDk4N2ZhZTY2N2MyMTIzKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2M5MjliMzcxZTZmODRlOTRiZTQ1OGMwMzU3NDg4NjZiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNzAuOTg2NiwtOC41MDU3XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMzA4Y2FjN2I5Mzk0NGIxY2IyMTkyNWQ1YjJlNmQ2NDIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZDJkNjMwMTE2YTliNDM5NDljMzRjMmYwNDExNWMwZmMgPSAkKCc8ZGl2IGlkPSJodG1sX2QyZDYzMDExNmE5YjQzOTQ5YzM0YzJmMDQxMTVjMGZjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5KTUlDPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8zMDhjYWM3YjkzOTQ0YjFjYjIxOTI1ZDViMmU2ZDY0Mi5zZXRDb250ZW50KGh0bWxfZDJkNjMwMTE2YTliNDM5NDljMzRjMmYwNDExNWMwZmMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9jOTI5YjM3MWU2Zjg0ZTk0YmU0NThjMDM1NzQ4ODY2Yi5iaW5kUG9wdXAocG9wdXBfMzA4Y2FjN2I5Mzk0NGIxY2IyMTkyNWQ1YjJlNmQ2NDIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMmU3Mzc1N2RkMDhkNDUzOTgyY2JhNWVhMDFkYThiNmEgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0Ny45NDYyLC05MS40OTUzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfYTc0ZDEyZmYwMGU1NGU1NzljOGU4YzE2MzE4MzMyNDcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZWU5OGNlYTA3YjE2NDM2MzkwNjU3ZjdmODIwZjIyN2IgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYzk0NmFmY2YxNjAwNGRkMGIyNGFiYmIxODZjZjllODUgPSAkKCc8ZGl2IGlkPSJodG1sX2M5NDZhZmNmMTYwMDRkZDBiMjRhYmJiMTg2Y2Y5ZTg1IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij48Yj5FWU1OPC9iPjwvaDQ+PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lZTk4Y2VhMDdiMTY0MzYzOTA2NTdmN2Y4MjBmMjI3Yi5zZXRDb250ZW50KGh0bWxfYzk0NmFmY2YxNjAwNGRkMGIyNGFiYmIxODZjZjllODUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8yZTczNzU3ZGQwOGQ0NTM5ODJjYmE1ZWEwMWRhOGI2YS5iaW5kUG9wdXAocG9wdXBfZWU5OGNlYTA3YjE2NDM2MzkwNjU3ZjdmODIwZjIyN2IpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMmM1ZWY1NGNkYzJiNDIwOWFjZjA5ZmZkZGZiODNlNjkgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFsxNC40ODcyNCw0OS4wMzc3OV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwX2E3NGQxMmZmMDBlNTRlNTc5YzhlOGMxNjMxODMzMjQ3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzI1MjhjZjMyNzRmZTRkMDZiZjkwZWE0ZmE2MTcyMDQxID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2Q1MzBjMGQ0Y2Y5YTQzZjZiNzM4ZDg1NmI4MGRiNmQ3ID0gJCgnPGRpdiBpZD0iaHRtbF9kNTMwYzBkNGNmOWE0M2Y2YjczOGQ4NTZiODBkYjZkNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+PGI+TVVLQTwvYj48L2g0PjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjUyOGNmMzI3NGZlNGQwNmJmOTBlYTRmYTYxNzIwNDEuc2V0Q29udGVudChodG1sX2Q1MzBjMGQ0Y2Y5YTQzZjZiNzM4ZDg1NmI4MGRiNmQ3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMmM1ZWY1NGNkYzJiNDIwOWFjZjA5ZmZkZGZiODNlNjkuYmluZFBvcHVwKHBvcHVwXzI1MjhjZjMyNzRmZTRkMDZiZjkwZWE0ZmE2MTcyMDQxKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzM3OTQxNzY4YzA4MjRjYjNiYTEyYWQ4NTg4NjNlNjE4ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbMTMuNjM1LDM4Ljk4MTFdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF9hNzRkMTJmZjAwZTU0ZTU3OWM4ZThjMTYzMTgzMzI0Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83MTdmNzlhZTYwOWY0NzhlODk1NmJiMjQxOWZiMzYwMCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xMGNlNzg3Y2Y2YmE0NjU5ODczOTFjNzg4ZTE5OTNjOSA9ICQoJzxkaXYgaWQ9Imh0bWxfMTBjZTc4N2NmNmJhNDY1OTg3MzkxYzc4OGUxOTkzYzkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPjxiPkFEWUU8L2I+PC9oND48L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzcxN2Y3OWFlNjA5ZjQ3OGU4OTU2YmIyNDE5ZmIzNjAwLnNldENvbnRlbnQoaHRtbF8xMGNlNzg3Y2Y2YmE0NjU5ODczOTFjNzg4ZTE5OTNjOSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzM3OTQxNzY4YzA4MjRjYjNiYTEyYWQ4NTg4NjNlNjE4LmJpbmRQb3B1cChwb3B1cF83MTdmNzlhZTYwOWY0NzhlODk1NmJiMjQxOWZiMzYwMCk7CgogICAgICAgICAgICAKICAgICAgICAKPC9zY3JpcHQ+\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
  815. ],
  816. "text/plain": [
  817. "<folium.folium.Map at 0x7f0e65593be0>"
  818. ]
  819. },
  820. "execution_count": 51,
  821. "metadata": {},
  822. "output_type": "execute_result"
  823. }
  824. ],
  825. "source": [
  826. "def plot_stations():\n",
  827. " import folium\n",
  828. " fmap = folium.Map(\n",
  829. " location=[best_source.lat, best_source.lon],\n",
  830. " tiles='Stamen Terrain',\n",
  831. " zoom_start=3)\n",
  832. " folium.Marker([best_source.lat, best_source.lon],\n",
  833. " popup=('2009 Aquila Earthquake'),\n",
  834. " icon=folium.Icon(color='red', icon='info-sign')).add_to(fmap)\n",
  835. " \n",
  836. " for s in stations_list:\n",
  837. " folium.Marker([s.lat, s.lon],\n",
  838. " popup='<b>%s</b></h4>' % s.station).add_to(fmap)\n",
  839. " fmap.add_child(folium.LatLngPopup())\n",
  840. " return fmap\n",
  841. " \n",
  842. "plot_stations()"
  843. ]
  844. },
  845. {
  846. "cell_type": "code",
  847. "execution_count": null,
  848. "metadata": {},
  849. "outputs": [],
  850. "source": [
  851. "plot_traces(result)"
  852. ]
  853. },
  854. {
  855. "cell_type": "markdown",
  856. "metadata": {},
  857. "source": [
  858. "Alternatively we can plot using snuffler, which will open in a seperate window."
  859. ]
  860. },
  861. {
  862. "cell_type": "code",
  863. "execution_count": null,
  864. "metadata": {},
  865. "outputs": [],
  866. "source": [
  867. "plot_snuffler(result)"
  868. ]
  869. }
  870. ],
  871. "metadata": {
  872. "kernelspec": {
  873. "display_name": "Python 3",
  874. "language": "python",
  875. "name": "python3"
  876. },
  877. "language_info": {
  878. "codemirror_mode": {
  879. "name": "ipython",
  880. "version": 3
  881. },
  882. "file_extension": ".py",
  883. "mimetype": "text/x-python",
  884. "name": "python",
  885. "nbconvert_exporter": "python",
  886. "pygments_lexer": "ipython3",
  887. "version": "3.6.3"
  888. }
  889. },
  890. "nbformat": 4,
  891. "nbformat_minor": 2
  892. }