-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcsce410.md.html
490 lines (490 loc) · 105 KB
/
csce410.md.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="pandoc" />
<title></title>
<style type="text/css">code{white-space: pre;}</style>
<link href="data:text/css;charset=utf-8,%0Ahtml%20%7B%0Afont%2Dsize%3A%20100%25%3B%0Aoverflow%2Dy%3A%20scroll%3B%0A%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%0A%2Dms%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%0A%7D%0Abody%20%7B%0Acolor%3A%20%23444%3B%0Afont%2Dfamily%3A%20Georgia%2C%20Palatino%2C%20%27Palatino%20Linotype%27%2C%20Times%2C%20%27Times%20New%20Roman%27%2C%20serif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E7%3B%0Apadding%3A%201em%3B%0Amargin%3A%20auto%3B%0Amax%2Dwidth%3A%2050em%3B%0Abackground%3A%20%23fefefe%3B%0A%7D%0Aa%2C%20p%2C%20dl%2C%20dt%2C%20ul%2C%20li%20%7B%0Afont%2Dsize%3A%2018px%3B%0A%7D%0Aa%20%7B%0Acolor%3A%20%230645ad%3B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0Aa%3Avisited%20%7B%0Acolor%3A%20%230b0080%3B%0A%7D%0Aa%3Ahover%20%7B%0Acolor%3A%20%2306e%3B%0A%7D%0Aa%3Aactive%20%7B%0Acolor%3A%20%23faa700%3B%0A%7D%0Aa%3Afocus%20%7B%0Aoutline%3A%20thin%20dotted%3B%0A%7D%0Ap%20%7B%0Amargin%3A%201em%200%3B%0A%7D%0Aimg%20%7B%0Amax%2Dwidth%3A%20100%25%3B%0A%7D%0Ah1%2C%20h2%2C%20h3%2C%20h4%2C%20h5%2C%20h6%20%7B%0Acolor%3A%20%23111%3B%0Aline%2Dheight%3A%20125%25%3B%0Amargin%2Dtop%3A%202em%3B%0Amargin%2Dbottom%3A%200%2E125em%3B%0Afont%2Dweight%3A%20normal%3B%0A%7D%0Ah4%2C%20h5%2C%20h6%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Ah1%20%7B%0Afont%2Dsize%3A%202em%3B%0A%7D%0Ah2%20%7B%0Afont%2Dsize%3A%201%2E5em%3B%0A%7D%0Ah3%20%7B%0Afont%2Dsize%3A%201%2E2em%3B%0A%7D%0Ah4%20%7B%0Afont%2Dsize%3A%201%2E1em%3B%0A%7D%0Ah5%20%7B%0Afont%2Dsize%3A%201em%3B%0A%7D%0Ah6%20%7B%0Afont%2Dsize%3A%200%2E9em%3B%0A%7D%0Ablockquote%20%7B%0Acolor%3A%20%23666666%3B%0Amargin%3A%200%3B%0Apadding%2Dleft%3A%203em%3B%0Aborder%2Dleft%3A%200%2E5em%20%23EEE%20solid%3B%0A%7D%0Ahr%20%7B%0Adisplay%3A%20block%3B%0Aheight%3A%202px%3B%0Aborder%3A%200%3B%0Aborder%2Dtop%3A%201px%20solid%20%23aaa%3B%0Aborder%2Dbottom%3A%201px%20solid%20%23eee%3B%0Amargin%3A%201em%200%3B%0Apadding%3A%200%3B%0A%7D%0Apre%2C%20code%2C%20kbd%2C%20samp%20%7B%0Acolor%3A%20%23000%3B%0Afont%2Dfamily%3A%20monospace%2C%20monospace%3B%0A%5Ffont%2Dfamily%3A%20%27courier%20new%27%2C%20monospace%3B%0Afont%2Dsize%3A%200%2E98em%3B%0A%7D%0Apre%20%7B%0Awhite%2Dspace%3A%20pre%3B%0Awhite%2Dspace%3A%20pre%2Dwrap%3B%0Aword%2Dwrap%3A%20break%2Dword%3B%0A%7D%0Ab%2C%20strong%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Adfn%20%7B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0Ains%20%7B%0Abackground%3A%20%23ff9%3B%0Acolor%3A%20%23000%3B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0Amark%20%7B%0Abackground%3A%20%23ff0%3B%0Acolor%3A%20%23000%3B%0Afont%2Dstyle%3A%20italic%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Asub%2C%20sup%20%7B%0Afont%2Dsize%3A%2075%25%3B%0Aline%2Dheight%3A%200%3B%0Aposition%3A%20relative%3B%0Avertical%2Dalign%3A%20baseline%3B%0A%7D%0Asup%20%7B%0Atop%3A%20%2D0%2E5em%3B%0A%7D%0Asub%20%7B%0Abottom%3A%20%2D0%2E25em%3B%0A%7D%0Aul%2C%20ol%20%7B%0Amargin%3A%200%3B%0Apadding%3A%200%200%200%201%2E25em%3B%0A%7D%0Ali%20p%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0Aul%20ul%2C%20ol%20ol%20%7B%0Amargin%3A%200%3B%0A%7D%0Adl%20%7B%0Amargin%2Dbottom%3A%201em%3B%0A%7D%0Adt%20%7B%0Afont%2Dweight%3A%20bold%3B%0Amargin%2Dbottom%3A%20%2E8em%3B%0A%7D%0Add%20%7B%0Amargin%3A%200%200%20%2E8em%202em%3B%0A%7D%0Add%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0Aimg%20%7B%0Aborder%3A%200%3B%0A%2Dms%2Dinterpolation%2Dmode%3A%20bicubic%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0Afigure%20%7B%0Adisplay%3A%20block%3B%0Atext%2Dalign%3A%20center%3B%0Amargin%3A%201em%200%3B%0A%7D%0Afigure%20img%20%7B%0Aborder%3A%20none%3B%0Amargin%3A%200%20auto%3B%0A%7D%0Afigcaption%20%7B%0Afont%2Dsize%3A%200%2E8em%3B%0Afont%2Dstyle%3A%20italic%3B%0Amargin%3A%200%200%20%2E8em%3B%0A%7D%0Atable%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0A%0Aborder%2Dbottom%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dright%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dspacing%3A%200%3B%0Aborder%2Dcollapse%3A%20collapse%3B%0A%7D%0Atable%20th%20%7B%0Apadding%3A%20%2E2em%201em%3B%0Abackground%2Dcolor%3A%20%23eee%3B%0Aborder%2Dtop%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dleft%3A%201px%20solid%20%23ddd%3B%0A%7D%0Atable%20td%20%7B%0Apadding%3A%20%2E2em%201em%3B%0Aborder%2Dtop%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dleft%3A%201px%20solid%20%23ddd%3B%0Avertical%2Dalign%3A%20top%3B%0A%7D%0A%2Eauthor%20%7B%0Afont%2Dsize%3A%201%2E2em%3B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%40media%20only%20screen%20and%20%28min%2Dwidth%3A%20480px%29%20%7B%0Abody%20%7B%0Afont%2Dsize%3A%2014px%3B%0A%7D%0A%7D%0A%40media%20only%20screen%20and%20%28min%2Dwidth%3A%20768px%29%20%7B%0Abody%20%7B%0Afont%2Dsize%3A%2016px%3B%0A%7D%0A%7D%0A%40media%20print%20%7B%0A%2A%20%7B%0Abackground%3A%20transparent%20%21important%3B%0Acolor%3A%20black%20%21important%3B%0Afilter%3A%20none%20%21important%3B%0A%2Dms%2Dfilter%3A%20none%20%21important%3B%0A%7D%0Abody%20%7B%0Afont%2Dsize%3A%2012pt%3B%0Amax%2Dwidth%3A%20100%25%3B%0A%7D%0Aa%2C%20a%3Avisited%20%7B%0Atext%2Ddecoration%3A%20underline%3B%0A%7D%0Ahr%20%7B%0Aheight%3A%201px%3B%0Aborder%3A%200%3B%0Aborder%2Dbottom%3A%201px%20solid%20black%3B%0A%7D%0Aa%5Bhref%5D%3Aafter%20%7B%0Acontent%3A%20%22%20%28%22%20attr%28href%29%20%22%29%22%3B%0A%7D%0Aabbr%5Btitle%5D%3Aafter%20%7B%0Acontent%3A%20%22%20%28%22%20attr%28title%29%20%22%29%22%3B%0A%7D%0A%2Eir%20a%3Aafter%2C%20a%5Bhref%5E%3D%22javascript%3A%22%5D%3Aafter%2C%20a%5Bhref%5E%3D%22%23%22%5D%3Aafter%20%7B%0Acontent%3A%20%22%22%3B%0A%7D%0Apre%2C%20blockquote%20%7B%0Aborder%3A%201px%20solid%20%23999%3B%0Apadding%2Dright%3A%201em%3B%0Apage%2Dbreak%2Dinside%3A%20avoid%3B%0A%7D%0Atr%2C%20img%20%7B%0Apage%2Dbreak%2Dinside%3A%20avoid%3B%0A%7D%0Aimg%20%7B%0Amax%2Dwidth%3A%20100%25%20%21important%3B%0A%7D%0A%40page%20%3Aleft%20%7B%0Amargin%3A%2015mm%2020mm%2015mm%2010mm%3B%0A%7D%0A%40page%20%3Aright%20%7B%0Amargin%3A%2015mm%2010mm%2015mm%2020mm%3B%0A%7D%0Ap%2C%20h2%2C%20h3%20%7B%0Aorphans%3A%203%3B%0Awidows%3A%203%3B%0A%7D%0Ah2%2C%20h3%20%7B%0Apage%2Dbreak%2Dafter%3A%20avoid%3B%0A%7D%0A%7D%0A" rel="stylesheet" type="text/css" />
<script src="data:application/javascript; charset=utf-8;base64,LyoKICogIC9NYXRoSmF4LmpzCiAqCiAqICBDb3B5cmlnaHQgKGMpIDIwMDktMjAxNyBUaGUgTWF0aEpheCBDb25zb3J0aXVtCiAqCiAqICBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICogIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICogIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAogKgogKiAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAogKgogKiAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogKiAgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKICogIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogKiAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogKiAgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiAqLwoKaWYoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQmJmRvY3VtZW50LmNoaWxkTm9kZXMmJmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQpe2lmKCEod2luZG93Lk1hdGhKYXgmJk1hdGhKYXguSHViKSl7aWYod2luZG93Lk1hdGhKYXgpe3dpbmRvdy5NYXRoSmF4PXtBdXRob3JDb25maWc6d2luZG93Lk1hdGhKYXh9fWVsc2V7d2luZG93Lk1hdGhKYXg9e319TWF0aEpheC5pc1BhY2tlZD10cnVlO01hdGhKYXgudmVyc2lvbj0iMi43LjEiO01hdGhKYXguZmlsZXZlcnNpb249IjIuNy4xIjtNYXRoSmF4LmNkblZlcnNpb249IjIuNy4xIjtNYXRoSmF4LmNkbkZpbGVWZXJzaW9ucz17fTsoZnVuY3Rpb24oZCl7dmFyIGI9d2luZG93W2RdO2lmKCFiKXtiPXdpbmRvd1tkXT17fX12YXIgZT1bXTt2YXIgYz1mdW5jdGlvbihmKXt2YXIgZz1mLmNvbnN0cnVjdG9yO2lmKCFnKXtnPWZ1bmN0aW9uKCl7fX1mb3IodmFyIGggaW4gZil7aWYoaCE9PSJjb25zdHJ1Y3RvciImJmYuaGFzT3duUHJvcGVydHkoaCkpe2dbaF09ZltoXX19cmV0dXJuIGd9O3ZhciBhPWZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGFyZ3VtZW50cy5jYWxsZWUuSW5pdC5jYWxsKHRoaXMsYXJndW1lbnRzKX19O2IuT2JqZWN0PWMoe2NvbnN0cnVjdG9yOmEoKSxTdWJjbGFzczpmdW5jdGlvbihmLGgpe3ZhciBnPWEoKTtnLlNVUEVSPXRoaXM7Zy5Jbml0PXRoaXMuSW5pdDtnLlN1YmNsYXNzPXRoaXMuU3ViY2xhc3M7Zy5BdWdtZW50PXRoaXMuQXVnbWVudDtnLnByb3RvRnVuY3Rpb249dGhpcy5wcm90b0Z1bmN0aW9uO2cuY2FuPXRoaXMuY2FuO2cuaGFzPXRoaXMuaGFzO2cuaXNhPXRoaXMuaXNhO2cucHJvdG90eXBlPW5ldyB0aGlzKGUpO2cucHJvdG90eXBlLmNvbnN0cnVjdG9yPWc7Zy5BdWdtZW50KGYsaCk7cmV0dXJuIGd9LEluaXQ6ZnVuY3Rpb24oZil7dmFyIGc9dGhpcztpZihmLmxlbmd0aD09PTEmJmZbMF09PT1lKXtyZXR1cm4gZ31pZighKGcgaW5zdGFuY2VvZiBmLmNhbGxlZSkpe2c9bmV3IGYuY2FsbGVlKGUpfXJldHVybiBnLkluaXQuYXBwbHkoZyxmKXx8Z30sQXVnbWVudDpmdW5jdGlvbihmLGcpe3ZhciBoO2lmKGYhPW51bGwpe2ZvcihoIGluIGYpe2lmKGYuaGFzT3duUHJvcGVydHkoaCkpe3RoaXMucHJvdG9GdW5jdGlvbihoLGZbaF0pfX1pZihmLnRvU3RyaW5nIT09dGhpcy5wcm90b3R5cGUudG9TdHJpbmcmJmYudG9TdHJpbmchPT17fS50b1N0cmluZyl7dGhpcy5wcm90b0Z1bmN0aW9uKCJ0b1N0cmluZyIsZi50b1N0cmluZyl9fWlmKGchPW51bGwpe2ZvcihoIGluIGcpe2lmKGcuaGFzT3duUHJvcGVydHkoaCkpe3RoaXNbaF09Z1toXX19fXJldHVybiB0aGlzfSxwcm90b0Z1bmN0aW9uOmZ1bmN0aW9uKGcsZil7dGhpcy5wcm90b3R5cGVbZ109ZjtpZih0eXBlb2YgZj09PSJmdW5jdGlvbiIpe2YuU1VQRVI9dGhpcy5TVVBFUi5wcm90b3R5cGV9fSxwcm90b3R5cGU6e0luaXQ6ZnVuY3Rpb24oKXt9LFNVUEVSOmZ1bmN0aW9uKGYpe3JldHVybiBmLmNhbGxlZS5TVVBFUn0sY2FuOmZ1bmN0aW9uKGYpe3JldHVybiB0eXBlb2YodGhpc1tmXSk9PT0iZnVuY3Rpb24ifSxoYXM6ZnVuY3Rpb24oZil7cmV0dXJuIHR5cGVvZih0aGlzW2ZdKSE9PSJ1bmRlZmluZWQifSxpc2E6ZnVuY3Rpb24oZil7cmV0dXJuKGYgaW5zdGFuY2VvZiBPYmplY3QpJiYodGhpcyBpbnN0YW5jZW9mIGYpfX0sY2FuOmZ1bmN0aW9uKGYpe3JldHVybiB0aGlzLnByb3RvdHlwZS5jYW4uY2FsbCh0aGlzLGYpfSxoYXM6ZnVuY3Rpb24oZil7cmV0dXJuIHRoaXMucHJvdG90eXBlLmhhcy5jYWxsKHRoaXMsZil9LGlzYTpmdW5jdGlvbihnKXt2YXIgZj10aGlzO3doaWxlKGYpe2lmKGY9PT1nKXtyZXR1cm4gdHJ1ZX1lbHNle2Y9Zi5TVVBFUn19cmV0dXJuIGZhbHNlfSxTaW1wbGVTVVBFUjpjKHtjb25zdHJ1Y3RvcjpmdW5jdGlvbihmKXtyZXR1cm4gdGhpcy5TaW1wbGVTVVBFUi5kZWZpbmUoZil9LGRlZmluZTpmdW5jdGlvbihmKXt2YXIgaD17fTtpZihmIT1udWxsKXtmb3IodmFyIGcgaW4gZil7aWYoZi5oYXNPd25Qcm9wZXJ0eShnKSl7aFtnXT10aGlzLndyYXAoZyxmW2ddKX19aWYoZi50b1N0cmluZyE9PXRoaXMucHJvdG90eXBlLnRvU3RyaW5nJiZmLnRvU3RyaW5nIT09e30udG9TdHJpbmcpe2gudG9TdHJpbmc9dGhpcy53cmFwKCJ0b1N0cmluZyIsZi50b1N0cmluZyl9fXJldHVybiBofSx3cmFwOmZ1bmN0aW9uKGksaCl7aWYodHlwZW9mKGgpIT09ImZ1bmN0aW9uInx8IWgudG9TdHJpbmcoKS5tYXRjaCgvXC5ccypTVVBFUlxzKlwoLykpe3JldHVybiBofXZhciBnPWZ1bmN0aW9uKCl7dGhpcy5TVVBFUj1nLlNVUEVSW2ldO3RyeXt2YXIgZj1oLmFwcGx5KHRoaXMsYXJndW1lbnRzKX1jYXRjaChqKXtkZWxldGUgdGhpcy5TVVBFUjt0aHJvdyBqfWRlbGV0ZSB0aGlzLlNVUEVSO3JldHVybiBmfTtnLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIGgudG9TdHJpbmcuYXBwbHkoaCxhcmd1bWVudHMpfTtyZXR1cm4gZ319KX0pO2IuT2JqZWN0LmlzQXJyYXk9QXJyYXkuaXNBcnJheXx8ZnVuY3Rpb24oZil7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChmKT09PSJbb2JqZWN0IEFycmF5XSJ9O2IuT2JqZWN0LkFycmF5PUFycmF5fSkoIk1hdGhKYXgiKTsoZnVuY3Rpb24oQkFTRU5BTUUpe3ZhciBCQVNFPXdpbmRvd1tCQVNFTkFNRV07aWYoIUJBU0Upe0JBU0U9d2luZG93W0JBU0VOQU1FXT17fX12YXIgaXNBcnJheT1CQVNFLk9iamVjdC5pc0FycmF5O3ZhciBDQUxMQkFDSz1mdW5jdGlvbihkYXRhKXt2YXIgY2I9ZnVuY3Rpb24oKXtyZXR1cm4gYXJndW1lbnRzLmNhbGxlZS5leGVjdXRlLmFwcGx5KGFyZ3VtZW50cy5jYWxsZWUsYXJndW1lbnRzKX07Zm9yKHZhciBpZCBpbiBDQUxMQkFDSy5wcm90b3R5cGUpe2lmKENBTExCQUNLLnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eShpZCkpe2lmKHR5cGVvZihkYXRhW2lkXSkhPT0idW5kZWZpbmVkIil7Y2JbaWRdPWRhdGFbaWRdfWVsc2V7Y2JbaWRdPUNBTExCQUNLLnByb3RvdHlwZVtpZF19fX1jYi50b1N0cmluZz1DQUxMQkFDSy5wcm90b3R5cGUudG9TdHJpbmc7cmV0dXJuIGNifTtDQUxMQkFDSy5wcm90b3R5cGU9e2lzQ2FsbGJhY2s6dHJ1ZSxob29rOmZ1bmN0aW9uKCl7fSxkYXRhOltdLG9iamVjdDp3aW5kb3csZXhlY3V0ZTpmdW5jdGlvbigpe2lmKCF0aGlzLmNhbGxlZHx8dGhpcy5hdXRvUmVzZXQpe3RoaXMuY2FsbGVkPSF0aGlzLmF1dG9SZXNldDtyZXR1cm4gdGhpcy5ob29rLmFwcGx5KHRoaXMub2JqZWN0LHRoaXMuZGF0YS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMsMCkpKX19LHJlc2V0OmZ1bmN0aW9uKCl7ZGVsZXRlIHRoaXMuY2FsbGVkfSx0b1N0cmluZzpmdW5jdGlvbigpe3JldHVybiB0aGlzLmhvb2sudG9TdHJpbmcuYXBwbHkodGhpcy5ob29rLGFyZ3VtZW50cyl9fTt2YXIgSVNDQUxMQkFDSz1mdW5jdGlvbihmKXtyZXR1cm4odHlwZW9mKGYpPT09ImZ1bmN0aW9uIiYmZi5pc0NhbGxiYWNrKX07dmFyIEVWQUw9ZnVuY3Rpb24oY29kZSl7cmV0dXJuIGV2YWwuY2FsbCh3aW5kb3csY29kZSl9O3ZhciBURVNURVZBTD1mdW5jdGlvbigpe0VWQUwoInZhciBfX1RlU3RfVmFSX18gPSAxIik7aWYod2luZG93Ll9fVGVTdF9WYVJfXyl7dHJ5e2RlbGV0ZSB3aW5kb3cuX19UZVN0X1ZhUl9ffWNhdGNoKGVycm9yKXt3aW5kb3cuX19UZVN0X1ZhUl9fPW51bGx9fWVsc2V7aWYod2luZG93LmV4ZWNTY3JpcHQpe0VWQUw9ZnVuY3Rpb24oY29kZSl7QkFTRS5fX2NvZGU9Y29kZTtjb2RlPSJ0cnkgeyIrQkFTRU5BTUUrIi5fX3Jlc3VsdCA9IGV2YWwoIitCQVNFTkFNRSsiLl9fY29kZSl9IGNhdGNoKGVycikgeyIrQkFTRU5BTUUrIi5fX3Jlc3VsdCA9IGVycn0iO3dpbmRvdy5leGVjU2NyaXB0KGNvZGUpO3ZhciByZXN1bHQ9QkFTRS5fX3Jlc3VsdDtkZWxldGUgQkFTRS5fX3Jlc3VsdDtkZWxldGUgQkFTRS5fX2NvZGU7aWYocmVzdWx0IGluc3RhbmNlb2YgRXJyb3Ipe3Rocm93IHJlc3VsdH1yZXR1cm4gcmVzdWx0fX1lbHNle0VWQUw9ZnVuY3Rpb24oY29kZSl7QkFTRS5fX2NvZGU9Y29kZTtjb2RlPSJ0cnkgeyIrQkFTRU5BTUUrIi5fX3Jlc3VsdCA9IGV2YWwoIitCQVNFTkFNRSsiLl9fY29kZSl9IGNhdGNoKGVycikgeyIrQkFTRU5BTUUrIi5fX3Jlc3VsdCA9IGVycn0iO3ZhciBoZWFkPShkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpKVswXTtpZighaGVhZCl7aGVhZD1kb2N1bWVudC5ib2R5fXZhciBzY3JpcHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7c2NyaXB0LmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGNvZGUpKTtoZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7aGVhZC5yZW1vdmVDaGlsZChzY3JpcHQpO3ZhciByZXN1bHQ9QkFTRS5fX3Jlc3VsdDtkZWxldGUgQkFTRS5fX3Jlc3VsdDtkZWxldGUgQkFTRS5fX2NvZGU7aWYocmVzdWx0IGluc3RhbmNlb2YgRXJyb3Ipe3Rocm93IHJlc3VsdH1yZXR1cm4gcmVzdWx0fX19VEVTVEVWQUw9bnVsbH07dmFyIFVTSU5HPWZ1bmN0aW9uKGFyZ3MsaSl7aWYoYXJndW1lbnRzLmxlbmd0aD4xKXtpZihhcmd1bWVudHMubGVuZ3RoPT09MiYmISh0eXBlb2YgYXJndW1lbnRzWzBdPT09ImZ1bmN0aW9uIikmJmFyZ3VtZW50c1swXSBpbnN0YW5jZW9mIE9iamVjdCYmdHlwZW9mIGFyZ3VtZW50c1sxXT09PSJudW1iZXIiKXthcmdzPVtdLnNsaWNlLmNhbGwoYXJncyxpKX1lbHNle2FyZ3M9W10uc2xpY2UuY2FsbChhcmd1bWVudHMsMCl9fWlmKGlzQXJyYXkoYXJncykmJmFyZ3MubGVuZ3RoPT09MSl7YXJncz1hcmdzWzBdfWlmKHR5cGVvZiBhcmdzPT09ImZ1bmN0aW9uIil7aWYoYXJncy5leGVjdXRlPT09Q0FMTEJBQ0sucHJvdG90eXBlLmV4ZWN1dGUpe3JldHVybiBhcmdzfXJldHVybiBDQUxMQkFDSyh7aG9vazphcmdzfSl9ZWxzZXtpZihpc0FycmF5KGFyZ3MpKXtpZih0eXBlb2YoYXJnc1swXSk9PT0ic3RyaW5nIiYmYXJnc1sxXSBpbnN0YW5jZW9mIE9iamVjdCYmdHlwZW9mIGFyZ3NbMV1bYXJnc1swXV09PT0iZnVuY3Rpb24iKXtyZXR1cm4gQ0FMTEJBQ0soe2hvb2s6YXJnc1sxXVthcmdzWzBdXSxvYmplY3Q6YXJnc1sxXSxkYXRhOmFyZ3Muc2xpY2UoMil9KX1lbHNle2lmKHR5cGVvZiBhcmdzWzBdPT09ImZ1bmN0aW9uIil7cmV0dXJuIENBTExCQUNLKHtob29rOmFyZ3NbMF0sZGF0YTphcmdzLnNsaWNlKDEpfSl9ZWxzZXtpZih0eXBlb2YgYXJnc1sxXT09PSJmdW5jdGlvbiIpe3JldHVybiBDQUxMQkFDSyh7aG9vazphcmdzWzFdLG9iamVjdDphcmdzWzBdLGRhdGE6YXJncy5zbGljZSgyKX0pfX19fWVsc2V7aWYodHlwZW9mKGFyZ3MpPT09InN0cmluZyIpe2lmKFRFU1RFVkFMKXtURVNURVZBTCgpfXJldHVybiBDQUxMQkFDSyh7aG9vazpFVkFMLGRhdGE6W2FyZ3NdfSl9ZWxzZXtpZihhcmdzIGluc3RhbmNlb2YgT2JqZWN0KXtyZXR1cm4gQ0FMTEJBQ0soYXJncyl9ZWxzZXtpZih0eXBlb2YoYXJncyk9PT0idW5kZWZpbmVkIil7cmV0dXJuIENBTExCQUNLKHt9KX19fX19dGhyb3cgRXJyb3IoIkNhbid0IG1ha2UgY2FsbGJhY2sgZnJvbSBnaXZlbiBkYXRhIil9O3ZhciBERUxBWT1mdW5jdGlvbih0aW1lLGNhbGxiYWNrKXtjYWxsYmFjaz1VU0lORyhjYWxsYmFjayk7Y2FsbGJhY2sudGltZW91dD1zZXRUaW1lb3V0KGNhbGxiYWNrLHRpbWUpO3JldHVybiBjYWxsYmFja307dmFyIFdBSVRGT1I9ZnVuY3Rpb24oY2FsbGJhY2ssc2lnbmFsKXtjYWxsYmFjaz1VU0lORyhjYWxsYmFjayk7aWYoIWNhbGxiYWNrLmNhbGxlZCl7V0FJVFNJR05BTChjYWxsYmFjayxzaWduYWwpO3NpZ25hbC5wZW5kaW5nKyt9fTt2YXIgV0FJVEVYRUNVVEU9ZnVuY3Rpb24oKXt2YXIgc2lnbmFscz10aGlzLnNpZ25hbDtkZWxldGUgdGhpcy5zaWduYWw7dGhpcy5leGVjdXRlPXRoaXMub2xkRXhlY3V0ZTtkZWxldGUgdGhpcy5vbGRFeGVjdXRlO3ZhciByZXN1bHQ9dGhpcy5leGVjdXRlLmFwcGx5KHRoaXMsYXJndW1lbnRzKTtpZihJU0NBTExCQUNLKHJlc3VsdCkmJiFyZXN1bHQuY2FsbGVkKXtXQUlUU0lHTkFMKHJlc3VsdCxzaWduYWxzKX1lbHNle2Zvcih2YXIgaT0wLG09c2lnbmFscy5sZW5ndGg7aTxtO2krKyl7c2lnbmFsc1tpXS5wZW5kaW5nLS07aWYoc2lnbmFsc1tpXS5wZW5kaW5nPD0wKXtzaWduYWxzW2ldLmNhbGwoKX19fX07dmFyIFdBSVRTSUdOQUw9ZnVuY3Rpb24oY2FsbGJhY2ssc2lnbmFscyl7aWYoIWlzQXJyYXkoc2lnbmFscykpe3NpZ25hbHM9W3NpZ25hbHNdfWlmKCFjYWxsYmFjay5zaWduYWwpe2NhbGxiYWNrLm9sZEV4ZWN1dGU9Y2FsbGJhY2suZXhlY3V0ZTtjYWxsYmFjay5leGVjdXRlPVdBSVRFWEVDVVRFO2NhbGxiYWNrLnNpZ25hbD1zaWduYWxzfWVsc2V7aWYoc2lnbmFscy5sZW5ndGg9PT0xKXtjYWxsYmFjay5zaWduYWwucHVzaChzaWduYWxzWzBdKX1lbHNle2NhbGxiYWNrLnNpZ25hbD1jYWxsYmFjay5zaWduYWwuY29uY2F0KHNpZ25hbHMpfX19O3ZhciBBRlRFUj1mdW5jdGlvbihjYWxsYmFjayl7Y2FsbGJhY2s9VVNJTkcoY2FsbGJhY2spO2NhbGxiYWNrLnBlbmRpbmc9MDtmb3IodmFyIGk9MSxtPWFyZ3VtZW50cy5sZW5ndGg7aTxtO2krKyl7aWYoYXJndW1lbnRzW2ldKXtXQUlURk9SKGFyZ3VtZW50c1tpXSxjYWxsYmFjayl9fWlmKGNhbGxiYWNrLnBlbmRpbmc9PT0wKXt2YXIgcmVzdWx0PWNhbGxiYWNrKCk7aWYoSVNDQUxMQkFDSyhyZXN1bHQpKXtjYWxsYmFjaz1yZXN1bHR9fXJldHVybiBjYWxsYmFja307dmFyIEhPT0tTPU1hdGhKYXguT2JqZWN0LlN1YmNsYXNzKHtJbml0OmZ1bmN0aW9uKHJlc2V0KXt0aGlzLmhvb2tzPVtdO3RoaXMucmVtb3ZlPVtdO3RoaXMucmVzZXQ9cmVzZXQ7dGhpcy5ydW5uaW5nPWZhbHNlfSxBZGQ6ZnVuY3Rpb24oaG9vayxwcmlvcml0eSl7aWYocHJpb3JpdHk9PW51bGwpe3ByaW9yaXR5PTEwfWlmKCFJU0NBTExCQUNLKGhvb2spKXtob29rPVVTSU5HKGhvb2spfWhvb2sucHJpb3JpdHk9cHJpb3JpdHk7dmFyIGk9dGhpcy5ob29rcy5sZW5ndGg7d2hpbGUoaT4wJiZwcmlvcml0eTx0aGlzLmhvb2tzW2ktMV0ucHJpb3JpdHkpe2ktLX10aGlzLmhvb2tzLnNwbGljZShpLDAsaG9vayk7cmV0dXJuIGhvb2t9LFJlbW92ZTpmdW5jdGlvbihob29rKXtmb3IodmFyIGk9MCxtPXRoaXMuaG9va3MubGVuZ3RoO2k8bTtpKyspe2lmKHRoaXMuaG9va3NbaV09PT1ob29rKXtpZih0aGlzLnJ1bm5pbmcpe3RoaXMucmVtb3ZlLnB1c2goaSl9ZWxzZXt0aGlzLmhvb2tzLnNwbGljZShpLDEpfXJldHVybn19fSxFeGVjdXRlOmZ1bmN0aW9uKCl7dmFyIGNhbGxiYWNrcz1be31dO3RoaXMucnVubmluZz10cnVlO2Zvcih2YXIgaT0wLG09dGhpcy5ob29rcy5sZW5ndGg7aTxtO2krKyl7aWYodGhpcy5yZXNldCl7dGhpcy5ob29rc1tpXS5yZXNldCgpfXZhciByZXN1bHQ9dGhpcy5ob29rc1tpXS5hcHBseSh3aW5kb3csYXJndW1lbnRzKTtpZihJU0NBTExCQUNLKHJlc3VsdCkmJiFyZXN1bHQuY2FsbGVkKXtjYWxsYmFja3MucHVzaChyZXN1bHQpfX10aGlzLnJ1bm5pbmc9ZmFsc2U7aWYodGhpcy5yZW1vdmUubGVuZ3RoKXt0aGlzLlJlbW92ZVBlbmRpbmcoKX1pZihjYWxsYmFja3MubGVuZ3RoPT09MSl7cmV0dXJuIG51bGx9aWYoY2FsbGJhY2tzLmxlbmd0aD09PTIpe3JldHVybiBjYWxsYmFja3NbMV19cmV0dXJuIEFGVEVSLmFwcGx5KHt9LGNhbGxiYWNrcyl9LFJlbW92ZVBlbmRpbmc6ZnVuY3Rpb24oKXt0aGlzLnJlbW92ZT10aGlzLnJlbW92ZS5zb3J0KCk7Zm9yKHZhciBpPXRoaXMucmVtb3ZlLmxlbmd0aC0xO2k+PTA7aS0tKXt0aGlzLmhvb2tzLnNwbGljZShpLDEpfXRoaXMucmVtb3ZlPVtdfX0pO3ZhciBFWEVDVVRFSE9PS1M9ZnVuY3Rpb24oaG9va3MsZGF0YSxyZXNldCl7aWYoIWhvb2tzKXtyZXR1cm4gbnVsbH1pZighaXNBcnJheShob29rcykpe2hvb2tzPVtob29rc119aWYoIWlzQXJyYXkoZGF0YSkpe2RhdGE9KGRhdGE9PW51bGw/W106W2RhdGFdKX12YXIgaGFuZGxlcj1IT09LUyhyZXNldCk7Zm9yKHZhciBpPTAsbT1ob29rcy5sZW5ndGg7aTxtO2krKyl7aGFuZGxlci5BZGQoaG9va3NbaV0pfXJldHVybiBoYW5kbGVyLkV4ZWN1dGUuYXBwbHkoaGFuZGxlcixkYXRhKX07dmFyIFFVRVVFPUJBU0UuT2JqZWN0LlN1YmNsYXNzKHtJbml0OmZ1bmN0aW9uKCl7dGhpcy5wZW5kaW5nPXRoaXMucnVubmluZz0wO3RoaXMucXVldWU9W107dGhpcy5QdXNoLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sUHVzaDpmdW5jdGlvbigpe3ZhciBjYWxsYmFjaztmb3IodmFyIGk9MCxtPWFyZ3VtZW50cy5sZW5ndGg7aTxtO2krKyl7Y2FsbGJhY2s9VVNJTkcoYXJndW1lbnRzW2ldKTtpZihjYWxsYmFjaz09PWFyZ3VtZW50c1tpXSYmIWNhbGxiYWNrLmNhbGxlZCl7Y2FsbGJhY2s9VVNJTkcoWyJ3YWl0Iix0aGlzLGNhbGxiYWNrXSl9dGhpcy5xdWV1ZS5wdXNoKGNhbGxiYWNrKX1pZighdGhpcy5ydW5uaW5nJiYhdGhpcy5wZW5kaW5nKXt0aGlzLlByb2Nlc3MoKX1yZXR1cm4gY2FsbGJhY2t9LFByb2Nlc3M6ZnVuY3Rpb24ocXVldWUpe3doaWxlKCF0aGlzLnJ1bm5pbmcmJiF0aGlzLnBlbmRpbmcmJnRoaXMucXVldWUubGVuZ3RoKXt2YXIgY2FsbGJhY2s9dGhpcy5xdWV1ZVswXTtxdWV1ZT10aGlzLnF1ZXVlLnNsaWNlKDEpO3RoaXMucXVldWU9W107dGhpcy5TdXNwZW5kKCk7dmFyIHJlc3VsdD1jYWxsYmFjaygpO3RoaXMuUmVzdW1lKCk7aWYocXVldWUubGVuZ3RoKXt0aGlzLnF1ZXVlPXF1ZXVlLmNvbmNhdCh0aGlzLnF1ZXVlKX1pZihJU0NBTExCQUNLKHJlc3VsdCkmJiFyZXN1bHQuY2FsbGVkKXtXQUlURk9SKHJlc3VsdCx0aGlzKX19fSxTdXNwZW5kOmZ1bmN0aW9uKCl7dGhpcy5ydW5uaW5nKyt9LFJlc3VtZTpmdW5jdGlvbigpe2lmKHRoaXMucnVubmluZyl7dGhpcy5ydW5uaW5nLS19fSxjYWxsOmZ1bmN0aW9uKCl7dGhpcy5Qcm9jZXNzLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sd2FpdDpmdW5jdGlvbihjYWxsYmFjayl7cmV0dXJuIGNhbGxiYWNrfX0pO3ZhciBTSUdOQUw9UVVFVUUuU3ViY2xhc3Moe0luaXQ6ZnVuY3Rpb24obmFtZSl7UVVFVUUucHJvdG90eXBlLkluaXQuY2FsbCh0aGlzKTt0aGlzLm5hbWU9bmFtZTt0aGlzLnBvc3RlZD1bXTt0aGlzLmxpc3RlbmVycz1IT09LUyh0cnVlKTt0aGlzLnBvc3Rpbmc9ZmFsc2U7dGhpcy5jYWxsYmFjaz1udWxsfSxQb3N0OmZ1bmN0aW9uKG1lc3NhZ2UsY2FsbGJhY2ssZm9yZ2V0KXtjYWxsYmFjaz1VU0lORyhjYWxsYmFjayk7aWYodGhpcy5wb3N0aW5nfHx0aGlzLnBlbmRpbmcpe3RoaXMuUHVzaChbIlBvc3QiLHRoaXMsbWVzc2FnZSxjYWxsYmFjayxmb3JnZXRdKX1lbHNle3RoaXMuY2FsbGJhY2s9Y2FsbGJhY2s7Y2FsbGJhY2sucmVzZXQoKTtpZighZm9yZ2V0KXt0aGlzLnBvc3RlZC5wdXNoKG1lc3NhZ2UpfXRoaXMuU3VzcGVuZCgpO3RoaXMucG9zdGluZz10cnVlO3ZhciByZXN1bHQ9dGhpcy5saXN0ZW5lcnMuRXhlY3V0ZShtZXNzYWdlKTtpZihJU0NBTExCQUNLKHJlc3VsdCkmJiFyZXN1bHQuY2FsbGVkKXtXQUlURk9SKHJlc3VsdCx0aGlzKX10aGlzLlJlc3VtZSgpO3RoaXMucG9zdGluZz1mYWxzZTtpZighdGhpcy5wZW5kaW5nKXt0aGlzLmNhbGwoKX19cmV0dXJuIGNhbGxiYWNrfSxDbGVhcjpmdW5jdGlvbihjYWxsYmFjayl7Y2FsbGJhY2s9VVNJTkcoY2FsbGJhY2spO2lmKHRoaXMucG9zdGluZ3x8dGhpcy5wZW5kaW5nKXtjYWxsYmFjaz10aGlzLlB1c2goWyJDbGVhciIsdGhpcyxjYWxsYmFja10pfWVsc2V7dGhpcy5wb3N0ZWQ9W107Y2FsbGJhY2soKX1yZXR1cm4gY2FsbGJhY2t9LGNhbGw6ZnVuY3Rpb24oKXt0aGlzLmNhbGxiYWNrKHRoaXMpO3RoaXMuUHJvY2VzcygpfSxJbnRlcmVzdDpmdW5jdGlvbihjYWxsYmFjayxpZ25vcmVQYXN0LHByaW9yaXR5KXtjYWxsYmFjaz1VU0lORyhjYWxsYmFjayk7dGhpcy5saXN0ZW5lcnMuQWRkKGNhbGxiYWNrLHByaW9yaXR5KTtpZighaWdub3JlUGFzdCl7Zm9yKHZhciBpPTAsbT10aGlzLnBvc3RlZC5sZW5ndGg7aTxtO2krKyl7Y2FsbGJhY2sucmVzZXQoKTt2YXIgcmVzdWx0PWNhbGxiYWNrKHRoaXMucG9zdGVkW2ldKTtpZihJU0NBTExCQUNLKHJlc3VsdCkmJmk9PT10aGlzLnBvc3RlZC5sZW5ndGgtMSl7V0FJVEZPUihyZXN1bHQsdGhpcyl9fX1yZXR1cm4gY2FsbGJhY2t9LE5vSW50ZXJlc3Q6ZnVuY3Rpb24oY2FsbGJhY2spe3RoaXMubGlzdGVuZXJzLlJlbW92ZShjYWxsYmFjayl9LE1lc3NhZ2VIb29rOmZ1bmN0aW9uKG1zZyxjYWxsYmFjayxwcmlvcml0eSl7Y2FsbGJhY2s9VVNJTkcoY2FsbGJhY2spO2lmKCF0aGlzLmhvb2tzKXt0aGlzLmhvb2tzPXt9O3RoaXMuSW50ZXJlc3QoWyJFeGVjdXRlSG9va3MiLHRoaXNdKX1pZighdGhpcy5ob29rc1ttc2ddKXt0aGlzLmhvb2tzW21zZ109SE9PS1ModHJ1ZSl9dGhpcy5ob29rc1ttc2ddLkFkZChjYWxsYmFjayxwcmlvcml0eSk7Zm9yKHZhciBpPTAsbT10aGlzLnBvc3RlZC5sZW5ndGg7aTxtO2krKyl7aWYodGhpcy5wb3N0ZWRbaV09PW1zZyl7Y2FsbGJhY2sucmVzZXQoKTtjYWxsYmFjayh0aGlzLnBvc3RlZFtpXSl9fWNhbGxiYWNrLm1zZz1tc2c7cmV0dXJuIGNhbGxiYWNrfSxFeGVjdXRlSG9va3M6ZnVuY3Rpb24obXNnKXt2YXIgdHlwZT0oaXNBcnJheShtc2cpP21zZ1swXTptc2cpO2lmKCF0aGlzLmhvb2tzW3R5cGVdKXtyZXR1cm4gbnVsbH1yZXR1cm4gdGhpcy5ob29rc1t0eXBlXS5FeGVjdXRlKG1zZyl9LFJlbW92ZUhvb2s6ZnVuY3Rpb24oaG9vayl7dGhpcy5ob29rc1tob29rLm1zZ10uUmVtb3ZlKGhvb2spfX0se3NpZ25hbHM6e30sZmluZDpmdW5jdGlvbihuYW1lKXtpZighU0lHTkFMLnNpZ25hbHNbbmFtZV0pe1NJR05BTC5zaWduYWxzW25hbWVdPW5ldyBTSUdOQUwobmFtZSl9cmV0dXJuIFNJR05BTC5zaWduYWxzW25hbWVdfX0pO0JBU0UuQ2FsbGJhY2s9QkFTRS5DYWxsQmFjaz1VU0lORztCQVNFLkNhbGxiYWNrLkRlbGF5PURFTEFZO0JBU0UuQ2FsbGJhY2suQWZ0ZXI9QUZURVI7QkFTRS5DYWxsYmFjay5RdWV1ZT1RVUVVRTtCQVNFLkNhbGxiYWNrLlNpZ25hbD1TSUdOQUwuZmluZDtCQVNFLkNhbGxiYWNrLkhvb2tzPUhPT0tTO0JBU0UuQ2FsbGJhY2suRXhlY3V0ZUhvb2tzPUVYRUNVVEVIT09LU30pKCJNYXRoSmF4Iik7KGZ1bmN0aW9uKGUpe3ZhciBhPXdpbmRvd1tlXTtpZighYSl7YT13aW5kb3dbZV09e319dmFyIGQ9KG5hdmlnYXRvci52ZW5kb3I9PT0iQXBwbGUgQ29tcHV0ZXIsIEluYy4iJiZ0eXBlb2YgbmF2aWdhdG9yLnZlbmRvclN1Yj09PSJ1bmRlZmluZWQiKTt2YXIgZz0wO3ZhciBoPWZ1bmN0aW9uKGkpe2lmKGRvY3VtZW50LnN0eWxlU2hlZXRzJiZkb2N1bWVudC5zdHlsZVNoZWV0cy5sZW5ndGg+Zyl7Zz1kb2N1bWVudC5zdHlsZVNoZWV0cy5sZW5ndGh9aWYoIWkpe2k9ZG9jdW1lbnQuaGVhZHx8KChkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpKVswXSk7aWYoIWkpe2k9ZG9jdW1lbnQuYm9keX19cmV0dXJuIGl9O3ZhciBmPVtdO3ZhciBjPWZ1bmN0aW9uKCl7Zm9yKHZhciBrPTAsaj1mLmxlbmd0aDtrPGo7aysrKXthLkFqYXguaGVhZC5yZW1vdmVDaGlsZChmW2tdKX1mPVtdfTt2YXIgYj17fTtiW2VdPSIiO2IuYTExeT0iW01hdGhKYXhdL2V4dGVuc2lvbnMvYTExeSI7Yi5Db250cmliPSJodHRwczovL2Nkbi5tYXRoamF4Lm9yZy9tYXRoamF4L2NvbnRyaWIiO2EuQWpheD17bG9hZGVkOnt9LGxvYWRpbmc6e30sbG9hZEhvb2tzOnt9LHRpbWVvdXQ6MTUqMTAwMCxzdHlsZURlbGF5OjEsY29uZmlnOntyb290OiIiLHBhdGg6Yn0scGFyYW1zOnt9LFNUQVRVUzp7T0s6MSxFUlJPUjotMX0sZmlsZVVSTDpmdW5jdGlvbihqKXt2YXIgaTt3aGlsZSgoaT1qLm1hdGNoKC9eXFsoWy0uX2EtejAtOV0rKVxdL2kpKSYmYi5oYXNPd25Qcm9wZXJ0eShpWzFdKSl7aj0oYltpWzFdXXx8dGhpcy5jb25maWcucm9vdCkrai5zdWJzdHIoaVsxXS5sZW5ndGgrMil9cmV0dXJuIGp9LGZpbGVOYW1lOmZ1bmN0aW9uKGope3ZhciBpPXRoaXMuY29uZmlnLnJvb3Q7aWYoai5zdWJzdHIoMCxpLmxlbmd0aCk9PT1pKXtqPSJbIitlKyJdIitqLnN1YnN0cihpLmxlbmd0aCl9ZG97dmFyIGs9ZmFsc2U7Zm9yKHZhciBsIGluIGIpe2lmKGIuaGFzT3duUHJvcGVydHkobCkmJmJbbF0pe2lmKGouc3Vic3RyKDAsYltsXS5sZW5ndGgpPT09YltsXSl7aj0iWyIrbCsiXSIrai5zdWJzdHIoYltsXS5sZW5ndGgpO2s9dHJ1ZTticmVha319fX13aGlsZShrKTtyZXR1cm4gan0sZmlsZVJldjpmdW5jdGlvbihqKXt2YXIgaT1hLmNkbkZpbGVWZXJzaW9uc1tqXXx8YS5jZG5WZXJzaW9ufHwiIjtpZihpKXtpPSI/Vj0iK2l9cmV0dXJuIGl9LHVybFJldjpmdW5jdGlvbihpKXtyZXR1cm4gdGhpcy5maWxlVVJMKGkpK3RoaXMuZmlsZVJldihpKX0sUmVxdWlyZTpmdW5jdGlvbihrLG4pe249YS5DYWxsYmFjayhuKTt2YXIgbDtpZihrIGluc3RhbmNlb2YgT2JqZWN0KXtmb3IodmFyIGogaW4gayl7aWYoay5oYXNPd25Qcm9wZXJ0eShqKSl7bD1qLnRvVXBwZXJDYXNlKCk7az1rW2pdfX19ZWxzZXtsPWsuc3BsaXQoL1wuLykucG9wKCkudG9VcHBlckNhc2UoKX1pZih0aGlzLnBhcmFtcy5ub0NvbnRyaWImJmsuc3Vic3RyKDAsOSk9PT0iW0NvbnRyaWJdIil7bih0aGlzLlNUQVRVUy5FUlJPUil9ZWxzZXtrPXRoaXMuZmlsZVVSTChrKTtpZih0aGlzLmxvYWRlZFtrXSl7bih0aGlzLmxvYWRlZFtrXSl9ZWxzZXt2YXIgbT17fTttW2xdPWs7dGhpcy5Mb2FkKG0sbil9fXJldHVybiBufSxMb2FkOmZ1bmN0aW9uKGssbSl7bT1hLkNhbGxiYWNrKG0pO3ZhciBsO2lmKGsgaW5zdGFuY2VvZiBPYmplY3Qpe2Zvcih2YXIgaiBpbiBrKXtpZihrLmhhc093blByb3BlcnR5KGopKXtsPWoudG9VcHBlckNhc2UoKTtrPWtbal19fX1lbHNle2w9ay5zcGxpdCgvXC4vKS5wb3AoKS50b1VwcGVyQ2FzZSgpfWs9dGhpcy5maWxlVVJMKGspO2lmKHRoaXMubG9hZGluZ1trXSl7dGhpcy5hZGRIb29rKGssbSl9ZWxzZXt0aGlzLmhlYWQ9aCh0aGlzLmhlYWQpO2lmKHRoaXMubG9hZGVyW2xdKXt0aGlzLmxvYWRlcltsXS5jYWxsKHRoaXMsayxtKX1lbHNle3Rocm93IEVycm9yKCJDYW4ndCBsb2FkIGZpbGVzIG9mIHR5cGUgIitsKX19cmV0dXJuIG19LExvYWRIb29rOmZ1bmN0aW9uKGwsbSxrKXttPWEuQ2FsbGJhY2sobSk7aWYobCBpbnN0YW5jZW9mIE9iamVjdCl7Zm9yKHZhciBqIGluIGwpe2lmKGwuaGFzT3duUHJvcGVydHkoaikpe2w9bFtqXX19fWw9dGhpcy5maWxlVVJMKGwpO2lmKHRoaXMubG9hZGVkW2xdKXttKHRoaXMubG9hZGVkW2xdKX1lbHNle3RoaXMuYWRkSG9vayhsLG0sayl9cmV0dXJuIG19LGFkZEhvb2s6ZnVuY3Rpb24oaixrLGkpe2lmKCF0aGlzLmxvYWRIb29rc1tqXSl7dGhpcy5sb2FkSG9va3Nbal09TWF0aEpheC5DYWxsYmFjay5Ib29rcygpfXRoaXMubG9hZEhvb2tzW2pdLkFkZChrLGkpO2suZmlsZT1qfSxyZW1vdmVIb29rOmZ1bmN0aW9uKGkpe2lmKHRoaXMubG9hZEhvb2tzW2kuZmlsZV0pe3RoaXMubG9hZEhvb2tzW2kuZmlsZV0uUmVtb3ZlKGkpO2lmKCF0aGlzLmxvYWRIb29rc1tpLmZpbGVdLmhvb2tzLmxlbmd0aCl7ZGVsZXRlIHRoaXMubG9hZEhvb2tzW2kuZmlsZV19fX0sUHJlbG9hZGluZzpmdW5jdGlvbigpe2Zvcih2YXIgbD0wLGo9YXJndW1lbnRzLmxlbmd0aDtsPGo7bCsrKXt2YXIgaz10aGlzLmZpbGVVUkwoYXJndW1lbnRzW2xdKTtpZighdGhpcy5sb2FkaW5nW2tdKXt0aGlzLmxvYWRpbmdba109e3ByZWxvYWRlZDp0cnVlfX19fSxsb2FkZXI6e0pTOmZ1bmN0aW9uKGssbSl7dmFyIGo9dGhpcy5maWxlTmFtZShrKTt2YXIgaT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKTt2YXIgbD1hLkNhbGxiYWNrKFsibG9hZFRpbWVvdXQiLHRoaXMsa10pO3RoaXMubG9hZGluZ1trXT17Y2FsbGJhY2s6bSx0aW1lb3V0OnNldFRpbWVvdXQobCx0aGlzLnRpbWVvdXQpLHN0YXR1czp0aGlzLlNUQVRVUy5PSyxzY3JpcHQ6aX07dGhpcy5sb2FkaW5nW2tdLm1lc3NhZ2U9YS5NZXNzYWdlLkZpbGUoaik7aS5vbmVycm9yPWw7aS50eXBlPSJ0ZXh0L2phdmFzY3JpcHQiO2kuc3JjPWsrdGhpcy5maWxlUmV2KGopO3RoaXMuaGVhZC5hcHBlbmRDaGlsZChpKX0sQ1NTOmZ1bmN0aW9uKGosbCl7dmFyIGk9dGhpcy5maWxlTmFtZShqKTt2YXIgaz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJsaW5rIik7ay5yZWw9InN0eWxlc2hlZXQiO2sudHlwZT0idGV4dC9jc3MiO2suaHJlZj1qK3RoaXMuZmlsZVJldihpKTt0aGlzLmxvYWRpbmdbal09e2NhbGxiYWNrOmwsbWVzc2FnZTphLk1lc3NhZ2UuRmlsZShpKSxzdGF0dXM6dGhpcy5TVEFUVVMuT0t9O3RoaXMuaGVhZC5hcHBlbmRDaGlsZChrKTt0aGlzLnRpbWVyLmNyZWF0ZS5jYWxsKHRoaXMsW3RoaXMudGltZXIuZmlsZSxqXSxrKX19LHRpbWVyOntjcmVhdGU6ZnVuY3Rpb24oaixpKXtqPWEuQ2FsbGJhY2soaik7aWYoaS5ub2RlTmFtZT09PSJTVFlMRSImJmkuc3R5bGVTaGVldCYmdHlwZW9mKGkuc3R5bGVTaGVldC5jc3NUZXh0KSE9PSJ1bmRlZmluZWQiKXtqKHRoaXMuU1RBVFVTLk9LKX1lbHNle2lmKHdpbmRvdy5jaHJvbWUmJmkubm9kZU5hbWU9PT0iTElOSyIpe2oodGhpcy5TVEFUVVMuT0spfWVsc2V7aWYoZCl7dGhpcy50aW1lci5zdGFydCh0aGlzLFt0aGlzLnRpbWVyLmNoZWNrU2FmYXJpMixnKyssal0sdGhpcy5zdHlsZURlbGF5KX1lbHNle3RoaXMudGltZXIuc3RhcnQodGhpcyxbdGhpcy50aW1lci5jaGVja0xlbmd0aCxpLGpdLHRoaXMuc3R5bGVEZWxheSl9fX1yZXR1cm4gan0sc3RhcnQ6ZnVuY3Rpb24oaixpLGssbCl7aT1hLkNhbGxiYWNrKGkpO2kuZXhlY3V0ZT10aGlzLmV4ZWN1dGU7aS50aW1lPXRoaXMudGltZTtpLlNUQVRVUz1qLlNUQVRVUztpLnRpbWVvdXQ9bHx8ai50aW1lb3V0O2kuZGVsYXk9aS50b3RhbD1rfHwwO2lmKGspe3NldFRpbWVvdXQoaSxrKX1lbHNle2koKX19LHRpbWU6ZnVuY3Rpb24oaSl7dGhpcy50b3RhbCs9dGhpcy5kZWxheTt0aGlzLmRlbGF5PU1hdGguZmxvb3IodGhpcy5kZWxheSoxLjA1KzUpO2lmKHRoaXMudG90YWw+PXRoaXMudGltZW91dCl7aSh0aGlzLlNUQVRVUy5FUlJPUik7cmV0dXJuIDF9cmV0dXJuIDB9LGZpbGU6ZnVuY3Rpb24oaixpKXtpZihpPDApe2EuQWpheC5sb2FkVGltZW91dChqKX1lbHNle2EuQWpheC5sb2FkQ29tcGxldGUoail9fSxleGVjdXRlOmZ1bmN0aW9uKCl7dGhpcy5ob29rLmNhbGwodGhpcy5vYmplY3QsdGhpcyx0aGlzLmRhdGFbMF0sdGhpcy5kYXRhWzFdKX0sY2hlY2tTYWZhcmkyOmZ1bmN0aW9uKGksaixrKXtpZihpLnRpbWUoaykpe3JldHVybn1pZihkb2N1bWVudC5zdHlsZVNoZWV0cy5sZW5ndGg+aiYmZG9jdW1lbnQuc3R5bGVTaGVldHNbal0uY3NzUnVsZXMmJmRvY3VtZW50LnN0eWxlU2hlZXRzW2pdLmNzc1J1bGVzLmxlbmd0aCl7ayhpLlNUQVRVUy5PSyl9ZWxzZXtzZXRUaW1lb3V0KGksaS5kZWxheSl9fSxjaGVja0xlbmd0aDpmdW5jdGlvbihpLGwsbil7aWYoaS50aW1lKG4pKXtyZXR1cm59dmFyIG09MDt2YXIgaj0obC5zaGVldHx8bC5zdHlsZVNoZWV0KTt0cnl7aWYoKGouY3NzUnVsZXN8fGoucnVsZXN8fFtdKS5sZW5ndGg+MCl7bT0xfX1jYXRjaChrKXtpZihrLm1lc3NhZ2UubWF0Y2goL3Byb3RlY3RlZCB2YXJpYWJsZXxyZXN0cmljdGVkIFVSSS8pKXttPTF9ZWxzZXtpZihrLm1lc3NhZ2UubWF0Y2goL1NlY3VyaXR5IGVycm9yLykpe209MX19fWlmKG0pe3NldFRpbWVvdXQoYS5DYWxsYmFjayhbbixpLlNUQVRVUy5PS10pLDApfWVsc2V7c2V0VGltZW91dChpLGkuZGVsYXkpfX19LGxvYWRDb21wbGV0ZTpmdW5jdGlvbihpKXtpPXRoaXMuZmlsZVVSTChpKTt2YXIgaj10aGlzLmxvYWRpbmdbaV07aWYoaiYmIWoucHJlbG9hZGVkKXthLk1lc3NhZ2UuQ2xlYXIoai5tZXNzYWdlKTtjbGVhclRpbWVvdXQoai50aW1lb3V0KTtpZihqLnNjcmlwdCl7aWYoZi5sZW5ndGg9PT0wKXtzZXRUaW1lb3V0KGMsMCl9Zi5wdXNoKGouc2NyaXB0KX10aGlzLmxvYWRlZFtpXT1qLnN0YXR1cztkZWxldGUgdGhpcy5sb2FkaW5nW2ldO3RoaXMuYWRkSG9vayhpLGouY2FsbGJhY2spfWVsc2V7aWYoail7ZGVsZXRlIHRoaXMubG9hZGluZ1tpXX10aGlzLmxvYWRlZFtpXT10aGlzLlNUQVRVUy5PSztqPXtzdGF0dXM6dGhpcy5TVEFUVVMuT0t9fWlmKCF0aGlzLmxvYWRIb29rc1tpXSl7cmV0dXJuIG51bGx9cmV0dXJuIHRoaXMubG9hZEhvb2tzW2ldLkV4ZWN1dGUoai5zdGF0dXMpfSxsb2FkVGltZW91dDpmdW5jdGlvbihpKXtpZih0aGlzLmxvYWRpbmdbaV0udGltZW91dCl7Y2xlYXJUaW1lb3V0KHRoaXMubG9hZGluZ1tpXS50aW1lb3V0KX10aGlzLmxvYWRpbmdbaV0uc3RhdHVzPXRoaXMuU1RBVFVTLkVSUk9SO3RoaXMubG9hZEVycm9yKGkpO3RoaXMubG9hZENvbXBsZXRlKGkpfSxsb2FkRXJyb3I6ZnVuY3Rpb24oaSl7YS5NZXNzYWdlLlNldChbIkxvYWRGYWlsZWQiLCJGaWxlIGZhaWxlZCB0byBsb2FkOiAlMSIsaV0sbnVsbCwyMDAwKTthLkh1Yi5zaWduYWwuUG9zdChbImZpbGUgbG9hZCBlcnJvciIsaV0pfSxTdHlsZXM6ZnVuY3Rpb24oayxsKXt2YXIgaT10aGlzLlN0eWxlU3RyaW5nKGspO2lmKGk9PT0iIil7bD1hLkNhbGxiYWNrKGwpO2woKX1lbHNle3ZhciBqPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInN0eWxlIik7ai50eXBlPSJ0ZXh0L2NzcyI7dGhpcy5oZWFkPWgodGhpcy5oZWFkKTt0aGlzLmhlYWQuYXBwZW5kQ2hpbGQoaik7aWYoai5zdHlsZVNoZWV0JiZ0eXBlb2Yoai5zdHlsZVNoZWV0LmNzc1RleHQpIT09InVuZGVmaW5lZCIpe2ouc3R5bGVTaGVldC5jc3NUZXh0PWl9ZWxzZXtqLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGkpKX1sPXRoaXMudGltZXIuY3JlYXRlLmNhbGwodGhpcyxsLGopfXJldHVybiBsfSxTdHlsZVN0cmluZzpmdW5jdGlvbihuKXtpZih0eXBlb2Yobik9PT0ic3RyaW5nIil7cmV0dXJuIG59dmFyIGs9IiIsbyxtO2ZvcihvIGluIG4pe2lmKG4uaGFzT3duUHJvcGVydHkobykpe2lmKHR5cGVvZiBuW29dPT09InN0cmluZyIpe2srPW8rIiB7IituW29dKyJ9XG4ifWVsc2V7aWYoYS5PYmplY3QuaXNBcnJheShuW29dKSl7Zm9yKHZhciBsPTA7bDxuW29dLmxlbmd0aDtsKyspe209e307bVtvXT1uW29dW2xdO2srPXRoaXMuU3R5bGVTdHJpbmcobSl9fWVsc2V7aWYoby5zdWJzdHIoMCw2KT09PSJAbWVkaWEiKXtrKz1vKyIgeyIrdGhpcy5TdHlsZVN0cmluZyhuW29dKSsifVxuIn1lbHNle2lmKG5bb10hPW51bGwpe209W107Zm9yKHZhciBqIGluIG5bb10pe2lmKG5bb10uaGFzT3duUHJvcGVydHkoaikpe2lmKG5bb11bal0hPW51bGwpe21bbS5sZW5ndGhdPWorIjogIituW29dW2pdfX19ays9bysiIHsiK20uam9pbigiOyAiKSsifVxuIn19fX19fXJldHVybiBrfX19KSgiTWF0aEpheCIpO01hdGhKYXguSFRNTD17RWxlbWVudDpmdW5jdGlvbihkLGYsZSl7dmFyIGc9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudChkKSxoO2lmKGYpe2lmKGYuaGFzT3duUHJvcGVydHkoInN0eWxlIikpe3ZhciBjPWYuc3R5bGU7Zi5zdHlsZT17fTtmb3IoaCBpbiBjKXtpZihjLmhhc093blByb3BlcnR5KGgpKXtmLnN0eWxlW2gucmVwbGFjZSgvLShbYS16XSkvZyx0aGlzLnVjTWF0Y2gpXT1jW2hdfX19TWF0aEpheC5IdWIuSW5zZXJ0KGcsZik7Zm9yKGggaW4gZil7aWYoaD09PSJyb2xlInx8aC5zdWJzdHIoMCw1KT09PSJhcmlhLSIpe2cuc2V0QXR0cmlidXRlKGgsZltoXSl9fX1pZihlKXtpZighTWF0aEpheC5PYmplY3QuaXNBcnJheShlKSl7ZT1bZV19Zm9yKHZhciBiPTAsYT1lLmxlbmd0aDtiPGE7YisrKXtpZihNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGVbYl0pKXtnLmFwcGVuZENoaWxkKHRoaXMuRWxlbWVudChlW2JdWzBdLGVbYl1bMV0sZVtiXVsyXSkpfWVsc2V7aWYoZD09PSJzY3JpcHQiKXt0aGlzLnNldFNjcmlwdChnLGVbYl0pfWVsc2V7Zy5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShlW2JdKSl9fX19cmV0dXJuIGd9LHVjTWF0Y2g6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYi50b1VwcGVyQ2FzZSgpfSxhZGRFbGVtZW50OmZ1bmN0aW9uKGIsYSxkLGMpe3JldHVybiBiLmFwcGVuZENoaWxkKHRoaXMuRWxlbWVudChhLGQsYykpfSxUZXh0Tm9kZTpmdW5jdGlvbihhKXtyZXR1cm4gZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoYSl9LGFkZFRleHQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYS5hcHBlbmRDaGlsZCh0aGlzLlRleHROb2RlKGIpKX0sc2V0U2NyaXB0OmZ1bmN0aW9uKGEsYil7aWYodGhpcy5zZXRTY3JpcHRCdWcpe2EudGV4dD1ifWVsc2V7d2hpbGUoYS5maXJzdENoaWxkKXthLnJlbW92ZUNoaWxkKGEuZmlyc3RDaGlsZCl9dGhpcy5hZGRUZXh0KGEsYil9fSxnZXRTY3JpcHQ6ZnVuY3Rpb24oYSl7dmFyIGI9KGEudGV4dD09PSIiP2EuaW5uZXJIVE1MOmEudGV4dCk7cmV0dXJuIGIucmVwbGFjZSgvXlxzKy8sIiIpLnJlcGxhY2UoL1xzKyQvLCIiKX0sQ29va2llOntwcmVmaXg6Im1qeCIsZXhwaXJlczozNjUsU2V0OmZ1bmN0aW9uKGEsZSl7dmFyIGQ9W107aWYoZSl7Zm9yKHZhciBnIGluIGUpe2lmKGUuaGFzT3duUHJvcGVydHkoZykpe2QucHVzaChnKyI6IitlW2ddLnRvU3RyaW5nKCkucmVwbGFjZSgvJi9nLCImJiIpKX19fXZhciBiPXRoaXMucHJlZml4KyIuIithKyI9Iitlc2NhcGUoZC5qb2luKCImOyIpKTtpZih0aGlzLmV4cGlyZXMpe3ZhciBmPW5ldyBEYXRlKCk7Zi5zZXREYXRlKGYuZ2V0RGF0ZSgpK3RoaXMuZXhwaXJlcyk7Yis9IjsgZXhwaXJlcz0iK2YudG9HTVRTdHJpbmcoKX10cnl7ZG9jdW1lbnQuY29va2llPWIrIjsgcGF0aD0vIn1jYXRjaChjKXt9fSxHZXQ6ZnVuY3Rpb24oYSxkKXtpZighZCl7ZD17fX12YXIgZz1uZXcgUmVnRXhwKCIoPzpefDtcXHMqKSIrdGhpcy5wcmVmaXgrIlxcLiIrYSsiPShbXjtdKikoPzo7fCQpIik7dmFyIGY7dHJ5e2Y9Zy5leGVjKGRvY3VtZW50LmNvb2tpZSl9Y2F0Y2goYyl7fWlmKGYmJmZbMV0hPT0iIil7dmFyIGo9dW5lc2NhcGUoZlsxXSkuc3BsaXQoIiY7Iik7Zm9yKHZhciBlPTAsYj1qLmxlbmd0aDtlPGI7ZSsrKXtmPWpbZV0ubWF0Y2goLyhbXjpdKyk6KC4qKS8pO3ZhciBoPWZbMl0ucmVwbGFjZSgvJiYvZywiJiIpO2lmKGg9PT0idHJ1ZSIpe2g9dHJ1ZX1lbHNle2lmKGg9PT0iZmFsc2UiKXtoPWZhbHNlfWVsc2V7aWYoaC5tYXRjaCgvXi0/KFxkKyhcLlxkKyk/fFwuXGQrKSQvKSl7aD1wYXJzZUZsb2F0KGgpfX19ZFtmWzFdXT1ofX1yZXR1cm4gZH19fTtNYXRoSmF4LkxvY2FsaXphdGlvbj17bG9jYWxlOiJlbiIsZGlyZWN0b3J5OiJbTWF0aEpheF0vbG9jYWxpemF0aW9uIixzdHJpbmdzOnthc3Q6e21lbnVUaXRsZToiYXN0dXJpYW51In0sYmc6e21lbnVUaXRsZToiXHUwNDMxXHUwNDRBXHUwNDNCXHUwNDMzXHUwNDMwXHUwNDQwXHUwNDQxXHUwNDNBXHUwNDM4In0sYmNjOnttZW51VGl0bGU6Ilx1MDYyOFx1MDY0NFx1MDY0OFx1MDY4Nlx1MDZDQyJ9LGJyOnttZW51VGl0bGU6ImJyZXpob25lZyJ9LGNhOnttZW51VGl0bGU6ImNhdGFsXHUwMEUwIn0sY2RvOnttZW51VGl0bGU6Ik1cdTAwRUNuZy1kXHUwMTE1XHUwMzI0bmctbmdcdTFFNzNcdTAzMDQifSxjczp7bWVudVRpdGxlOiJcdTAxMERlXHUwMTYxdGluYSJ9LGRhOnttZW51VGl0bGU6ImRhbnNrIn0sZGU6e21lbnVUaXRsZToiRGV1dHNjaCJ9LGRpcTp7bWVudVRpdGxlOiJaYXpha2kifSxlbjp7bWVudVRpdGxlOiJFbmdsaXNoIixpc0xvYWRlZDp0cnVlfSxlbzp7bWVudVRpdGxlOiJFc3BlcmFudG8ifSxlczp7bWVudVRpdGxlOiJlc3BhXHUwMEYxb2wifSxmYTp7bWVudVRpdGxlOiJcdTA2NDFcdTA2MjdcdTA2MzFcdTA2MzNcdTA2Q0MifSxmaTp7bWVudVRpdGxlOiJzdW9taSJ9LGZyOnttZW51VGl0bGU6ImZyYW5cdTAwRTdhaXMifSxnbDp7bWVudVRpdGxlOiJnYWxlZ28ifSxoZTp7bWVudVRpdGxlOiJcdTA1RTJcdTA1RDFcdTA1RThcdTA1RDlcdTA1RUEifSxpYTp7bWVudVRpdGxlOiJpbnRlcmxpbmd1YSJ9LGl0OnttZW51VGl0bGU6Iml0YWxpYW5vIn0samE6e21lbnVUaXRsZToiXHU2NUU1XHU2NzJDXHU4QTlFIn0sa246e21lbnVUaXRsZToiXHUwQzk1XHUwQ0E4XHUwQ0NEXHUwQ0E4XHUwQ0ExIn0sa286e21lbnVUaXRsZToiXHVENTVDXHVBRDZEXHVDNUI0In0sbGI6e21lbnVUaXRsZToiTFx1MDBFQnR6ZWJ1ZXJnZXNjaCJ9LGxraTp7bWVudVRpdGxlOiJcdTA2NDRcdTA2RDVcdTA2QTlcdTA2Q0MifSxsdDp7bWVudVRpdGxlOiJsaWV0dXZpXHUwMTczIn0sbWs6e21lbnVUaXRsZToiXHUwNDNDXHUwNDMwXHUwNDNBXHUwNDM1XHUwNDM0XHUwNDNFXHUwNDNEXHUwNDQxXHUwNDNBXHUwNDM4In0sbmw6e21lbnVUaXRsZToiTmVkZXJsYW5kcyJ9LG9jOnttZW51VGl0bGU6Im9jY2l0YW4ifSxwbDp7bWVudVRpdGxlOiJwb2xza2kifSxwdDp7bWVudVRpdGxlOiJwb3J0dWd1c1x1MDBFQSJ9LCJwdC1iciI6e21lbnVUaXRsZToicG9ydHVndVx1MDBFQXMgZG8gQnJhc2lsIn0scnU6e21lbnVUaXRsZToiXHUwNDQwXHUwNDQzXHUwNDQxXHUwNDQxXHUwNDNBXHUwNDM4XHUwNDM5In0sc2NvOnttZW51VGl0bGU6IlNjb3RzIn0sc2NuOnttZW51VGl0bGU6InNpY2lsaWFudSJ9LHNsOnttZW51VGl0bGU6InNsb3Zlblx1MDE2MVx1MDEwRGluYSJ9LHN2OnttZW51VGl0bGU6InN2ZW5za2EifSx0cjp7bWVudVRpdGxlOiJUXHUwMEZDcmtcdTAwRTdlIn0sdWs6e21lbnVUaXRsZToiXHUwNDQzXHUwNDNBXHUwNDQwXHUwNDMwXHUwNDU3XHUwNDNEXHUwNDQxXHUwNDRDXHUwNDNBXHUwNDMwIn0sdmk6e21lbnVUaXRsZToiVGlcdTFFQkZuZyBWaVx1MUVDN3QifSwiemgtaGFucyI6e21lbnVUaXRsZToiXHU0RTJEXHU2NTg3XHVGRjA4XHU3QjgwXHU0RjUzXHVGRjA5In19LHBhdHRlcm46LyUoXGQrfFx7XGQrXH18XHtbYS16XSs6XCVcZCsoPzpcfCg/OiVce1xkK1x9fCUufFteXH1dKSopK1x9fC4pL2csU1BMSVQ6KCJheGIiLnNwbGl0KC8oeCkvKS5sZW5ndGg9PT0zP2Z1bmN0aW9uKGEsYil7cmV0dXJuIGEuc3BsaXQoYil9OmZ1bmN0aW9uKGMsZSl7dmFyIGE9W10sYixkPTA7ZS5sYXN0SW5kZXg9MDt3aGlsZSgoYj1lLmV4ZWMoYykpKXthLnB1c2goYy5zdWJzdHIoZCxiLmluZGV4LWQpKTthLnB1c2guYXBwbHkoYSxiLnNsaWNlKDEpKTtkPWIuaW5kZXgrYlswXS5sZW5ndGh9YS5wdXNoKGMuc3Vic3RyKGQpKTtyZXR1cm4gYX0pLF86ZnVuY3Rpb24oYixhKXtpZihNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGEpKXtyZXR1cm4gdGhpcy5wcm9jZXNzU25pcHBldChiLGEpfXJldHVybiB0aGlzLnByb2Nlc3NTdHJpbmcodGhpcy5sb29rdXBQaHJhc2UoYixhKSxbXS5zbGljZS5jYWxsKGFyZ3VtZW50cywyKSl9LHByb2Nlc3NTdHJpbmc6ZnVuY3Rpb24obCxwLGcpe3ZhciBqLGUsbz1NYXRoSmF4Lk9iamVjdC5pc0FycmF5O2ZvcihqPTAsZT1wLmxlbmd0aDtqPGU7aisrKXtpZihnJiZvKHBbal0pKXtwW2pdPXRoaXMucHJvY2Vzc1NuaXBwZXQoZyxwW2pdKX19dmFyIGY9dGhpcy5TUExJVChsLHRoaXMucGF0dGVybik7Zm9yKGo9MSxlPWYubGVuZ3RoO2o8ZTtqKz0yKXt2YXIgcT1mW2pdLmNoYXJBdCgwKTtpZihxPj0iMCImJnE8PSI5Iil7ZltqXT1wW2Zbal0tMV07aWYodHlwZW9mIGZbal09PT0ibnVtYmVyIil7ZltqXT10aGlzLm51bWJlcihmW2pdKX19ZWxzZXtpZihxPT09InsiKXtxPWZbal0uc3Vic3RyKDEpO2lmKHE+PSIwIiYmcTw9IjkiKXtmW2pdPXBbZltqXS5zdWJzdHIoMSxmW2pdLmxlbmd0aC0yKS0xXTtpZih0eXBlb2YgZltqXT09PSJudW1iZXIiKXtmW2pdPXRoaXMubnVtYmVyKGZbal0pfX1lbHNle3ZhciBrPWZbal0ubWF0Y2goL15ceyhbYS16XSspOiUoXGQrKVx8KC4qKVx9JC8pO2lmKGspe2lmKGtbMV09PT0icGx1cmFsIil7dmFyIGQ9cFtrWzJdLTFdO2lmKHR5cGVvZiBkPT09InVuZGVmaW5lZCIpe2Zbal09Ij8/PyJ9ZWxzZXtkPXRoaXMucGx1cmFsKGQpLTE7dmFyIGg9a1szXS5yZXBsYWNlKC8oXnxbXiVdKSglJSkqJVx8L2csIiQxJDIlXHVFRkVGIikuc3BsaXQoL1x8Lyk7aWYoZD49MCYmZDxoLmxlbmd0aCl7ZltqXT10aGlzLnByb2Nlc3NTdHJpbmcoaFtkXS5yZXBsYWNlKC9cdUVGRUYvZywifCIpLHAsZyl9ZWxzZXtmW2pdPSI/Pz8ifX19ZWxzZXtmW2pdPSIlIitmW2pdfX19fX1pZihmW2pdPT1udWxsKXtmW2pdPSI/Pz8ifX1pZighZyl7cmV0dXJuIGYuam9pbigiIil9dmFyIGE9W10sYj0iIjtmb3Ioaj0wO2o8ZTtqKyspe2IrPWZbal07aisrO2lmKGo8ZSl7aWYobyhmW2pdKSl7YS5wdXNoKGIpO2E9YS5jb25jYXQoZltqXSk7Yj0iIn1lbHNle2IrPWZbal19fX1pZihiIT09IiIpe2EucHVzaChiKX1yZXR1cm4gYX0scHJvY2Vzc1NuaXBwZXQ6ZnVuY3Rpb24oZyxlKXt2YXIgYz1bXTtmb3IodmFyIGQ9MCxiPWUubGVuZ3RoO2Q8YjtkKyspe2lmKE1hdGhKYXguT2JqZWN0LmlzQXJyYXkoZVtkXSkpe3ZhciBmPWVbZF07aWYodHlwZW9mIGZbMV09PT0ic3RyaW5nIil7dmFyIGg9ZlswXTtpZighTWF0aEpheC5PYmplY3QuaXNBcnJheShoKSl7aD1bZyxoXX12YXIgYT10aGlzLmxvb2t1cFBocmFzZShoLGZbMV0pO2M9Yy5jb25jYXQodGhpcy5wcm9jZXNzTWFya2Rvd24oYSxmLnNsaWNlKDIpLGcpKX1lbHNle2lmKE1hdGhKYXguT2JqZWN0LmlzQXJyYXkoZlsxXSkpe2M9Yy5jb25jYXQodGhpcy5wcm9jZXNzU25pcHBldC5hcHBseSh0aGlzLGYpKX1lbHNle2lmKGYubGVuZ3RoPj0zKXtjLnB1c2goW2ZbMF0sZlsxXSx0aGlzLnByb2Nlc3NTbmlwcGV0KGcsZlsyXSldKX1lbHNle2MucHVzaChlW2RdKX19fX1lbHNle2MucHVzaChlW2RdKX19cmV0dXJuIGN9LG1hcmtkb3duUGF0dGVybjovKCUuKXwoXCp7MSwzfSkoKD86JS58LikrPylcMnwoYCspKCg/OiUufC4pKz8pXDR8XFsoKD86JS58LikrPylcXVwoKFteXHNcKV0rKVwpLyxwcm9jZXNzTWFya2Rvd246ZnVuY3Rpb24oYixoLGQpe3ZhciBqPVtdLGU7dmFyIGM9Yi5zcGxpdCh0aGlzLm1hcmtkb3duUGF0dGVybik7dmFyIGc9Y1swXTtmb3IodmFyIGY9MSxhPWMubGVuZ3RoO2Y8YTtmKz04KXtpZihjW2YrMV0pe2U9dGhpcy5wcm9jZXNzU3RyaW5nKGNbZisyXSxoLGQpO2lmKCFNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGUpKXtlPVtlXX1lPVtbImIiLCJpIiwiaSJdW2NbZisxXS5sZW5ndGgtMV0se30sZV07aWYoY1tmKzFdLmxlbmd0aD09PTMpe2U9WyJiIix7fSxlXX19ZWxzZXtpZihjW2YrM10pe2U9dGhpcy5wcm9jZXNzU3RyaW5nKGNbZis0XS5yZXBsYWNlKC9eXHMvLCIiKS5yZXBsYWNlKC9ccyQvLCIiKSxoLGQpO2lmKCFNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGUpKXtlPVtlXX1lPVsiY29kZSIse30sZV19ZWxzZXtpZihjW2YrNV0pe2U9dGhpcy5wcm9jZXNzU3RyaW5nKGNbZis1XSxoLGQpO2lmKCFNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGUpKXtlPVtlXX1lPVsiYSIse2hyZWY6dGhpcy5wcm9jZXNzU3RyaW5nKGNbZis2XSxoKSx0YXJnZXQ6Il9ibGFuayJ9LGVdfWVsc2V7Zys9Y1tmXTtlPW51bGx9fX1pZihlKXtqPXRoaXMuY29uY2F0U3RyaW5nKGosZyxoLGQpO2oucHVzaChlKTtnPSIifWlmKGNbZis3XSE9PSIiKXtnKz1jW2YrN119fWo9dGhpcy5jb25jYXRTdHJpbmcoaixnLGgsZCk7cmV0dXJuIGp9LGNvbmNhdFN0cmluZzpmdW5jdGlvbihhLGMsYixkKXtpZihjIT0iIil7Yz10aGlzLnByb2Nlc3NTdHJpbmcoYyxiLGQpO2lmKCFNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGMpKXtjPVtjXX1hPWEuY29uY2F0KGMpfXJldHVybiBhfSxsb29rdXBQaHJhc2U6ZnVuY3Rpb24oZixhLGQpe2lmKCFkKXtkPSJfIn1pZihNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGYpKXtkPShmWzBdfHwiXyIpO2Y9KGZbMV18fCIiKX12YXIgYz10aGlzLmxvYWREb21haW4oZCk7aWYoYyl7TWF0aEpheC5IdWIuUmVzdGFydEFmdGVyKGMpfXZhciBiPXRoaXMuc3RyaW5nc1t0aGlzLmxvY2FsZV07aWYoYil7aWYoYi5kb21haW5zJiZkIGluIGIuZG9tYWlucyl7dmFyIGU9Yi5kb21haW5zW2RdO2lmKGUuc3RyaW5ncyYmZiBpbiBlLnN0cmluZ3Mpe2E9ZS5zdHJpbmdzW2ZdfX19cmV0dXJuIGF9LGxvYWRGaWxlOmZ1bmN0aW9uKGIsZCxlKXtlPU1hdGhKYXguQ2FsbGJhY2soZSk7Yj0oZC5maWxlfHxiKTtpZighYi5tYXRjaCgvXC5qcyQvKSl7Yis9Ii5qcyJ9aWYoIWIubWF0Y2goL14oW2Etel0rOnxcW01hdGhKYXhcXSkvKSl7dmFyIGE9KHRoaXMuc3RyaW5nc1t0aGlzLmxvY2FsZV0uZGlyZWN0b3J5fHx0aGlzLmRpcmVjdG9yeSsiLyIrdGhpcy5sb2NhbGV8fCJbTWF0aEpheF0vbG9jYWxpemF0aW9uLyIrdGhpcy5sb2NhbGUpO2I9YSsiLyIrYn12YXIgYz1NYXRoSmF4LkFqYXguUmVxdWlyZShiLGZ1bmN0aW9uKCl7ZC5pc0xvYWRlZD10cnVlO3JldHVybiBlKCl9KTtyZXR1cm4oYy5jYWxsZWQ/bnVsbDpjKX0sbG9hZERvbWFpbjpmdW5jdGlvbihjLGUpe3ZhciBiLGE9dGhpcy5zdHJpbmdzW3RoaXMubG9jYWxlXTtpZihhKXtpZighYS5pc0xvYWRlZCl7Yj10aGlzLmxvYWRGaWxlKHRoaXMubG9jYWxlLGEpO2lmKGIpe3JldHVybiBNYXRoSmF4LkNhbGxiYWNrLlF1ZXVlKGIsWyJsb2FkRG9tYWluIix0aGlzLGNdKS5QdXNoKGV8fHt9KX19aWYoYS5kb21haW5zJiZjIGluIGEuZG9tYWlucyl7dmFyIGQ9YS5kb21haW5zW2NdO2lmKCFkLmlzTG9hZGVkKXtiPXRoaXMubG9hZEZpbGUoYyxkKTtpZihiKXtyZXR1cm4gTWF0aEpheC5DYWxsYmFjay5RdWV1ZShiKS5QdXNoKGUpfX19fXJldHVybiBNYXRoSmF4LkNhbGxiYWNrKGUpKCl9LFRyeTpmdW5jdGlvbihhKXthPU1hdGhKYXguQ2FsbGJhY2soYSk7YS5hdXRvUmVzZXQ9dHJ1ZTt0cnl7YSgpfWNhdGNoKGIpe2lmKCFiLnJlc3RhcnQpe3Rocm93IGJ9TWF0aEpheC5DYWxsYmFjay5BZnRlcihbIlRyeSIsdGhpcyxhXSxiLnJlc3RhcnQpfX0scmVzZXRMb2NhbGU6ZnVuY3Rpb24oYSl7aWYoIWEpe3JldHVybn1hPWEudG9Mb3dlckNhc2UoKTt3aGlsZSghdGhpcy5zdHJpbmdzW2FdKXt2YXIgYz1hLmxhc3RJbmRleE9mKCItIik7aWYoYz09PS0xKXtyZXR1cm59YT1hLnN1YnN0cmluZygwLGMpfXZhciBiPXRoaXMuc3RyaW5nc1thXS5yZW1hcDt0aGlzLmxvY2FsZT1iP2I6YX0sc2V0TG9jYWxlOmZ1bmN0aW9uKGEpe3RoaXMucmVzZXRMb2NhbGUoYSk7aWYoTWF0aEpheC5NZW51KXt0aGlzLmxvYWREb21haW4oIk1hdGhNZW51Iil9fSxhZGRUcmFuc2xhdGlvbjpmdW5jdGlvbihiLGUsYyl7dmFyIGQ9dGhpcy5zdHJpbmdzW2JdLGE9ZmFsc2U7aWYoIWQpe2Q9dGhpcy5zdHJpbmdzW2JdPXt9O2E9dHJ1ZX1pZighZC5kb21haW5zKXtkLmRvbWFpbnM9e319aWYoZSl7aWYoIWQuZG9tYWluc1tlXSl7ZC5kb21haW5zW2VdPXt9fWQ9ZC5kb21haW5zW2VdfU1hdGhKYXguSHViLkluc2VydChkLGMpO2lmKGEmJk1hdGhKYXguTWVudS5tZW51KXtNYXRoSmF4Lk1lbnUuQ3JlYXRlTG9jYWxlTWVudSgpfX0sc2V0Q1NTOmZ1bmN0aW9uKGIpe3ZhciBhPXRoaXMuc3RyaW5nc1t0aGlzLmxvY2FsZV07aWYoYSl7aWYoYS5mb250RmFtaWx5KXtiLnN0eWxlLmZvbnRGYW1pbHk9YS5mb250RmFtaWx5fWlmKGEuZm9udERpcmVjdGlvbil7Yi5zdHlsZS5kaXJlY3Rpb249YS5mb250RGlyZWN0aW9uO2lmKGEuZm9udERpcmVjdGlvbj09PSJydGwiKXtiLnN0eWxlLnRleHRBbGlnbj0icmlnaHQifX19cmV0dXJuIGJ9LGZvbnRGYW1pbHk6ZnVuY3Rpb24oKXt2YXIgYT10aGlzLnN0cmluZ3NbdGhpcy5sb2NhbGVdO3JldHVybihhP2EuZm9udEZhbWlseTpudWxsKX0sZm9udERpcmVjdGlvbjpmdW5jdGlvbigpe3ZhciBhPXRoaXMuc3RyaW5nc1t0aGlzLmxvY2FsZV07cmV0dXJuKGE/YS5mb250RGlyZWN0aW9uOm51bGwpfSxwbHVyYWw6ZnVuY3Rpb24oYil7dmFyIGE9dGhpcy5zdHJpbmdzW3RoaXMubG9jYWxlXTtpZihhJiZhLnBsdXJhbCl7cmV0dXJuIGEucGx1cmFsKGIpfWlmKGI9PTEpe3JldHVybiAxfXJldHVybiAyfSxudW1iZXI6ZnVuY3Rpb24oYil7dmFyIGE9dGhpcy5zdHJpbmdzW3RoaXMubG9jYWxlXTtpZihhJiZhLm51bWJlcil7cmV0dXJuIGEubnVtYmVyKGIpfXJldHVybiBifX07TWF0aEpheC5NZXNzYWdlPXtyZWFkeTpmYWxzZSxsb2c6W3t9XSxjdXJyZW50Om51bGwsdGV4dE5vZGVCdWc6KG5hdmlnYXRvci52ZW5kb3I9PT0iQXBwbGUgQ29tcHV0ZXIsIEluYy4iJiZ0eXBlb2YgbmF2aWdhdG9yLnZlbmRvclN1Yj09PSJ1bmRlZmluZWQiKXx8KHdpbmRvdy5oYXNPd25Qcm9wZXJ0eSYmd2luZG93Lmhhc093blByb3BlcnR5KCJrb25xdWVyb3IiKSksc3R5bGVzOnsiI01hdGhKYXhfTWVzc2FnZSI6e3Bvc2l0aW9uOiJmaXhlZCIsbGVmdDoiMXB4Iixib3R0b206IjJweCIsImJhY2tncm91bmQtY29sb3IiOiIjRTZFNkU2Iixib3JkZXI6IjFweCBzb2xpZCAjOTU5NTk1IixtYXJnaW46IjBweCIscGFkZGluZzoiMnB4IDhweCIsInotaW5kZXgiOiIxMDIiLGNvbG9yOiJibGFjayIsImZvbnQtc2l6ZSI6IjgwJSIsd2lkdGg6ImF1dG8iLCJ3aGl0ZS1zcGFjZSI6Im5vd3JhcCJ9LCIjTWF0aEpheF9NU0lFX0ZyYW1lIjp7cG9zaXRpb246ImFic29sdXRlIix0b3A6MCxsZWZ0OjAsd2lkdGg6IjBweCIsInotaW5kZXgiOjEwMSxib3JkZXI6IjBweCIsbWFyZ2luOiIwcHgiLHBhZGRpbmc6IjBweCJ9fSxicm93c2Vyczp7TVNJRTpmdW5jdGlvbihhKXtNYXRoSmF4Lk1lc3NhZ2UubXNpZUZpeGVkUG9zaXRpb25CdWc9KChkb2N1bWVudC5kb2N1bWVudE1vZGV8fDApPDcpO2lmKE1hdGhKYXguTWVzc2FnZS5tc2llRml4ZWRQb3NpdGlvbkJ1Zyl7TWF0aEpheC5IdWIuY29uZmlnLnN0eWxlc1siI01hdGhKYXhfTWVzc2FnZSJdLnBvc2l0aW9uPSJhYnNvbHV0ZSJ9TWF0aEpheC5NZXNzYWdlLnF1aXJrcz0oZG9jdW1lbnQuY29tcGF0TW9kZT09PSJCYWNrQ29tcGF0Iil9LENocm9tZTpmdW5jdGlvbihhKXtNYXRoSmF4Lkh1Yi5jb25maWcuc3R5bGVzWyIjTWF0aEpheF9NZXNzYWdlIl0uYm90dG9tPSIxLjVlbSI7TWF0aEpheC5IdWIuY29uZmlnLnN0eWxlc1siI01hdGhKYXhfTWVzc2FnZSJdLmxlZnQ9IjFlbSJ9fSxJbml0OmZ1bmN0aW9uKGEpe2lmKGEpe3RoaXMucmVhZHk9dHJ1ZX1pZighZG9jdW1lbnQuYm9keXx8IXRoaXMucmVhZHkpe3JldHVybiBmYWxzZX1pZih0aGlzLmRpdiYmdGhpcy5kaXYucGFyZW50Tm9kZT09bnVsbCl7dGhpcy5kaXY9ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoIk1hdGhKYXhfTWVzc2FnZSIpO2lmKHRoaXMuZGl2KXt0aGlzLnRleHQ9dGhpcy5kaXYuZmlyc3RDaGlsZH19aWYoIXRoaXMuZGl2KXt2YXIgYj1kb2N1bWVudC5ib2R5O2lmKHRoaXMubXNpZUZpeGVkUG9zaXRpb25CdWcmJndpbmRvdy5hdHRhY2hFdmVudCl7Yj10aGlzLmZyYW1lPXRoaXMuYWRkRGl2KGRvY3VtZW50LmJvZHkpO2IucmVtb3ZlQXR0cmlidXRlKCJpZCIpO2Iuc3R5bGUucG9zaXRpb249ImFic29sdXRlIjtiLnN0eWxlLmJvcmRlcj1iLnN0eWxlLm1hcmdpbj1iLnN0eWxlLnBhZGRpbmc9IjBweCI7Yi5zdHlsZS56SW5kZXg9IjEwMSI7Yi5zdHlsZS5oZWlnaHQ9IjBweCI7Yj10aGlzLmFkZERpdihiKTtiLmlkPSJNYXRoSmF4X01TSUVfRnJhbWUiO3dpbmRvdy5hdHRhY2hFdmVudCgib25zY3JvbGwiLHRoaXMuTW92ZUZyYW1lKTt3aW5kb3cuYXR0YWNoRXZlbnQoIm9ucmVzaXplIix0aGlzLk1vdmVGcmFtZSk7dGhpcy5Nb3ZlRnJhbWUoKX10aGlzLmRpdj10aGlzLmFkZERpdihiKTt0aGlzLmRpdi5zdHlsZS5kaXNwbGF5PSJub25lIjt0aGlzLnRleHQ9dGhpcy5kaXYuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIiIpKX1yZXR1cm4gdHJ1ZX0sYWRkRGl2OmZ1bmN0aW9uKGEpe3ZhciBiPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpO2IuaWQ9Ik1hdGhKYXhfTWVzc2FnZSI7aWYoYS5maXJzdENoaWxkKXthLmluc2VydEJlZm9yZShiLGEuZmlyc3RDaGlsZCl9ZWxzZXthLmFwcGVuZENoaWxkKGIpfXJldHVybiBifSxNb3ZlRnJhbWU6ZnVuY3Rpb24oKXt2YXIgYT0oTWF0aEpheC5NZXNzYWdlLnF1aXJrcz9kb2N1bWVudC5ib2R5OmRvY3VtZW50LmRvY3VtZW50RWxlbWVudCk7dmFyIGI9TWF0aEpheC5NZXNzYWdlLmZyYW1lO2Iuc3R5bGUubGVmdD1hLnNjcm9sbExlZnQrInB4IjtiLnN0eWxlLnRvcD1hLnNjcm9sbFRvcCsicHgiO2Iuc3R5bGUud2lkdGg9YS5jbGllbnRXaWR0aCsicHgiO2I9Yi5maXJzdENoaWxkO2Iuc3R5bGUuaGVpZ2h0PWEuY2xpZW50SGVpZ2h0KyJweCJ9LGxvY2FsaXplOmZ1bmN0aW9uKGEpe3JldHVybiBNYXRoSmF4LkxvY2FsaXphdGlvbi5fKGEsYSl9LGZpbHRlclRleHQ6ZnVuY3Rpb24oYSxjLGIpe2lmKE1hdGhKYXguSHViLmNvbmZpZy5tZXNzYWdlU3R5bGU9PT0ic2ltcGxlIil7aWYoYj09PSJMb2FkRmlsZSIpe2lmKCF0aGlzLmxvYWRpbmcpe3RoaXMubG9hZGluZz10aGlzLmxvY2FsaXplKCJMb2FkaW5nIikrIiAifWE9dGhpcy5sb2FkaW5nO3RoaXMubG9hZGluZys9Ii4ifWVsc2V7aWYoYj09PSJQcm9jZXNzTWF0aCIpe2lmKCF0aGlzLnByb2Nlc3Npbmcpe3RoaXMucHJvY2Vzc2luZz10aGlzLmxvY2FsaXplKCJQcm9jZXNzaW5nIikrIiAifWE9dGhpcy5wcm9jZXNzaW5nO3RoaXMucHJvY2Vzc2luZys9Ii4ifWVsc2V7aWYoYj09PSJUeXBlc2V0TWF0aCIpe2lmKCF0aGlzLnR5cGVzZXR0aW5nKXt0aGlzLnR5cGVzZXR0aW5nPXRoaXMubG9jYWxpemUoIlR5cGVzZXR0aW5nIikrIiAifWE9dGhpcy50eXBlc2V0dGluZzt0aGlzLnR5cGVzZXR0aW5nKz0iLiJ9fX19cmV0dXJuIGF9LGNsZWFyQ291bnRzOmZ1bmN0aW9uKCl7ZGVsZXRlIHRoaXMubG9hZGluZztkZWxldGUgdGhpcy5wcm9jZXNzaW5nO2RlbGV0ZSB0aGlzLnR5cGVzZXR0aW5nfSxTZXQ6ZnVuY3Rpb24oYyxlLGIpe2lmKGU9PW51bGwpe2U9dGhpcy5sb2cubGVuZ3RoO3RoaXMubG9nW2VdPXt9fXZhciBkPSIiO2lmKE1hdGhKYXguT2JqZWN0LmlzQXJyYXkoYykpe2Q9Y1swXTtpZihNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGQpKXtkPWRbMV19dHJ5e2M9TWF0aEpheC5Mb2NhbGl6YXRpb24uXy5hcHBseShNYXRoSmF4LkxvY2FsaXphdGlvbixjKX1jYXRjaChhKXtpZighYS5yZXN0YXJ0KXt0aHJvdyBhfWlmKCFhLnJlc3RhcnQuY2FsbGVkKXtpZih0aGlzLmxvZ1tlXS5yZXN0YXJ0ZWQ9PW51bGwpe3RoaXMubG9nW2VdLnJlc3RhcnRlZD0wfXRoaXMubG9nW2VdLnJlc3RhcnRlZCsrO2RlbGV0ZSB0aGlzLmxvZ1tlXS5jbGVhcmVkO01hdGhKYXguQ2FsbGJhY2suQWZ0ZXIoWyJTZXQiLHRoaXMsYyxlLGJdLGEucmVzdGFydCk7cmV0dXJuIGV9fX1pZih0aGlzLnRpbWVyKXtjbGVhclRpbWVvdXQodGhpcy50aW1lcik7ZGVsZXRlIHRoaXMudGltZXJ9dGhpcy5sb2dbZV0udGV4dD1jO3RoaXMubG9nW2VdLmZpbHRlcmVkVGV4dD1jPXRoaXMuZmlsdGVyVGV4dChjLGUsZCk7aWYodHlwZW9mKHRoaXMubG9nW2VdLm5leHQpPT09InVuZGVmaW5lZCIpe3RoaXMubG9nW2VdLm5leHQ9dGhpcy5jdXJyZW50O2lmKHRoaXMuY3VycmVudCE9bnVsbCl7dGhpcy5sb2dbdGhpcy5jdXJyZW50XS5wcmV2PWV9dGhpcy5jdXJyZW50PWV9aWYodGhpcy5jdXJyZW50PT09ZSYmTWF0aEpheC5IdWIuY29uZmlnLm1lc3NhZ2VTdHlsZSE9PSJub25lIil7aWYodGhpcy5Jbml0KCkpe2lmKHRoaXMudGV4dE5vZGVCdWcpe3RoaXMuZGl2LmlubmVySFRNTD1jfWVsc2V7dGhpcy50ZXh0Lm5vZGVWYWx1ZT1jfXRoaXMuZGl2LnN0eWxlLmRpc3BsYXk9IiI7aWYodGhpcy5zdGF0dXMpe3dpbmRvdy5zdGF0dXM9IiI7ZGVsZXRlIHRoaXMuc3RhdHVzfX1lbHNle3dpbmRvdy5zdGF0dXM9Yzt0aGlzLnN0YXR1cz10cnVlfX1pZih0aGlzLmxvZ1tlXS5yZXN0YXJ0ZWQpe2lmKHRoaXMubG9nW2VdLmNsZWFyZWQpe2I9MH1pZigtLXRoaXMubG9nW2VdLnJlc3RhcnRlZD09PTApe2RlbGV0ZSB0aGlzLmxvZ1tlXS5jbGVhcmVkfX1pZihiKXtzZXRUaW1lb3V0KE1hdGhKYXguQ2FsbGJhY2soWyJDbGVhciIsdGhpcyxlXSksYil9ZWxzZXtpZihiPT0wKXt0aGlzLkNsZWFyKGUsMCl9fXJldHVybiBlfSxDbGVhcjpmdW5jdGlvbihiLGEpe2lmKHRoaXMubG9nW2JdLnByZXYhPW51bGwpe3RoaXMubG9nW3RoaXMubG9nW2JdLnByZXZdLm5leHQ9dGhpcy5sb2dbYl0ubmV4dH1pZih0aGlzLmxvZ1tiXS5uZXh0IT1udWxsKXt0aGlzLmxvZ1t0aGlzLmxvZ1tiXS5uZXh0XS5wcmV2PXRoaXMubG9nW2JdLnByZXZ9aWYodGhpcy5jdXJyZW50PT09Yil7dGhpcy5jdXJyZW50PXRoaXMubG9nW2JdLm5leHQ7aWYodGhpcy50ZXh0KXtpZih0aGlzLmRpdi5wYXJlbnROb2RlPT1udWxsKXt0aGlzLkluaXQoKX1pZih0aGlzLmN1cnJlbnQ9PW51bGwpe2lmKHRoaXMudGltZXIpe2NsZWFyVGltZW91dCh0aGlzLnRpbWVyKTtkZWxldGUgdGhpcy50aW1lcn1pZihhPT1udWxsKXthPTYwMH1pZihhPT09MCl7dGhpcy5SZW1vdmUoKX1lbHNle3RoaXMudGltZXI9c2V0VGltZW91dChNYXRoSmF4LkNhbGxiYWNrKFsiUmVtb3ZlIix0aGlzXSksYSl9fWVsc2V7aWYoTWF0aEpheC5IdWIuY29uZmlnLm1lc3NhZ2VTdHlsZSE9PSJub25lIil7aWYodGhpcy50ZXh0Tm9kZUJ1Zyl7dGhpcy5kaXYuaW5uZXJIVE1MPXRoaXMubG9nW3RoaXMuY3VycmVudF0uZmlsdGVyZWRUZXh0fWVsc2V7dGhpcy50ZXh0Lm5vZGVWYWx1ZT10aGlzLmxvZ1t0aGlzLmN1cnJlbnRdLmZpbHRlcmVkVGV4dH19fWlmKHRoaXMuc3RhdHVzKXt3aW5kb3cuc3RhdHVzPSIiO2RlbGV0ZSB0aGlzLnN0YXR1c319ZWxzZXtpZih0aGlzLnN0YXR1cyl7d2luZG93LnN0YXR1cz0odGhpcy5jdXJyZW50PT1udWxsPyIiOnRoaXMubG9nW3RoaXMuY3VycmVudF0udGV4dCl9fX1kZWxldGUgdGhpcy5sb2dbYl0ubmV4dDtkZWxldGUgdGhpcy5sb2dbYl0ucHJldjtkZWxldGUgdGhpcy5sb2dbYl0uZmlsdGVyZWRUZXh0O2lmKHRoaXMubG9nW2JdLnJlc3RhcnRlZCl7dGhpcy5sb2dbYl0uY2xlYXJlZD10cnVlfX0sUmVtb3ZlOmZ1bmN0aW9uKCl7dGhpcy50ZXh0Lm5vZGVWYWx1ZT0iIjt0aGlzLmRpdi5zdHlsZS5kaXNwbGF5PSJub25lIn0sRmlsZTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5TZXQoWyJMb2FkRmlsZSIsIkxvYWRpbmcgJTEiLGFdLG51bGwsbnVsbCl9LExvZzpmdW5jdGlvbigpe3ZhciBiPVtdO2Zvcih2YXIgYz0xLGE9dGhpcy5sb2cubGVuZ3RoO2M8YTtjKyspe2JbY109dGhpcy5sb2dbY10udGV4dH1yZXR1cm4gYi5qb2luKCJcbiIpfX07TWF0aEpheC5IdWI9e2NvbmZpZzp7cm9vdDoiIixjb25maWc6W10sc3R5bGVTaGVldHM6W10sc3R5bGVzOnsiLk1hdGhKYXhfUHJldmlldyI6e2NvbG9yOiIjODg4In19LGpheDpbXSxleHRlbnNpb25zOltdLHByZUpheDpudWxsLHBvc3RKYXg6bnVsbCxkaXNwbGF5QWxpZ246ImNlbnRlciIsZGlzcGxheUluZGVudDoiMCIscHJlUmVtb3ZlQ2xhc3M6Ik1hdGhKYXhfUHJldmlldyIsc2hvd1Byb2Nlc3NpbmdNZXNzYWdlczp0cnVlLG1lc3NhZ2VTdHlsZToibm9ybWFsIixkZWxheVN0YXJ0dXBVbnRpbDoibm9uZSIsc2tpcFN0YXJ0dXBUeXBlc2V0OmZhbHNlLGVsZW1lbnRzOltdLHBvc2l0aW9uVG9IYXNoOnRydWUsc2hvd01hdGhNZW51OnRydWUsc2hvd01hdGhNZW51TVNJRTp0cnVlLG1lbnVTZXR0aW5nczp7em9vbToiTm9uZSIsQ1RSTDpmYWxzZSxBTFQ6ZmFsc2UsQ01EOmZhbHNlLFNoaWZ0OmZhbHNlLGRpc2NvdmVyYWJsZTpmYWxzZSx6c2NhbGU6IjIwMCUiLHJlbmRlcmVyOm51bGwsZm9udDoiQXV0byIsY29udGV4dDoiTWF0aEpheCIsbG9jYWxlOm51bGwsbXBDb250ZXh0OmZhbHNlLG1wTW91c2U6ZmFsc2UsdGV4SGludHM6dHJ1ZSxGYXN0UHJldmlldzpudWxsLGFzc2lzdGl2ZU1NTDpudWxsLGluVGFiT3JkZXI6dHJ1ZSxzZW1hbnRpY3M6ZmFsc2V9LGVycm9yU2V0dGluZ3M6e21lc3NhZ2U6WyJbIixbIk1hdGhQcm9jZXNzaW5nRXJyb3IiLCJNYXRoIFByb2Nlc3NpbmcgRXJyb3IiXSwiXSJdLHN0eWxlOntjb2xvcjoiI0NDMDAwMCIsImZvbnQtc3R5bGUiOiJpdGFsaWMifX0saWdub3JlTU1MYXR0cmlidXRlczp7fX0scHJlUHJvY2Vzc29yczpNYXRoSmF4LkNhbGxiYWNrLkhvb2tzKHRydWUpLGlucHV0SmF4Ont9LG91dHB1dEpheDp7b3JkZXI6e319LHByb2Nlc3NTZWN0aW9uRGVsYXk6NTAscHJvY2Vzc1VwZGF0ZVRpbWU6MjUwLHByb2Nlc3NVcGRhdGVEZWxheToxMCxzaWduYWw6TWF0aEpheC5DYWxsYmFjay5TaWduYWwoIkh1YiIpLENvbmZpZzpmdW5jdGlvbihhKXt0aGlzLkluc2VydCh0aGlzLmNvbmZpZyxhKTtpZih0aGlzLmNvbmZpZy5BdWdtZW50KXt0aGlzLkF1Z21lbnQodGhpcy5jb25maWcuQXVnbWVudCl9fSxDb21iaW5lQ29uZmlnOmZ1bmN0aW9uKGMsZil7dmFyIGI9dGhpcy5jb25maWcsZyxlO2M9Yy5zcGxpdCgvXC4vKTtmb3IodmFyIGQ9MCxhPWMubGVuZ3RoO2Q8YTtkKyspe2c9Y1tkXTtpZighYltnXSl7YltnXT17fX1lPWI7Yj1iW2ddfWVbZ109Yj10aGlzLkluc2VydChmLGIpO3JldHVybiBifSxSZWdpc3Rlcjp7UHJlUHJvY2Vzc29yOmZ1bmN0aW9uKCl7cmV0dXJuIE1hdGhKYXguSHViLnByZVByb2Nlc3NvcnMuQWRkLmFwcGx5KE1hdGhKYXguSHViLnByZVByb2Nlc3NvcnMsYXJndW1lbnRzKX0sTWVzc2FnZUhvb2s6ZnVuY3Rpb24oKXtyZXR1cm4gTWF0aEpheC5IdWIuc2lnbmFsLk1lc3NhZ2VIb29rLmFwcGx5KE1hdGhKYXguSHViLnNpZ25hbCxhcmd1bWVudHMpfSxTdGFydHVwSG9vazpmdW5jdGlvbigpe3JldHVybiBNYXRoSmF4Lkh1Yi5TdGFydHVwLnNpZ25hbC5NZXNzYWdlSG9vay5hcHBseShNYXRoSmF4Lkh1Yi5TdGFydHVwLnNpZ25hbCxhcmd1bWVudHMpfSxMb2FkSG9vazpmdW5jdGlvbigpe3JldHVybiBNYXRoSmF4LkFqYXguTG9hZEhvb2suYXBwbHkoTWF0aEpheC5BamF4LGFyZ3VtZW50cyl9fSxVblJlZ2lzdGVyOntQcmVQcm9jZXNzb3I6ZnVuY3Rpb24oYSl7TWF0aEpheC5IdWIucHJlUHJvY2Vzc29ycy5SZW1vdmUoYSl9LE1lc3NhZ2VIb29rOmZ1bmN0aW9uKGEpe01hdGhKYXguSHViLnNpZ25hbC5SZW1vdmVIb29rKGEpfSxTdGFydHVwSG9vazpmdW5jdGlvbihhKXtNYXRoSmF4Lkh1Yi5TdGFydHVwLnNpZ25hbC5SZW1vdmVIb29rKGEpfSxMb2FkSG9vazpmdW5jdGlvbihhKXtNYXRoSmF4LkFqYXgucmVtb3ZlSG9vayhhKX19LGdldEFsbEpheDpmdW5jdGlvbihlKXt2YXIgYz1bXSxiPXRoaXMuZWxlbWVudFNjcmlwdHMoZSk7Zm9yKHZhciBkPTAsYT1iLmxlbmd0aDtkPGE7ZCsrKXtpZihiW2RdLk1hdGhKYXgmJmJbZF0uTWF0aEpheC5lbGVtZW50SmF4KXtjLnB1c2goYltkXS5NYXRoSmF4LmVsZW1lbnRKYXgpfX1yZXR1cm4gY30sZ2V0SmF4QnlUeXBlOmZ1bmN0aW9uKGYsZSl7dmFyIGM9W10sYj10aGlzLmVsZW1lbnRTY3JpcHRzKGUpO2Zvcih2YXIgZD0wLGE9Yi5sZW5ndGg7ZDxhO2QrKyl7aWYoYltkXS5NYXRoSmF4JiZiW2RdLk1hdGhKYXguZWxlbWVudEpheCYmYltkXS5NYXRoSmF4LmVsZW1lbnRKYXgubWltZVR5cGU9PT1mKXtjLnB1c2goYltkXS5NYXRoSmF4LmVsZW1lbnRKYXgpfX1yZXR1cm4gY30sZ2V0SmF4QnlJbnB1dFR5cGU6ZnVuY3Rpb24oZixlKXt2YXIgYz1bXSxiPXRoaXMuZWxlbWVudFNjcmlwdHMoZSk7Zm9yKHZhciBkPTAsYT1iLmxlbmd0aDtkPGE7ZCsrKXtpZihiW2RdLk1hdGhKYXgmJmJbZF0uTWF0aEpheC5lbGVtZW50SmF4JiZiW2RdLnR5cGUmJmJbZF0udHlwZS5yZXBsYWNlKC8gKjsoLnxccykqLywiIik9PT1mKXtjLnB1c2goYltkXS5NYXRoSmF4LmVsZW1lbnRKYXgpfX1yZXR1cm4gY30sZ2V0SmF4Rm9yOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZihhKT09PSJzdHJpbmciKXthPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGEpfWlmKGEmJmEuTWF0aEpheCl7cmV0dXJuIGEuTWF0aEpheC5lbGVtZW50SmF4fWlmKHRoaXMuaXNNYXRoSmF4Tm9kZShhKSl7aWYoIWEuaXNNYXRoSmF4KXthPWEuZmlyc3RDaGlsZH13aGlsZShhJiYhYS5qYXhJRCl7YT1hLnBhcmVudE5vZGV9aWYoYSl7cmV0dXJuIE1hdGhKYXguT3V0cHV0SmF4W2EuamF4SURdLmdldEpheEZyb21NYXRoKGEpfX1yZXR1cm4gbnVsbH0saXNKYXg6ZnVuY3Rpb24oYSl7aWYodHlwZW9mKGEpPT09InN0cmluZyIpe2E9ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoYSl9aWYodGhpcy5pc01hdGhKYXhOb2RlKGEpKXtyZXR1cm4gMX1pZihhJiYoYS50YWdOYW1lfHwiIikudG9Mb3dlckNhc2UoKT09PSJzY3JpcHQiKXtpZihhLk1hdGhKYXgpe3JldHVybihhLk1hdGhKYXguc3RhdGU9PT1NYXRoSmF4LkVsZW1lbnRKYXguU1RBVEUuUFJPQ0VTU0VEPzE6LTEpfWlmKGEudHlwZSYmdGhpcy5pbnB1dEpheFthLnR5cGUucmVwbGFjZSgvICo7KC58XHMpKi8sIiIpXSl7cmV0dXJuIC0xfX1yZXR1cm4gMH0saXNNYXRoSmF4Tm9kZTpmdW5jdGlvbihhKXtyZXR1cm4gISFhJiYoYS5pc01hdGhKYXh8fChhLmNsYXNzTmFtZXx8IiIpPT09Ik1hdGhKYXhfTWF0aE1MIil9LHNldFJlbmRlcmVyOmZ1bmN0aW9uKGQsYyl7aWYoIWQpe3JldHVybn1pZighTWF0aEpheC5PdXRwdXRKYXhbZF0pe3RoaXMuY29uZmlnLm1lbnVTZXR0aW5ncy5yZW5kZXJlcj0iIjt2YXIgYj0iW01hdGhKYXhdL2pheC9vdXRwdXQvIitkKyIvY29uZmlnLmpzIjtyZXR1cm4gTWF0aEpheC5BamF4LlJlcXVpcmUoYixbInNldFJlbmRlcmVyIix0aGlzLGQsY10pfWVsc2V7dGhpcy5jb25maWcubWVudVNldHRpbmdzLnJlbmRlcmVyPWQ7aWYoYz09bnVsbCl7Yz0iamF4L21tbCJ9dmFyIGE9dGhpcy5vdXRwdXRKYXg7aWYoYVtjXSYmYVtjXS5sZW5ndGgpe2lmKGQhPT1hW2NdWzBdLmlkKXthW2NdLnVuc2hpZnQoTWF0aEpheC5PdXRwdXRKYXhbZF0pO3JldHVybiB0aGlzLnNpZ25hbC5Qb3N0KFsiUmVuZGVyZXIgU2VsZWN0ZWQiLGRdKX19cmV0dXJuIG51bGx9fSxRdWV1ZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLnF1ZXVlLlB1c2guYXBwbHkodGhpcy5xdWV1ZSxhcmd1bWVudHMpfSxUeXBlc2V0OmZ1bmN0aW9uKGMsZCl7aWYoIU1hdGhKYXguaXNSZWFkeSl7cmV0dXJuIG51bGx9dmFyIGI9dGhpcy5lbGVtZW50Q2FsbGJhY2soYyxkKTtpZihiLmNvdW50KXt2YXIgYT1NYXRoSmF4LkNhbGxiYWNrLlF1ZXVlKFsiUHJlUHJvY2VzcyIsdGhpcyxiLmVsZW1lbnRzXSxbIlByb2Nlc3MiLHRoaXMsYi5lbGVtZW50c10pfXJldHVybiBhLlB1c2goYi5jYWxsYmFjayl9LFByZVByb2Nlc3M6ZnVuY3Rpb24oZSxnKXt2YXIgYz10aGlzLmVsZW1lbnRDYWxsYmFjayhlLGcpO3ZhciBiPU1hdGhKYXguQ2FsbGJhY2suUXVldWUoKTtpZihjLmNvdW50KXt2YXIgZj0oYy5jb3VudD09PTE/W2MuZWxlbWVudHNdOmMuZWxlbWVudHMpO2IuUHVzaChbIlBvc3QiLHRoaXMuc2lnbmFsLFsiQmVnaW4gUHJlUHJvY2VzcyIsYy5lbGVtZW50c11dKTtmb3IodmFyIGQ9MCxhPWYubGVuZ3RoO2Q8YTtkKyspe2lmKGZbZF0pe2IuUHVzaChbIkV4ZWN1dGUiLHRoaXMucHJlUHJvY2Vzc29ycyxmW2RdXSl9fWIuUHVzaChbIlBvc3QiLHRoaXMuc2lnbmFsLFsiRW5kIFByZVByb2Nlc3MiLGMuZWxlbWVudHNdXSl9cmV0dXJuIGIuUHVzaChjLmNhbGxiYWNrKX0sUHJvY2VzczpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLnRha2VBY3Rpb24oIlByb2Nlc3MiLGEsYil9LFVwZGF0ZTpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLnRha2VBY3Rpb24oIlVwZGF0ZSIsYSxiKX0sUmVwcm9jZXNzOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMudGFrZUFjdGlvbigiUmVwcm9jZXNzIixhLGIpfSxSZXJlbmRlcjpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLnRha2VBY3Rpb24oIlJlcmVuZGVyIixhLGIpfSx0YWtlQWN0aW9uOmZ1bmN0aW9uKGcsZCxoKXt2YXIgYz10aGlzLmVsZW1lbnRDYWxsYmFjayhkLGgpO3ZhciBmPWMuZWxlbWVudHM7dmFyIGE9TWF0aEpheC5DYWxsYmFjay5RdWV1ZShbIkNsZWFyIix0aGlzLnNpZ25hbF0pO3ZhciBlPXtzY3JpcHRzOltdLHN0YXJ0Om5ldyBEYXRlKCkuZ2V0VGltZSgpLGk6MCxqOjAsamF4Ont9LGpheElEczpbXX07aWYoYy5jb3VudCl7dmFyIGI9WyJEZWxheSIsTWF0aEpheC5DYWxsYmFjayx0aGlzLnByb2Nlc3NTZWN0aW9uRGVsYXldO2lmKCFiWzJdKXtiPXt9fWEuUHVzaChbImNsZWFyQ291bnRzIixNYXRoSmF4Lk1lc3NhZ2VdLFsiUG9zdCIsdGhpcy5zaWduYWwsWyJCZWdpbiAiK2csZl1dLFsiUG9zdCIsdGhpcy5zaWduYWwsWyJCZWdpbiBNYXRoIixmLGddXSxbInByZXBhcmVTY3JpcHRzIix0aGlzLGcsZixlXSxbIlBvc3QiLHRoaXMuc2lnbmFsLFsiQmVnaW4gTWF0aCBJbnB1dCIsZixnXV0sWyJwcm9jZXNzSW5wdXQiLHRoaXMsZV0sWyJQb3N0Iix0aGlzLnNpZ25hbCxbIkVuZCBNYXRoIElucHV0IixmLGddXSxiLFsicHJlcGFyZU91dHB1dCIsdGhpcyxlLCJwcmVQcm9jZXNzIl0sYixbIlBvc3QiLHRoaXMuc2lnbmFsLFsiQmVnaW4gTWF0aCBPdXRwdXQiLGYsZ11dLFsicHJvY2Vzc091dHB1dCIsdGhpcyxlXSxbIlBvc3QiLHRoaXMuc2lnbmFsLFsiRW5kIE1hdGggT3V0cHV0IixmLGddXSxiLFsicHJlcGFyZU91dHB1dCIsdGhpcyxlLCJwb3N0UHJvY2VzcyJdLGIsWyJQb3N0Iix0aGlzLnNpZ25hbCxbIkVuZCBNYXRoIixmLGddXSxbIlBvc3QiLHRoaXMuc2lnbmFsLFsiRW5kICIrZyxmXV0sWyJjbGVhckNvdW50cyIsTWF0aEpheC5NZXNzYWdlXSl9cmV0dXJuIGEuUHVzaChjLmNhbGxiYWNrKX0sc2NyaXB0QWN0aW9uOntQcm9jZXNzOmZ1bmN0aW9uKGEpe30sVXBkYXRlOmZ1bmN0aW9uKGIpe3ZhciBhPWIuTWF0aEpheC5lbGVtZW50SmF4O2lmKGEmJmEubmVlZHNVcGRhdGUoKSl7YS5SZW1vdmUodHJ1ZSk7Yi5NYXRoSmF4LnN0YXRlPWEuU1RBVEUuVVBEQVRFfWVsc2V7Yi5NYXRoSmF4LnN0YXRlPWEuU1RBVEUuUFJPQ0VTU0VEfX0sUmVwcm9jZXNzOmZ1bmN0aW9uKGIpe3ZhciBhPWIuTWF0aEpheC5lbGVtZW50SmF4O2lmKGEpe2EuUmVtb3ZlKHRydWUpO2IuTWF0aEpheC5zdGF0ZT1hLlNUQVRFLlVQREFURX19LFJlcmVuZGVyOmZ1bmN0aW9uKGIpe3ZhciBhPWIuTWF0aEpheC5lbGVtZW50SmF4O2lmKGEpe2EuUmVtb3ZlKHRydWUpO2IuTWF0aEpheC5zdGF0ZT1hLlNUQVRFLk9VVFBVVH19fSxwcmVwYXJlU2NyaXB0czpmdW5jdGlvbihoLGUsZyl7aWYoYXJndW1lbnRzLmNhbGxlZS5kaXNhYmxlZCl7cmV0dXJufXZhciBiPXRoaXMuZWxlbWVudFNjcmlwdHMoZSk7dmFyIGY9TWF0aEpheC5FbGVtZW50SmF4LlNUQVRFO2Zvcih2YXIgZD0wLGE9Yi5sZW5ndGg7ZDxhO2QrKyl7dmFyIGM9YltkXTtpZihjLnR5cGUmJnRoaXMuaW5wdXRKYXhbYy50eXBlLnJlcGxhY2UoLyAqOygufFxuKSovLCIiKV0pe2lmKGMuTWF0aEpheCl7aWYoYy5NYXRoSmF4LmVsZW1lbnRKYXgmJmMuTWF0aEpheC5lbGVtZW50SmF4LmhvdmVyKXtNYXRoSmF4LkV4dGVuc2lvbi5NYXRoRXZlbnRzLkhvdmVyLkNsZWFySG92ZXIoYy5NYXRoSmF4LmVsZW1lbnRKYXgpfWlmKGMuTWF0aEpheC5zdGF0ZSE9PWYuUEVORElORyl7dGhpcy5zY3JpcHRBY3Rpb25baF0oYyl9fWlmKCFjLk1hdGhKYXgpe2MuTWF0aEpheD17c3RhdGU6Zi5QRU5ESU5HfX1pZihjLk1hdGhKYXguZXJyb3Ipe2RlbGV0ZSBjLk1hdGhKYXguZXJyb3J9aWYoYy5NYXRoSmF4LnN0YXRlIT09Zi5QUk9DRVNTRUQpe2cuc2NyaXB0cy5wdXNoKGMpfX19fSxjaGVja1NjcmlwdFNpYmxpbmdzOmZ1bmN0aW9uKGEpe2lmKGEuTWF0aEpheC5jaGVja2VkKXtyZXR1cm59dmFyIGI9dGhpcy5jb25maWcsZj1hLnByZXZpb3VzU2libGluZztpZihmJiZmLm5vZGVOYW1lPT09IiN0ZXh0Iil7dmFyIGQsZSxjPWEubmV4dFNpYmxpbmc7aWYoYyYmYy5ub2RlTmFtZSE9PSIjdGV4dCIpe2M9bnVsbH1pZihiLnByZUpheCl7aWYodHlwZW9mKGIucHJlSmF4KT09PSJzdHJpbmciKXtiLnByZUpheD1uZXcgUmVnRXhwKGIucHJlSmF4KyIkIil9ZD1mLm5vZGVWYWx1ZS5tYXRjaChiLnByZUpheCl9aWYoYi5wb3N0SmF4JiZjKXtpZih0eXBlb2YoYi5wb3N0SmF4KT09PSJzdHJpbmciKXtiLnBvc3RKYXg9bmV3IFJlZ0V4cCgiXiIrYi5wb3N0SmF4KX1lPWMubm9kZVZhbHVlLm1hdGNoKGIucG9zdEpheCl9aWYoZCYmKCFiLnBvc3RKYXh8fGUpKXtmLm5vZGVWYWx1ZT1mLm5vZGVWYWx1ZS5yZXBsYWNlKGIucHJlSmF4LChkLmxlbmd0aD4xP2RbMV06IiIpKTtmPW51bGx9aWYoZSYmKCFiLnByZUpheHx8ZCkpe2Mubm9kZVZhbHVlPWMubm9kZVZhbHVlLnJlcGxhY2UoYi5wb3N0SmF4LChlLmxlbmd0aD4xP2VbMV06IiIpKX1pZihmJiYhZi5ub2RlVmFsdWUubWF0Y2goL1xTLykpe2Y9Zi5wcmV2aW91c1NpYmxpbmd9fWlmKGIucHJlUmVtb3ZlQ2xhc3MmJmYmJmYuY2xhc3NOYW1lPT09Yi5wcmVSZW1vdmVDbGFzcyl7YS5NYXRoSmF4LnByZXZpZXc9Zn1hLk1hdGhKYXguY2hlY2tlZD0xfSxwcm9jZXNzSW5wdXQ6ZnVuY3Rpb24oYSl7dmFyIGIsaT1NYXRoSmF4LkVsZW1lbnRKYXguU1RBVEU7dmFyIGgsZSxkPWEuc2NyaXB0cy5sZW5ndGg7dHJ5e3doaWxlKGEuaTxkKXtoPWEuc2NyaXB0c1thLmldO2lmKCFoKXthLmkrKztjb250aW51ZX1lPWgucHJldmlvdXNTaWJsaW5nO2lmKGUmJmUuY2xhc3NOYW1lPT09Ik1hdGhKYXhfRXJyb3IiKXtlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZSl9aWYoIWgucGFyZW50Tm9kZXx8IWguTWF0aEpheHx8aC5NYXRoSmF4LnN0YXRlPT09aS5QUk9DRVNTRUQpe2EuaSsrO2NvbnRpbnVlfWlmKCFoLk1hdGhKYXguZWxlbWVudEpheHx8aC5NYXRoSmF4LnN0YXRlPT09aS5VUERBVEUpe3RoaXMuY2hlY2tTY3JpcHRTaWJsaW5ncyhoKTt2YXIgZz1oLnR5cGUucmVwbGFjZSgvICo7KC58XHMpKi8sIiIpO3ZhciBqPXRoaXMuaW5wdXRKYXhbZ107Yj1qLlByb2Nlc3MoaCxhKTtpZih0eXBlb2YgYj09PSJmdW5jdGlvbiIpe2lmKGIuY2FsbGVkKXtjb250aW51ZX10aGlzLlJlc3RhcnRBZnRlcihiKX1iPWIuQXR0YWNoKGgsai5pZCk7dGhpcy5zYXZlU2NyaXB0KGIsYSxoLGkpO3RoaXMucG9zdElucHV0SG9va3MuRXhlY3V0ZShiLGouaWQsaCl9ZWxzZXtpZihoLk1hdGhKYXguc3RhdGU9PT1pLk9VVFBVVCl7dGhpcy5zYXZlU2NyaXB0KGguTWF0aEpheC5lbGVtZW50SmF4LGEsaCxpKX19YS5pKys7dmFyIGM9bmV3IERhdGUoKS5nZXRUaW1lKCk7aWYoYy1hLnN0YXJ0PnRoaXMucHJvY2Vzc1VwZGF0ZVRpbWUmJmEuaTxhLnNjcmlwdHMubGVuZ3RoKXthLnN0YXJ0PWM7dGhpcy5SZXN0YXJ0QWZ0ZXIoTWF0aEpheC5DYWxsYmFjay5EZWxheSgxKSl9fX1jYXRjaChmKXtyZXR1cm4gdGhpcy5wcm9jZXNzRXJyb3IoZixhLCJJbnB1dCIpfWlmKGEuc2NyaXB0cy5sZW5ndGgmJnRoaXMuY29uZmlnLnNob3dQcm9jZXNzaW5nTWVzc2FnZXMpe01hdGhKYXguTWVzc2FnZS5TZXQoWyJQcm9jZXNzTWF0aCIsIlByb2Nlc3NpbmcgbWF0aDogJTElJSIsMTAwXSwwKX1hLnN0YXJ0PW5ldyBEYXRlKCkuZ2V0VGltZSgpO2EuaT1hLmo9MDtyZXR1cm4gbnVsbH0scG9zdElucHV0SG9va3M6TWF0aEpheC5DYWxsYmFjay5Ib29rcyh0cnVlKSxzYXZlU2NyaXB0OmZ1bmN0aW9uKGEsZCxiLGMpe2lmKCF0aGlzLm91dHB1dEpheFthLm1pbWVUeXBlXSl7Yi5NYXRoSmF4LnN0YXRlPWMuVVBEQVRFO3Rocm93IEVycm9yKCJObyBvdXRwdXQgamF4IHJlZ2lzdGVyZWQgZm9yICIrYS5taW1lVHlwZSl9YS5vdXRwdXRKYXg9dGhpcy5vdXRwdXRKYXhbYS5taW1lVHlwZV1bMF0uaWQ7aWYoIWQuamF4W2Eub3V0cHV0SmF4XSl7aWYoZC5qYXhJRHMubGVuZ3RoPT09MCl7ZC5qYXhbYS5vdXRwdXRKYXhdPWQuc2NyaXB0c31lbHNle2lmKGQuamF4SURzLmxlbmd0aD09PTEpe2QuamF4W2QuamF4SURzWzBdXT1kLnNjcmlwdHMuc2xpY2UoMCxkLmkpfWQuamF4W2Eub3V0cHV0SmF4XT1bXX1kLmpheElEcy5wdXNoKGEub3V0cHV0SmF4KX1pZihkLmpheElEcy5sZW5ndGg+MSl7ZC5qYXhbYS5vdXRwdXRKYXhdLnB1c2goYil9Yi5NYXRoSmF4LnN0YXRlPWMuT1VUUFVUfSxwcmVwYXJlT3V0cHV0OmZ1bmN0aW9uKGMsZil7d2hpbGUoYy5qPGMuamF4SURzLmxlbmd0aCl7dmFyIGU9Yy5qYXhJRHNbYy5qXSxkPU1hdGhKYXguT3V0cHV0SmF4W2VdO2lmKGRbZl0pe3RyeXt2YXIgYT1kW2ZdKGMpO2lmKHR5cGVvZiBhPT09ImZ1bmN0aW9uIil7aWYoYS5jYWxsZWQpe2NvbnRpbnVlfXRoaXMuUmVzdGFydEFmdGVyKGEpfX1jYXRjaChiKXtpZighYi5yZXN0YXJ0KXtNYXRoSmF4Lk1lc3NhZ2UuU2V0KFsiUHJlcEVycm9yIiwiRXJyb3IgcHJlcGFyaW5nICUxIG91dHB1dCAoJTIpIixlLGZdLG51bGwsNjAwKTtNYXRoSmF4Lkh1Yi5sYXN0UHJlcEVycm9yPWI7Yy5qKyt9cmV0dXJuIE1hdGhKYXguQ2FsbGJhY2suQWZ0ZXIoWyJwcmVwYXJlT3V0cHV0Iix0aGlzLGMsZl0sYi5yZXN0YXJ0KX19Yy5qKyt9cmV0dXJuIG51bGx9LHByb2Nlc3NPdXRwdXQ6ZnVuY3Rpb24oaCl7dmFyIGIsZz1NYXRoSmF4LkVsZW1lbnRKYXguU1RBVEUsZCxhPWguc2NyaXB0cy5sZW5ndGg7dHJ5e3doaWxlKGguaTxhKXtkPWguc2NyaXB0c1toLmldO2lmKCFkfHwhZC5wYXJlbnROb2RlfHwhZC5NYXRoSmF4fHxkLk1hdGhKYXguZXJyb3Ipe2guaSsrO2NvbnRpbnVlfXZhciBjPWQuTWF0aEpheC5lbGVtZW50SmF4O2lmKCFjKXtoLmkrKztjb250aW51ZX1iPU1hdGhKYXguT3V0cHV0SmF4W2Mub3V0cHV0SmF4XS5Qcm9jZXNzKGQsaCk7aWYoYiE9PWZhbHNlKXtkLk1hdGhKYXguc3RhdGU9Zy5QUk9DRVNTRUQ7aWYoZC5NYXRoSmF4LnByZXZpZXcpe2QuTWF0aEpheC5wcmV2aWV3LmlubmVySFRNTD0iIjtkLk1hdGhKYXgucHJldmlldy5zdHlsZS5kaXNwbGF5PSJub25lIn10aGlzLnNpZ25hbC5Qb3N0KFsiTmV3IE1hdGgiLGMuaW5wdXRJRF0pfWguaSsrO3ZhciBlPW5ldyBEYXRlKCkuZ2V0VGltZSgpO2lmKGUtaC5zdGFydD50aGlzLnByb2Nlc3NVcGRhdGVUaW1lJiZoLmk8aC5zY3JpcHRzLmxlbmd0aCl7aC5zdGFydD1lO3RoaXMuUmVzdGFydEFmdGVyKE1hdGhKYXguQ2FsbGJhY2suRGVsYXkodGhpcy5wcm9jZXNzVXBkYXRlRGVsYXkpKX19fWNhdGNoKGYpe3JldHVybiB0aGlzLnByb2Nlc3NFcnJvcihmLGgsIk91dHB1dCIpfWlmKGguc2NyaXB0cy5sZW5ndGgmJnRoaXMuY29uZmlnLnNob3dQcm9jZXNzaW5nTWVzc2FnZXMpe01hdGhKYXguTWVzc2FnZS5TZXQoWyJUeXBlc2V0TWF0aCIsIlR5cGVzZXR0aW5nIG1hdGg6ICUxJSUiLDEwMF0sMCk7TWF0aEpheC5NZXNzYWdlLkNsZWFyKDApfWguaT1oLmo9MDtyZXR1cm4gbnVsbH0scHJvY2Vzc01lc3NhZ2U6ZnVuY3Rpb24oZCxiKXt2YXIgYT1NYXRoLmZsb29yKGQuaS8oZC5zY3JpcHRzLmxlbmd0aCkqMTAwKTt2YXIgYz0oYj09PSJPdXRwdXQiP1siVHlwZXNldE1hdGgiLCJUeXBlc2V0dGluZyBtYXRoOiAlMSUlIl06WyJQcm9jZXNzTWF0aCIsIlByb2Nlc3NpbmcgbWF0aDogJTElJSJdKTtpZih0aGlzLmNvbmZpZy5zaG93UHJvY2Vzc2luZ01lc3NhZ2VzKXtNYXRoSmF4Lk1lc3NhZ2UuU2V0KGMuY29uY2F0KGEpLDApfX0scHJvY2Vzc0Vycm9yOmZ1bmN0aW9uKGIsYyxhKXtpZighYi5yZXN0YXJ0KXtpZighdGhpcy5jb25maWcuZXJyb3JTZXR0aW5ncy5tZXNzYWdlKXt0aHJvdyBifXRoaXMuZm9ybWF0RXJyb3IoYy5zY3JpcHRzW2MuaV0sYik7Yy5pKyt9dGhpcy5wcm9jZXNzTWVzc2FnZShjLGEpO3JldHVybiBNYXRoSmF4LkNhbGxiYWNrLkFmdGVyKFsicHJvY2VzcyIrYSx0aGlzLGNdLGIucmVzdGFydCl9LGZvcm1hdEVycm9yOmZ1bmN0aW9uKGIsZil7dmFyIGg9ZnVuY3Rpb24obCxrLGosaSl7cmV0dXJuIE1hdGhKYXguTG9jYWxpemF0aW9uLl8obCxrLGosaSl9O3ZhciBlPWgoIkVycm9yTWVzc2FnZSIsIkVycm9yOiAlMSIsZi5tZXNzYWdlKSsiXG4iO2lmKGYuc291cmNlVVJMfHxmLmZpbGVOYW1lKXtlKz0iXG4iK2goIkVycm9yRmlsZSIsImZpbGU6ICUxIixmLnNvdXJjZVVSTHx8Zi5maWxlTmFtZSl9aWYoZi5saW5lfHxmLmxpbmVOdW1iZXIpe2UrPSJcbiIraCgiRXJyb3JMaW5lIiwibGluZTogJTEiLGYubGluZXx8Zi5saW5lTnVtYmVyKX1lKz0iXG5cbiIraCgiRXJyb3JUaXBzIiwiRGVidWdnaW5nIHRpcHM6IHVzZSAlMSwgaW5zcGVjdCAlMiBpbiB0aGUgYnJvd3NlciBjb25zb2xlIiwiJ3VucGFja2VkL01hdGhKYXguanMnIiwiJ01hdGhKYXguSHViLmxhc3RFcnJvciciKTtiLk1hdGhKYXguZXJyb3I9TWF0aEpheC5PdXRwdXRKYXguRXJyb3IuSmF4KGUsYik7aWYoYi5NYXRoSmF4LmVsZW1lbnRKYXgpe2IuTWF0aEpheC5lcnJvci5pbnB1dElEPWIuTWF0aEpheC5lbGVtZW50SmF4LmlucHV0SUR9dmFyIGc9dGhpcy5jb25maWcuZXJyb3JTZXR0aW5nczt2YXIgYT1oKGcubWVzc2FnZUlkLGcubWVzc2FnZSk7dmFyIGM9TWF0aEpheC5IVE1MLkVsZW1lbnQoInNwYW4iLHtjbGFzc05hbWU6Ik1hdGhKYXhfRXJyb3IiLGpheElEOiJFcnJvciIsaXNNYXRoSmF4OnRydWUsaWQ6Yi5NYXRoSmF4LmVycm9yLmlucHV0SUQrIi1GcmFtZSJ9LFtbInNwYW4iLG51bGwsYV1dKTtNYXRoSmF4LkFqYXguUmVxdWlyZSgiW01hdGhKYXhdL2V4dGVuc2lvbnMvTWF0aEV2ZW50cy5qcyIsZnVuY3Rpb24oKXt2YXIgaj1NYXRoSmF4LkV4dGVuc2lvbi5NYXRoRXZlbnRzLkV2ZW50LGk9TWF0aEpheC5IdWI7Yy5vbmNvbnRleHRtZW51PWouTWVudTtjLm9ubW91c2Vkb3duPWouTW91c2Vkb3duO2Mub25rZXlkb3duPWouS2V5ZG93bjtjLnRhYkluZGV4PWkuZ2V0VGFiT3JkZXIoaS5nZXRKYXhGb3IoYikpfSk7dmFyIGQ9ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoYy5pZCk7aWYoZCl7ZC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGQpfWlmKGIucGFyZW50Tm9kZSl7Yi5wYXJlbnROb2RlLmluc2VydEJlZm9yZShjLGIpfWlmKGIuTWF0aEpheC5wcmV2aWV3KXtiLk1hdGhKYXgucHJldmlldy5pbm5lckhUTUw9IiI7Yi5NYXRoSmF4LnByZXZpZXcuc3R5bGUuZGlzcGxheT0ibm9uZSJ9dGhpcy5sYXN0RXJyb3I9Zjt0aGlzLnNpZ25hbC5Qb3N0KFsiTWF0aCBQcm9jZXNzaW5nIEVycm9yIixiLGZdKX0sUmVzdGFydEFmdGVyOmZ1bmN0aW9uKGEpe3Rocm93IHRoaXMuSW5zZXJ0KEVycm9yKCJyZXN0YXJ0Iikse3Jlc3RhcnQ6TWF0aEpheC5DYWxsYmFjayhhKX0pfSxlbGVtZW50Q2FsbGJhY2s6ZnVuY3Rpb24oYyxmKXtpZihmPT1udWxsJiYoTWF0aEpheC5PYmplY3QuaXNBcnJheShjKXx8dHlwZW9mIGM9PT0iZnVuY3Rpb24iKSl7dHJ5e01hdGhKYXguQ2FsbGJhY2soYyk7Zj1jO2M9bnVsbH1jYXRjaChkKXt9fWlmKGM9PW51bGwpe2M9dGhpcy5jb25maWcuZWxlbWVudHN8fFtdfWlmKHRoaXMuaXNIVE1MQ29sbGVjdGlvbihjKSl7Yz10aGlzLkhUTUxDb2xsZWN0aW9uMkFycmF5KGMpfWlmKCFNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGMpKXtjPVtjXX1jPVtdLmNvbmNhdChjKTtmb3IodmFyIGI9MCxhPWMubGVuZ3RoO2I8YTtiKyspe2lmKHR5cGVvZihjW2JdKT09PSJzdHJpbmciKXtjW2JdPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGNbYl0pfX1pZighZG9jdW1lbnQuYm9keSl7ZG9jdW1lbnQuYm9keT1kb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiYm9keSIpWzBdfWlmKGMubGVuZ3RoPT0wKXtjLnB1c2goZG9jdW1lbnQuYm9keSl9aWYoIWYpe2Y9e319cmV0dXJue2NvdW50OmMubGVuZ3RoLGVsZW1lbnRzOihjLmxlbmd0aD09PTE/Y1swXTpjKSxjYWxsYmFjazpmfX0sZWxlbWVudFNjcmlwdHM6ZnVuY3Rpb24oZSl7dmFyIGI9W107aWYoTWF0aEpheC5PYmplY3QuaXNBcnJheShlKXx8dGhpcy5pc0hUTUxDb2xsZWN0aW9uKGUpKXtmb3IodmFyIGQ9MCxhPWUubGVuZ3RoO2Q8YTtkKyspe3ZhciBmPTA7Zm9yKHZhciBjPTA7YzxkJiYhZjtjKyspe2Y9ZVtjXS5jb250YWlucyhlW2RdKX1pZighZil7Yi5wdXNoLmFwcGx5KGIsdGhpcy5lbGVtZW50U2NyaXB0cyhlW2RdKSl9fXJldHVybiBifWlmKHR5cGVvZihlKT09PSJzdHJpbmciKXtlPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGUpfWlmKCFkb2N1bWVudC5ib2R5KXtkb2N1bWVudC5ib2R5PWRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJib2R5IilbMF19aWYoZT09bnVsbCl7ZT1kb2N1bWVudC5ib2R5fWlmKGUudGFnTmFtZSE9bnVsbCYmZS50YWdOYW1lLnRvTG93ZXJDYXNlKCk9PT0ic2NyaXB0Iil7cmV0dXJuW2VdfWI9ZS5nZXRFbGVtZW50c0J5VGFnTmFtZSgic2NyaXB0Iik7aWYodGhpcy5tc2llSFRNTENvbGxlY3Rpb25CdWcpe2I9dGhpcy5IVE1MQ29sbGVjdGlvbjJBcnJheShiKX1yZXR1cm4gYn0saXNIVE1MQ29sbGVjdGlvbjpmdW5jdGlvbihhKXtyZXR1cm4oIkhUTUxDb2xsZWN0aW9uIiBpbiB3aW5kb3cmJnR5cGVvZihhKT09PSJvYmplY3QiJiZhIGluc3RhbmNlb2YgSFRNTENvbGxlY3Rpb24pfSxIVE1MQ29sbGVjdGlvbjJBcnJheTpmdW5jdGlvbihjKXtpZighdGhpcy5tc2llSFRNTENvbGxlY3Rpb25CdWcpe3JldHVybltdLnNsaWNlLmNhbGwoYyl9dmFyIGI9W107Zm9yKHZhciBkPTAsYT1jLmxlbmd0aDtkPGE7ZCsrKXtiW2RdPWNbZF19cmV0dXJuIGJ9LEluc2VydDpmdW5jdGlvbihjLGEpe2Zvcih2YXIgYiBpbiBhKXtpZihhLmhhc093blByb3BlcnR5KGIpKXtpZih0eXBlb2YgYVtiXT09PSJvYmplY3QiJiYhKE1hdGhKYXguT2JqZWN0LmlzQXJyYXkoYVtiXSkpJiYodHlwZW9mIGNbYl09PT0ib2JqZWN0Inx8dHlwZW9mIGNbYl09PT0iZnVuY3Rpb24iKSl7dGhpcy5JbnNlcnQoY1tiXSxhW2JdKX1lbHNle2NbYl09YVtiXX19fXJldHVybiBjfSxnZXRUYWJPcmRlcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5jb25maWcubWVudVNldHRpbmdzLmluVGFiT3JkZXI/MDotMX0sU3BsaXRMaXN0OigidHJpbSIgaW4gU3RyaW5nLnByb3RvdHlwZT9mdW5jdGlvbihhKXtyZXR1cm4gYS50cmltKCkuc3BsaXQoL1xzKy8pfTpmdW5jdGlvbihhKXtyZXR1cm4gYS5yZXBsYWNlKC9eXHMrLywiIikucmVwbGFjZSgvXHMrJC8sIiIpLnNwbGl0KC9ccysvKX0pfTtNYXRoSmF4Lkh1Yi5JbnNlcnQoTWF0aEpheC5IdWIuY29uZmlnLnN0eWxlcyxNYXRoSmF4Lk1lc3NhZ2Uuc3R5bGVzKTtNYXRoSmF4Lkh1Yi5JbnNlcnQoTWF0aEpheC5IdWIuY29uZmlnLnN0eWxlcyx7Ii5NYXRoSmF4X0Vycm9yIjpNYXRoSmF4Lkh1Yi5jb25maWcuZXJyb3JTZXR0aW5ncy5zdHlsZX0pO01hdGhKYXguRXh0ZW5zaW9uPXt9O01hdGhKYXguSHViLkNvbmZpZ3VyZWQ9TWF0aEpheC5DYWxsYmFjayh7fSk7TWF0aEpheC5IdWIuU3RhcnR1cD17c2NyaXB0OiIiLHF1ZXVlOk1hdGhKYXguQ2FsbGJhY2suUXVldWUoKSxzaWduYWw6TWF0aEpheC5DYWxsYmFjay5TaWduYWwoIlN0YXJ0dXAiKSxwYXJhbXM6e30sQ29uZmlnOmZ1bmN0aW9uKCl7dGhpcy5xdWV1ZS5QdXNoKFsiUG9zdCIsdGhpcy5zaWduYWwsIkJlZ2luIENvbmZpZyJdKTtpZihNYXRoSmF4LkF1dGhvckNvbmZpZyYmTWF0aEpheC5BdXRob3JDb25maWcucm9vdCl7TWF0aEpheC5BamF4LmNvbmZpZy5yb290PU1hdGhKYXguQXV0aG9yQ29uZmlnLnJvb3R9aWYodGhpcy5wYXJhbXMubG9jYWxlKXtNYXRoSmF4LkxvY2FsaXphdGlvbi5yZXNldExvY2FsZSh0aGlzLnBhcmFtcy5sb2NhbGUpO01hdGhKYXguSHViLmNvbmZpZy5tZW51U2V0dGluZ3MubG9jYWxlPXRoaXMucGFyYW1zLmxvY2FsZX1pZih0aGlzLnBhcmFtcy5jb25maWcpe3ZhciBjPXRoaXMucGFyYW1zLmNvbmZpZy5zcGxpdCgvLC8pO2Zvcih2YXIgYj0wLGE9Yy5sZW5ndGg7YjxhO2IrKyl7aWYoIWNbYl0ubWF0Y2goL1wuanMkLykpe2NbYl0rPSIuanMifXRoaXMucXVldWUuUHVzaChbIlJlcXVpcmUiLE1hdGhKYXguQWpheCx0aGlzLlVSTCgiY29uZmlnIixjW2JdKV0pfX10aGlzLnF1ZXVlLlB1c2goWyJDb25maWciLE1hdGhKYXguSHViLE1hdGhKYXguQXV0aG9yQ29uZmlnXSk7aWYodGhpcy5zY3JpcHQubWF0Y2goL1xTLykpe3RoaXMucXVldWUuUHVzaCh0aGlzLnNjcmlwdCsiO1xuMTsiKX10aGlzLnF1ZXVlLlB1c2goWyJDb25maWdEZWxheSIsdGhpc10sWyJDb25maWdCbG9ja3MiLHRoaXNdLFtmdW5jdGlvbihkKXtyZXR1cm4gZC5sb2FkQXJyYXkoTWF0aEpheC5IdWIuY29uZmlnLmNvbmZpZywiY29uZmlnIixudWxsLHRydWUpfSx0aGlzXSxbIlBvc3QiLHRoaXMuc2lnbmFsLCJFbmQgQ29uZmlnIl0pfSxDb25maWdEZWxheTpmdW5jdGlvbigpe3ZhciBhPXRoaXMucGFyYW1zLmRlbGF5U3RhcnR1cFVudGlsfHxNYXRoSmF4Lkh1Yi5jb25maWcuZGVsYXlTdGFydHVwVW50aWw7aWYoYT09PSJvbmxvYWQiKXtyZXR1cm4gdGhpcy5vbmxvYWR9aWYoYT09PSJjb25maWd1cmVkIil7cmV0dXJuIE1hdGhKYXguSHViLkNvbmZpZ3VyZWR9cmV0dXJuIGF9LENvbmZpZ0Jsb2NrczpmdW5jdGlvbigpe3ZhciBjPWRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJzY3JpcHQiKTt2YXIgYj1NYXRoSmF4LkNhbGxiYWNrLlF1ZXVlKCk7Zm9yKHZhciBkPTAsYT1jLmxlbmd0aDtkPGE7ZCsrKXt2YXIgZT1TdHJpbmcoY1tkXS50eXBlKS5yZXBsYWNlKC8gL2csIiIpO2lmKGUubWF0Y2goL150ZXh0XC94LW1hdGhqYXgtY29uZmlnKDsuKik/JC8pJiYhZS5tYXRjaCgvO2V4ZWN1dGVkPXRydWUvKSl7Y1tkXS50eXBlKz0iO2V4ZWN1dGVkPXRydWUiO2IuUHVzaChjW2RdLmlubmVySFRNTCsiO1xuMTsiKX19cmV0dXJuIGIuUHVzaChmdW5jdGlvbigpe01hdGhKYXguQWpheC5jb25maWcucm9vdD1NYXRoSmF4Lkh1Yi5jb25maWcucm9vdH0pfSxDb29raWU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5xdWV1ZS5QdXNoKFsiUG9zdCIsdGhpcy5zaWduYWwsIkJlZ2luIENvb2tpZSJdLFsiR2V0IixNYXRoSmF4LkhUTUwuQ29va2llLCJtZW51IixNYXRoSmF4Lkh1Yi5jb25maWcubWVudVNldHRpbmdzXSxbZnVuY3Rpb24oZSl7dmFyIGQ9ZS5tZW51U2V0dGluZ3M7aWYoZC5sb2NhbGUpe01hdGhKYXguTG9jYWxpemF0aW9uLnJlc2V0TG9jYWxlKGQubG9jYWxlKX12YXIgZz1lLm1lbnVTZXR0aW5ncy5yZW5kZXJlcixiPWUuamF4O2lmKGcpe3ZhciBjPSJvdXRwdXQvIitnO2Iuc29ydCgpO2Zvcih2YXIgZj0wLGE9Yi5sZW5ndGg7ZjxhO2YrKyl7aWYoYltmXS5zdWJzdHIoMCw3KT09PSJvdXRwdXQvIil7YnJlYWt9fWlmKGY9PWEtMSl7Yi5wb3AoKX1lbHNle3doaWxlKGY8YSl7aWYoYltmXT09PWMpe2Iuc3BsaWNlKGYsMSk7YnJlYWt9ZisrfX1iLnVuc2hpZnQoYyl9aWYoZC5DSFRNTHByZXZpZXchPW51bGwpe2lmKGQuRmFzdFByZXZpZXc9PW51bGwpe2QuRmFzdFByZXZpZXc9ZC5DSFRNTHByZXZpZXd9ZGVsZXRlIGQuQ0hUTUxwcmV2aWV3fWlmKGQuRmFzdFByZXZpZXcmJiFNYXRoSmF4LkV4dGVuc2lvblsiZmFzdC1wcmV2aWV3Il0pe01hdGhKYXguSHViLmNvbmZpZy5leHRlbnNpb25zLnB1c2goImZhc3QtcHJldmlldy5qcyIpfWlmKGUubWVudVNldHRpbmdzLmFzc2lzdGl2ZU1NTCYmIU1hdGhKYXguRXh0ZW5zaW9uLkFzc2lzdGl2ZU1NTCl7TWF0aEpheC5IdWIuY29uZmlnLmV4dGVuc2lvbnMucHVzaCgiQXNzaXN0aXZlTU1MLmpzIil9fSxNYXRoSmF4Lkh1Yi5jb25maWddLFsiUG9zdCIsdGhpcy5zaWduYWwsIkVuZCBDb29raWUiXSl9LFN0eWxlczpmdW5jdGlvbigpe3JldHVybiB0aGlzLnF1ZXVlLlB1c2goWyJQb3N0Iix0aGlzLnNpZ25hbCwiQmVnaW4gU3R5bGVzIl0sWyJsb2FkQXJyYXkiLHRoaXMsTWF0aEpheC5IdWIuY29uZmlnLnN0eWxlU2hlZXRzLCJjb25maWciXSxbIlN0eWxlcyIsTWF0aEpheC5BamF4LE1hdGhKYXguSHViLmNvbmZpZy5zdHlsZXNdLFsiUG9zdCIsdGhpcy5zaWduYWwsIkVuZCBTdHlsZXMiXSl9LEpheDpmdW5jdGlvbigpe3ZhciBmPU1hdGhKYXguSHViLmNvbmZpZyxjPU1hdGhKYXguSHViLm91dHB1dEpheDtmb3IodmFyIGc9MCxiPWYuamF4Lmxlbmd0aCxkPTA7ZzxiO2crKyl7dmFyIGU9Zi5qYXhbZ10uc3Vic3RyKDcpO2lmKGYuamF4W2ddLnN1YnN0cigwLDcpPT09Im91dHB1dC8iJiZjLm9yZGVyW2VdPT1udWxsKXtjLm9yZGVyW2VdPWQ7ZCsrfX12YXIgYT1NYXRoSmF4LkNhbGxiYWNrLlF1ZXVlKCk7cmV0dXJuIGEuUHVzaChbIlBvc3QiLHRoaXMuc2lnbmFsLCJCZWdpbiBKYXgiXSxbImxvYWRBcnJheSIsdGhpcyxmLmpheCwiamF4IiwiY29uZmlnLmpzIl0sWyJQb3N0Iix0aGlzLnNpZ25hbCwiRW5kIEpheCJdKX0sRXh0ZW5zaW9uczpmdW5jdGlvbigpe3ZhciBhPU1hdGhKYXguQ2FsbGJhY2suUXVldWUoKTtyZXR1cm4gYS5QdXNoKFsiUG9zdCIsdGhpcy5zaWduYWwsIkJlZ2luIEV4dGVuc2lvbnMiXSxbImxvYWRBcnJheSIsdGhpcyxNYXRoSmF4Lkh1Yi5jb25maWcuZXh0ZW5zaW9ucywiZXh0ZW5zaW9ucyJdLFsiUG9zdCIsdGhpcy5zaWduYWwsIkVuZCBFeHRlbnNpb25zIl0pfSxNZXNzYWdlOmZ1bmN0aW9uKCl7TWF0aEpheC5NZXNzYWdlLkluaXQodHJ1ZSl9LE1lbnU6ZnVuY3Rpb24oKXt2YXIgYj1NYXRoSmF4Lkh1Yi5jb25maWcubWVudVNldHRpbmdzLGE9TWF0aEpheC5IdWIub3V0cHV0SmF4LGQ7Zm9yKHZhciBjIGluIGEpe2lmKGEuaGFzT3duUHJvcGVydHkoYykpe2lmKGFbY10ubGVuZ3RoKXtkPWFbY107YnJlYWt9fX1pZihkJiZkLmxlbmd0aCl7aWYoYi5yZW5kZXJlciYmYi5yZW5kZXJlciE9PWRbMF0uaWQpe2QudW5zaGlmdChNYXRoSmF4Lk91dHB1dEpheFtiLnJlbmRlcmVyXSl9Yi5yZW5kZXJlcj1kWzBdLmlkfX0sSGFzaDpmdW5jdGlvbigpe2lmKE1hdGhKYXguSHViLmNvbmZpZy5wb3NpdGlvblRvSGFzaCYmZG9jdW1lbnQubG9jYXRpb24uaGFzaCYmZG9jdW1lbnQuYm9keSYmZG9jdW1lbnQuYm9keS5zY3JvbGxJbnRvVmlldyl7dmFyIGQ9ZG9jdW1lbnQubG9jYXRpb24uaGFzaC5zdWJzdHIoMSk7dmFyIGY9ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoZCk7aWYoIWYpe3ZhciBjPWRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJhIik7Zm9yKHZhciBlPTAsYj1jLmxlbmd0aDtlPGI7ZSsrKXtpZihjW2VdLm5hbWU9PT1kKXtmPWNbZV07YnJlYWt9fX1pZihmKXt3aGlsZSghZi5zY3JvbGxJbnRvVmlldyl7Zj1mLnBhcmVudE5vZGV9Zj10aGlzLkhhc2hDaGVjayhmKTtpZihmJiZmLnNjcm9sbEludG9WaWV3KXtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7Zi5zY3JvbGxJbnRvVmlldyh0cnVlKX0sMSl9fX19LEhhc2hDaGVjazpmdW5jdGlvbihiKXt2YXIgYT1NYXRoSmF4Lkh1Yi5nZXRKYXhGb3IoYik7aWYoYSYmTWF0aEpheC5PdXRwdXRKYXhbYS5vdXRwdXRKYXhdLmhhc2hDaGVjayl7Yj1NYXRoSmF4Lk91dHB1dEpheFthLm91dHB1dEpheF0uaGFzaENoZWNrKGIpfXJldHVybiBifSxNZW51Wm9vbTpmdW5jdGlvbigpe2lmKE1hdGhKYXguSHViLmNvbmZpZy5zaG93TWF0aE1lbnUpe2lmKCFNYXRoSmF4LkV4dGVuc2lvbi5NYXRoTWVudSl7c2V0VGltZW91dChmdW5jdGlvbigpe01hdGhKYXguQ2FsbGJhY2suUXVldWUoWyJSZXF1aXJlIixNYXRoSmF4LkFqYXgsIltNYXRoSmF4XS9leHRlbnNpb25zL01hdGhNZW51LmpzIix7fV0sWyJsb2FkRG9tYWluIixNYXRoSmF4LkxvY2FsaXphdGlvbiwiTWF0aE1lbnUiXSl9LDEwMDApfWVsc2V7c2V0VGltZW91dChNYXRoSmF4LkNhbGxiYWNrKFsibG9hZERvbWFpbiIsTWF0aEpheC5Mb2NhbGl6YXRpb24sIk1hdGhNZW51Il0pLDEwMDApfWlmKCFNYXRoSmF4LkV4dGVuc2lvbi5NYXRoWm9vbSl7c2V0VGltZW91dChNYXRoSmF4LkNhbGxiYWNrKFsiUmVxdWlyZSIsTWF0aEpheC5BamF4LCJbTWF0aEpheF0vZXh0ZW5zaW9ucy9NYXRoWm9vbS5qcyIse31dKSwyMDAwKX19fSxvbkxvYWQ6ZnVuY3Rpb24oKXt2YXIgYT10aGlzLm9ubG9hZD1NYXRoSmF4LkNhbGxiYWNrKGZ1bmN0aW9uKCl7TWF0aEpheC5IdWIuU3RhcnR1cC5zaWduYWwuUG9zdCgib25Mb2FkIil9KTtpZihkb2N1bWVudC5ib2R5JiZkb2N1bWVudC5yZWFkeVN0YXRlKXtpZihNYXRoSmF4Lkh1Yi5Ccm93c2VyLmlzTVNJRSl7aWYoZG9jdW1lbnQucmVhZHlTdGF0ZT09PSJjb21wbGV0ZSIpe3JldHVyblthXX19ZWxzZXtpZihkb2N1bWVudC5yZWFkeVN0YXRlIT09ImxvYWRpbmciKXtyZXR1cm5bYV19fX1pZih3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcil7d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoImxvYWQiLGEsZmFsc2UpO2lmKCF0aGlzLnBhcmFtcy5ub0RPTUNvbnRlbnRFdmVudCl7d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoIkRPTUNvbnRlbnRMb2FkZWQiLGEsZmFsc2UpfX1lbHNle2lmKHdpbmRvdy5hdHRhY2hFdmVudCl7d2luZG93LmF0dGFjaEV2ZW50KCJvbmxvYWQiLGEpfWVsc2V7d2luZG93Lm9ubG9hZD1hfX1yZXR1cm4gYX0sVHlwZXNldDpmdW5jdGlvbihhLGIpe2lmKE1hdGhKYXguSHViLmNvbmZpZy5za2lwU3RhcnR1cFR5cGVzZXQpe3JldHVybiBmdW5jdGlvbigpe319cmV0dXJuIHRoaXMucXVldWUuUHVzaChbIlBvc3QiLHRoaXMuc2lnbmFsLCJCZWdpbiBUeXBlc2V0Il0sWyJUeXBlc2V0IixNYXRoSmF4Lkh1YixhLGJdLFsiUG9zdCIsdGhpcy5zaWduYWwsIkVuZCBUeXBlc2V0Il0pfSxVUkw6ZnVuY3Rpb24oYixhKXtpZighYS5tYXRjaCgvXihbYS16XSs6XC9cL3xcW3xcLykvKSl7YT0iW01hdGhKYXhdLyIrYisiLyIrYX1yZXR1cm4gYX0sbG9hZEFycmF5OmZ1bmN0aW9uKGIsZixjLGEpe2lmKGIpe2lmKCFNYXRoSmF4Lk9iamVjdC5pc0FycmF5KGIpKXtiPVtiXX1pZihiLmxlbmd0aCl7dmFyIGg9TWF0aEpheC5DYWxsYmFjay5RdWV1ZSgpLGo9e30sZTtmb3IodmFyIGc9MCxkPWIubGVuZ3RoO2c8ZDtnKyspe2U9dGhpcy5VUkwoZixiW2ddKTtpZihjKXtlKz0iLyIrY31pZihhKXtoLlB1c2goWyJSZXF1aXJlIixNYXRoSmF4LkFqYXgsZSxqXSl9ZWxzZXtoLlB1c2goTWF0aEpheC5BamF4LlJlcXVpcmUoZSxqKSl9fXJldHVybiBoLlB1c2goe30pfX1yZXR1cm4gbnVsbH19OyhmdW5jdGlvbihkKXt2YXIgYj13aW5kb3dbZF0sZT0iWyIrZCsiXSI7dmFyIGM9Yi5IdWIsYT1iLkFqYXgsZj1iLkNhbGxiYWNrO3ZhciBnPU1hdGhKYXguT2JqZWN0LlN1YmNsYXNzKHtKQVhGSUxFOiJqYXguanMiLHJlcXVpcmU6bnVsbCxjb25maWc6e30sSW5pdDpmdW5jdGlvbihpLGgpe2lmKGFyZ3VtZW50cy5sZW5ndGg9PT0wKXtyZXR1cm4gdGhpc31yZXR1cm4odGhpcy5jb25zdHJ1Y3Rvci5TdWJjbGFzcyhpLGgpKSgpfSxBdWdtZW50OmZ1bmN0aW9uKGssail7dmFyIGk9dGhpcy5jb25zdHJ1Y3RvcixoPXt9O2lmKGshPW51bGwpe2Zvcih2YXIgbCBpbiBrKXtpZihrLmhhc093blByb3BlcnR5KGwpKXtpZih0eXBlb2Yga1tsXT09PSJmdW5jdGlvbiIpe2kucHJvdG9GdW5jdGlvbihsLGtbbF0pfWVsc2V7aFtsXT1rW2xdfX19aWYoay50b1N0cmluZyE9PWkucHJvdG90eXBlLnRvU3RyaW5nJiZrLnRvU3RyaW5nIT09e30udG9TdHJpbmcpe2kucHJvdG9GdW5jdGlvbigidG9TdHJpbmciLGsudG9TdHJpbmcpfX1jLkluc2VydChpLnByb3RvdHlwZSxoKTtpLkF1Z21lbnQobnVsbCxqKTtyZXR1cm4gdGhpc30sVHJhbnNsYXRlOmZ1bmN0aW9uKGgsaSl7dGhyb3cgRXJyb3IodGhpcy5kaXJlY3RvcnkrIi8iK3RoaXMuSkFYRklMRSsiIGZhaWxlZCB0byBkZWZpbmUgdGhlIFRyYW5zbGF0ZSgpIG1ldGhvZCIpfSxSZWdpc3RlcjpmdW5jdGlvbihoKXt9LENvbmZpZzpmdW5jdGlvbigpe3RoaXMuY29uZmlnPWMuQ29tYmluZUNvbmZpZyh0aGlzLmlkLHRoaXMuY29uZmlnKTtpZih0aGlzLmNvbmZpZy5BdWdtZW50KXt0aGlzLkF1Z21lbnQodGhpcy5jb25maWcuQXVnbWVudCl9fSxTdGFydHVwOmZ1bmN0aW9uKCl7fSxsb2FkQ29tcGxldGU6ZnVuY3Rpb24oaSl7aWYoaT09PSJjb25maWcuanMiKXtyZXR1cm4gYS5sb2FkQ29tcGxldGUodGhpcy5kaXJlY3RvcnkrIi8iK2kpfWVsc2V7dmFyIGg9Zi5RdWV1ZSgpO2guUHVzaChjLlJlZ2lzdGVyLlN0YXJ0dXBIb29rKCJFbmQgQ29uZmlnIix7fSksWyJQb3N0IixjLlN0YXJ0dXAuc2lnbmFsLHRoaXMuaWQrIiBKYXggQ29uZmlnIl0sWyJDb25maWciLHRoaXNdLFsiUG9zdCIsYy5TdGFydHVwLnNpZ25hbCx0aGlzLmlkKyIgSmF4IFJlcXVpcmUiXSxbZnVuY3Rpb24oail7cmV0dXJuIE1hdGhKYXguSHViLlN0YXJ0dXAubG9hZEFycmF5KGoucmVxdWlyZSx0aGlzLmRpcmVjdG9yeSl9LHRoaXNdLFtmdW5jdGlvbihqLGspe3JldHVybiBNYXRoSmF4Lkh1Yi5TdGFydHVwLmxvYWRBcnJheShqLmV4dGVuc2lvbnMsImV4dGVuc2lvbnMvIitrKX0sdGhpcy5jb25maWd8fHt9LHRoaXMuaWRdLFsiUG9zdCIsYy5TdGFydHVwLnNpZ25hbCx0aGlzLmlkKyIgSmF4IFN0YXJ0dXAiXSxbIlN0YXJ0dXAiLHRoaXNdLFsiUG9zdCIsYy5TdGFydHVwLnNpZ25hbCx0aGlzLmlkKyIgSmF4IFJlYWR5Il0pO2lmKHRoaXMuY29weVRyYW5zbGF0ZSl7aC5QdXNoKFtmdW5jdGlvbihqKXtqLnByZVByb2Nlc3M9ai5wcmVUcmFuc2xhdGU7ai5Qcm9jZXNzPWouVHJhbnNsYXRlO2oucG9zdFByb2Nlc3M9ai5wb3N0VHJhbnNsYXRlfSx0aGlzLmNvbnN0cnVjdG9yLnByb3RvdHlwZV0pfXJldHVybiBoLlB1c2goWyJsb2FkQ29tcGxldGUiLGEsdGhpcy5kaXJlY3RvcnkrIi8iK2ldKX19fSx7aWQ6IkpheCIsdmVyc2lvbjoiMi43LjEiLGRpcmVjdG9yeTplKyIvamF4IixleHRlbnNpb25EaXI6ZSsiL2V4dGVuc2lvbnMifSk7Yi5JbnB1dEpheD1nLlN1YmNsYXNzKHtlbGVtZW50SmF4OiJtbWwiLHNvdXJjZU1lbnVUaXRsZTpbIk9yaWdpbmFsIiwiT3JpZ2luYWwgRm9ybSJdLGNvcHlUcmFuc2xhdGU6dHJ1ZSxQcm9jZXNzOmZ1bmN0aW9uKGwscSl7dmFyIGo9Zi5RdWV1ZSgpLG87dmFyIGs9dGhpcy5lbGVtZW50SmF4O2lmKCFiLk9iamVjdC5pc0FycmF5KGspKXtrPVtrXX1mb3IodmFyIG49MCxoPWsubGVuZ3RoO248aDtuKyspe289Yi5FbGVtZW50SmF4LmRpcmVjdG9yeSsiLyIra1tuXSsiLyIrdGhpcy5KQVhGSUxFO2lmKCF0aGlzLnJlcXVpcmUpe3RoaXMucmVxdWlyZT1bXX1lbHNle2lmKCFiLk9iamVjdC5pc0FycmF5KHRoaXMucmVxdWlyZSkpe3RoaXMucmVxdWlyZT1bdGhpcy5yZXF1aXJlXX19dGhpcy5yZXF1aXJlLnB1c2gobyk7ai5QdXNoKGEuUmVxdWlyZShvKSl9bz10aGlzLmRpcmVjdG9yeSsiLyIrdGhpcy5KQVhGSUxFO3ZhciBwPWouUHVzaChhLlJlcXVpcmUobykpO2lmKCFwLmNhbGxlZCl7dGhpcy5jb25zdHJ1Y3Rvci5wcm90b3R5cGUuUHJvY2Vzcz1mdW5jdGlvbigpe2lmKCFwLmNhbGxlZCl7cmV0dXJuIHB9dGhyb3cgRXJyb3IobysiIGZhaWxlZCB0byBsb2FkIHByb3Blcmx5Iil9fWs9Yy5vdXRwdXRKYXhbImpheC8iK2tbMF1dO2lmKGspe2ouUHVzaChhLlJlcXVpcmUoa1swXS5kaXJlY3RvcnkrIi8iK3RoaXMuSkFYRklMRSkpfXJldHVybiBqLlB1c2goe30pfSxuZWVkc1VwZGF0ZTpmdW5jdGlvbihoKXt2YXIgaT1oLlNvdXJjZUVsZW1lbnQoKTtyZXR1cm4oaC5vcmlnaW5hbFRleHQhPT1iLkhUTUwuZ2V0U2NyaXB0KGkpKX0sUmVnaXN0ZXI6ZnVuY3Rpb24oaCl7aWYoIWMuaW5wdXRKYXgpe2MuaW5wdXRKYXg9e319Yy5pbnB1dEpheFtoXT10aGlzfX0se2lkOiJJbnB1dEpheCIsdmVyc2lvbjoiMi43LjEiLGRpcmVjdG9yeTpnLmRpcmVjdG9yeSsiL2lucHV0IixleHRlbnNpb25EaXI6Zy5leHRlbnNpb25EaXJ9KTtiLk91dHB1dEpheD1nLlN1YmNsYXNzKHtjb3B5VHJhbnNsYXRlOnRydWUscHJlUHJvY2VzczpmdW5jdGlvbihqKXt2YXIgaSxoPXRoaXMuZGlyZWN0b3J5KyIvIit0aGlzLkpBWEZJTEU7dGhpcy5jb25zdHJ1Y3Rvci5wcm90b3R5cGUucHJlUHJvY2Vzcz1mdW5jdGlvbihrKXtpZighaS5jYWxsZWQpe3JldHVybiBpfXRocm93IEVycm9yKGgrIiBmYWlsZWQgdG8gbG9hZCBwcm9wZXJseSIpfTtpPWEuUmVxdWlyZShoKTtyZXR1cm4gaX0sUmVnaXN0ZXI6ZnVuY3Rpb24oaSl7dmFyIGg9Yy5vdXRwdXRKYXg7aWYoIWhbaV0pe2hbaV09W119aWYoaFtpXS5sZW5ndGgmJih0aGlzLmlkPT09Yy5jb25maWcubWVudVNldHRpbmdzLnJlbmRlcmVyfHwoaC5vcmRlclt0aGlzLmlkXXx8MCk8KGgub3JkZXJbaFtpXVswXS5pZF18fDApKSl7aFtpXS51bnNoaWZ0KHRoaXMpfWVsc2V7aFtpXS5wdXNoKHRoaXMpfWlmKCF0aGlzLnJlcXVpcmUpe3RoaXMucmVxdWlyZT1bXX1lbHNle2lmKCFiLk9iamVjdC5pc0FycmF5KHRoaXMucmVxdWlyZSkpe3RoaXMucmVxdWlyZT1bdGhpcy5yZXF1aXJlXX19dGhpcy5yZXF1aXJlLnB1c2goYi5FbGVtZW50SmF4LmRpcmVjdG9yeSsiLyIrKGkuc3BsaXQoL1wvLylbMV0pKyIvIit0aGlzLkpBWEZJTEUpfSxSZW1vdmU6ZnVuY3Rpb24oaCl7fX0se2lkOiJPdXRwdXRKYXgiLHZlcnNpb246IjIuNy4xIixkaXJlY3Rvcnk6Zy5kaXJlY3RvcnkrIi9vdXRwdXQiLGV4dGVuc2lvbkRpcjpnLmV4dGVuc2lvbkRpcixmb250RGlyOmUrKGIuaXNQYWNrZWQ/IiI6Ii8uLiIpKyIvZm9udHMiLGltYWdlRGlyOmUrKGIuaXNQYWNrZWQ/IiI6Ii8uLiIpKyIvaW1hZ2VzIn0pO2IuRWxlbWVudEpheD1nLlN1YmNsYXNzKHtJbml0OmZ1bmN0aW9uKGksaCl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuU3ViY2xhc3MoaSxoKX0saW5wdXRKYXg6bnVsbCxvdXRwdXRKYXg6bnVsbCxpbnB1dElEOm51bGwsb3JpZ2luYWxUZXh0OiIiLG1pbWVUeXBlOiIiLHNvdXJjZU1lbnVUaXRsZTpbIk1hdGhNTGNvZGUiLCJNYXRoTUwgQ29kZSJdLFRleHQ6ZnVuY3Rpb24oaSxqKXt2YXIgaD10aGlzLlNvdXJjZUVsZW1lbnQoKTtiLkhUTUwuc2V0U2NyaXB0KGgsaSk7aC5NYXRoSmF4LnN0YXRlPXRoaXMuU1RBVEUuVVBEQVRFO3JldHVybiBjLlVwZGF0ZShoLGopfSxSZXByb2Nlc3M6ZnVuY3Rpb24oaSl7dmFyIGg9dGhpcy5Tb3VyY2VFbGVtZW50KCk7aC5NYXRoSmF4LnN0YXRlPXRoaXMuU1RBVEUuVVBEQVRFO3JldHVybiBjLlJlcHJvY2VzcyhoLGkpfSxVcGRhdGU6ZnVuY3Rpb24oaCl7cmV0dXJuIHRoaXMuUmVyZW5kZXIoaCl9LFJlcmVuZGVyOmZ1bmN0aW9uKGkpe3ZhciBoPXRoaXMuU291cmNlRWxlbWVudCgpO2guTWF0aEpheC5zdGF0ZT10aGlzLlNUQVRFLk9VVFBVVDtyZXR1cm4gYy5Qcm9jZXNzKGgsaSl9LFJlbW92ZTpmdW5jdGlvbihoKXtpZih0aGlzLmhvdmVyKXt0aGlzLmhvdmVyLmNsZWFyKHRoaXMpfWIuT3V0cHV0SmF4W3RoaXMub3V0cHV0SmF4XS5SZW1vdmUodGhpcyk7aWYoIWgpe2Muc2lnbmFsLlBvc3QoWyJSZW1vdmUgTWF0aCIsdGhpcy5pbnB1dElEXSk7dGhpcy5EZXRhY2goKX19LG5lZWRzVXBkYXRlOmZ1bmN0aW9uKCl7cmV0dXJuIGIuSW5wdXRKYXhbdGhpcy5pbnB1dEpheF0ubmVlZHNVcGRhdGUodGhpcyl9LFNvdXJjZUVsZW1lbnQ6ZnVuY3Rpb24oKXtyZXR1cm4gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5pbnB1dElEKX0sQXR0YWNoOmZ1bmN0aW9uKGksail7dmFyIGg9aS5NYXRoSmF4LmVsZW1lbnRKYXg7aWYoaS5NYXRoSmF4LnN0YXRlPT09dGhpcy5TVEFURS5VUERBVEUpe2guQ2xvbmUodGhpcyl9ZWxzZXtoPWkuTWF0aEpheC5lbGVtZW50SmF4PXRoaXM7aWYoaS5pZCl7dGhpcy5pbnB1dElEPWkuaWR9ZWxzZXtpLmlkPXRoaXMuaW5wdXRJRD1iLkVsZW1lbnRKYXguR2V0SUQoKTt0aGlzLm5ld0lEPTF9fWgub3JpZ2luYWxUZXh0PWIuSFRNTC5nZXRTY3JpcHQoaSk7aC5pbnB1dEpheD1qO2lmKGgucm9vdCl7aC5yb290LmlucHV0SUQ9aC5pbnB1dElEfXJldHVybiBofSxEZXRhY2g6ZnVuY3Rpb24oKXt2YXIgaD10aGlzLlNvdXJjZUVsZW1lbnQoKTtpZighaCl7cmV0dXJufXRyeXtkZWxldGUgaC5NYXRoSmF4fWNhdGNoKGkpe2guTWF0aEpheD1udWxsfWlmKHRoaXMubmV3SUQpe2guaWQ9IiJ9fSxDbG9uZTpmdW5jdGlvbihoKXt2YXIgaTtmb3IoaSBpbiB0aGlzKXtpZighdGhpcy5oYXNPd25Qcm9wZXJ0eShpKSl7Y29udGludWV9aWYodHlwZW9mKGhbaV0pPT09InVuZGVmaW5lZCImJmkhPT0ibmV3SUQiKXtkZWxldGUgdGhpc1tpXX19Zm9yKGkgaW4gaCl7aWYoIWguaGFzT3duUHJvcGVydHkoaSkpe2NvbnRpbnVlfWlmKHR5cGVvZih0aGlzW2ldKT09PSJ1bmRlZmluZWQifHwodGhpc1tpXSE9PWhbaV0mJmkhPT0iaW5wdXRJRCIpKXt0aGlzW2ldPWhbaV19fX19LHtpZDoiRWxlbWVudEpheCIsdmVyc2lvbjoiMi43LjEiLGRpcmVjdG9yeTpnLmRpcmVjdG9yeSsiL2VsZW1lbnQiLGV4dGVuc2lvbkRpcjpnLmV4dGVuc2lvbkRpcixJRDowLFNUQVRFOntQRU5ESU5HOjEsUFJPQ0VTU0VEOjIsVVBEQVRFOjMsT1VUUFVUOjR9LEdldElEOmZ1bmN0aW9uKCl7dGhpcy5JRCsrO3JldHVybiJNYXRoSmF4LUVsZW1lbnQtIit0aGlzLklEfSxTdWJjbGFzczpmdW5jdGlvbigpe3ZhciBoPWcuU3ViY2xhc3MuYXBwbHkodGhpcyxhcmd1bWVudHMpO2gubG9hZENvbXBsZXRlPXRoaXMucHJvdG90eXBlLmxvYWRDb21wbGV0ZTtyZXR1cm4gaH19KTtiLkVsZW1lbnRKYXgucHJvdG90eXBlLlNUQVRFPWIuRWxlbWVudEpheC5TVEFURTtiLk91dHB1dEpheC5FcnJvcj17aWQ6IkVycm9yIix2ZXJzaW9uOiIyLjcuMSIsY29uZmlnOnt9LGVycm9yczowLENvbnRleHRNZW51OmZ1bmN0aW9uKCl7cmV0dXJuIGIuRXh0ZW5zaW9uLk1hdGhFdmVudHMuRXZlbnQuQ29udGV4dE1lbnUuYXBwbHkoYi5FeHRlbnNpb24uTWF0aEV2ZW50cy5FdmVudCxhcmd1bWVudHMpfSxNb3VzZWRvd246ZnVuY3Rpb24oKXtyZXR1cm4gYi5FeHRlbnNpb24uTWF0aEV2ZW50cy5FdmVudC5BbHRDb250ZXh0TWVudS5hcHBseShiLkV4dGVuc2lvbi5NYXRoRXZlbnRzLkV2ZW50LGFyZ3VtZW50cyl9LGdldEpheEZyb21NYXRoOmZ1bmN0aW9uKGgpe3JldHVybihoLm5leHRTaWJsaW5nLk1hdGhKYXh8fHt9KS5lcnJvcn0sSmF4OmZ1bmN0aW9uKGosaSl7dmFyIGg9TWF0aEpheC5IdWIuaW5wdXRKYXhbaS50eXBlLnJlcGxhY2UoLyAqOygufFxzKSovLCIiKV07dGhpcy5lcnJvcnMrKztyZXR1cm57aW5wdXRKYXg6KGh8fHtpZDoiRXJyb3IifSkuaWQsb3V0cHV0SmF4OiJFcnJvciIsaW5wdXRJRDoiTWF0aEpheC1FcnJvci0iK3RoaXMuZXJyb3JzLHNvdXJjZU1lbnVUaXRsZTpbIkVycm9yTWVzc2FnZSIsIkVycm9yIE1lc3NhZ2UiXSxzb3VyY2VNZW51Rm9ybWF0OiJFcnJvciIsb3JpZ2luYWxUZXh0Ok1hdGhKYXguSFRNTC5nZXRTY3JpcHQoaSksZXJyb3JUZXh0Omp9fX07Yi5JbnB1dEpheC5FcnJvcj17aWQ6IkVycm9yIix2ZXJzaW9uOiIyLjcuMSIsY29uZmlnOnt9LHNvdXJjZU1lbnVUaXRsZTpbIk9yaWdpbmFsIiwiT3JpZ2luYWwgRm9ybSJdfX0pKCJNYXRoSmF4Iik7KGZ1bmN0aW9uKG8pe3ZhciBoPXdpbmRvd1tvXTtpZighaCl7aD13aW5kb3dbb109e319dmFyIGQ9aC5IdWI7dmFyIHM9ZC5TdGFydHVwO3ZhciB3PWQuY29uZmlnO3ZhciBnPWRvY3VtZW50LmhlYWR8fChkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdKTtpZighZyl7Zz1kb2N1bWVudC5jaGlsZE5vZGVzWzBdfXZhciBiPShkb2N1bWVudC5kb2N1bWVudEVsZW1lbnR8fGRvY3VtZW50KS5nZXRFbGVtZW50c0J5VGFnTmFtZSgic2NyaXB0Iik7aWYoYi5sZW5ndGg9PT0wJiZnLm5hbWVzcGFjZVVSSSl7Yj1kb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZU5TKGcubmFtZXNwYWNlVVJJLCJzY3JpcHQiKX12YXIgZj1uZXcgUmVnRXhwKCIoXnwvKSIrbysiXFwuanMoXFw/LiopPyQiKTtmb3IodmFyIHE9Yi5sZW5ndGgtMTtxPj0wO3EtLSl7aWYoKGJbcV0uc3JjfHwiIikubWF0Y2goZikpe3Muc2NyaXB0PWJbcV0uaW5uZXJIVE1MO2lmKFJlZ0V4cC4kMil7dmFyIHQ9UmVnRXhwLiQyLnN1YnN0cigxKS5zcGxpdCgvXCYvKTtmb3IodmFyIHA9MCxsPXQubGVuZ3RoO3A8bDtwKyspe3ZhciBuPXRbcF0ubWF0Y2goLyguKik9KC4qKS8pO2lmKG4pe3MucGFyYW1zW3VuZXNjYXBlKG5bMV0pXT11bmVzY2FwZShuWzJdKX1lbHNle3MucGFyYW1zW3RbcF1dPXRydWV9fX13LnJvb3Q9YltxXS5zcmMucmVwbGFjZSgvKF58XC8pW15cL10qKFw/LiopPyQvLCIiKTtoLkFqYXguY29uZmlnLnJvb3Q9dy5yb290O2guQWpheC5wYXJhbXM9cy5wYXJhbXM7YnJlYWt9fXZhciBrPW5hdmlnYXRvci51c2VyQWdlbnQ7dmFyIGE9e2lzTWFjOihuYXZpZ2F0b3IucGxhdGZvcm0uc3Vic3RyKDAsMyk9PT0iTWFjIiksaXNQQzoobmF2aWdhdG9yLnBsYXRmb3JtLnN1YnN0cigwLDMpPT09IldpbiIpLGlzTVNJRTooIkFjdGl2ZVhPYmplY3QiIGluIHdpbmRvdyYmImNsaXBib2FyZERhdGEiIGluIHdpbmRvdyksaXNFZGdlOigiTVNHZXN0dXJlRXZlbnQiIGluIHdpbmRvdyYmImNocm9tZSIgaW4gd2luZG93JiZ3aW5kb3cuY2hyb21lLmxvYWRUaW1lcz09bnVsbCksaXNGaXJlZm94OighIWsubWF0Y2goL0dlY2tvXC8vKSYmIWsubWF0Y2goL2xpa2UgR2Vja28vKSksaXNTYWZhcmk6KCEhay5tYXRjaCgvIChBcHBsZSk/V2ViS2l0XC8vKSYmIWsubWF0Y2goLyBsaWtlIGlQaG9uZSAvKSYmKCF3aW5kb3cuY2hyb21lfHx3aW5kb3cuY2hyb21lLmFwcD09bnVsbCkpLGlzQ2hyb21lOigiY2hyb21lIiBpbiB3aW5kb3cmJndpbmRvdy5jaHJvbWUubG9hZFRpbWVzIT1udWxsKSxpc09wZXJhOigib3BlcmEiIGluIHdpbmRvdyYmd2luZG93Lm9wZXJhLnZlcnNpb24hPW51bGwpLGlzS29ucXVlcm9yOigia29ucXVlcm9yIiBpbiB3aW5kb3cmJm5hdmlnYXRvci52ZW5kb3I9PSJLREUiKSx2ZXJzaW9uQXRMZWFzdDpmdW5jdGlvbih5KXt2YXIgeD0odGhpcy52ZXJzaW9uKS5zcGxpdCgiLiIpO3k9KG5ldyBTdHJpbmcoeSkpLnNwbGl0KCIuIik7Zm9yKHZhciB6PTAsaj15Lmxlbmd0aDt6PGo7eisrKXtpZih4W3pdIT15W3pdKXtyZXR1cm4gcGFyc2VJbnQoeFt6XXx8IjAiKT49cGFyc2VJbnQoeVt6XSl9fXJldHVybiB0cnVlfSxTZWxlY3Q6ZnVuY3Rpb24oail7dmFyIGk9altkLkJyb3dzZXJdO2lmKGkpe3JldHVybiBpKGQuQnJvd3Nlcil9cmV0dXJuIG51bGx9fTt2YXIgZT1rLnJlcGxhY2UoL15Nb3ppbGxhXC8oXGQrXC4pK1xkKyAvLCIiKS5yZXBsYWNlKC9bYS16XVstYS16MC05Ll86IF0rXC9cZCtbXiBdKi1bXiBdKlwuKFthLXpdW2Etel0pP1xkKyAvaSwiIikucmVwbGFjZSgvR2VudG9vIHxVYnVudHVcLyhcZCtcLikqXGQrIChcKFteKV0qXCkgKT8vLCIiKTtkLkJyb3dzZXI9ZC5JbnNlcnQoZC5JbnNlcnQobmV3IFN0cmluZygiVW5rbm93biIpLHt2ZXJzaW9uOiIwLjAifSksYSk7Zm9yKHZhciB2IGluIGEpe2lmKGEuaGFzT3duUHJvcGVydHkodikpe2lmKGFbdl0mJnYuc3Vic3RyKDAsMik9PT0iaXMiKXt2PXYuc2xpY2UoMik7aWYodj09PSJNYWMifHx2PT09IlBDIil7Y29udGludWV9ZC5Ccm93c2VyPWQuSW5zZXJ0KG5ldyBTdHJpbmcodiksYSk7dmFyIHI9bmV3IFJlZ0V4cCgiLiooVmVyc2lvbi98IFRyaWRlbnQvLio7IHJ2OikoKD86XFxkK1xcLikrXFxkKyl8LiooIit2KyIpIisodj09Ik1TSUUiPyIgIjoiLyIpKyIoKD86XFxkK1xcLikqXFxkKyl8KD86XnxcXCh8ICkoW2Etel1bLWEtejAtOS5fOiBdK3woPzpBcHBsZSk/V2ViS2l0KS8oKD86XFxkK1xcLikrXFxkKykiKTt2YXIgdT1yLmV4ZWMoZSl8fFsiIiwiIiwiIiwidW5rbm93biIsIjAuMCJdO2QuQnJvd3Nlci5uYW1lPSh1WzFdIT0iIj92Oih1WzNdfHx1WzVdKSk7ZC5Ccm93c2VyLnZlcnNpb249dVsyXXx8dVs0XXx8dVs2XTticmVha319fXRyeXtkLkJyb3dzZXIuU2VsZWN0KHtTYWZhcmk6ZnVuY3Rpb24oail7dmFyIGk9cGFyc2VJbnQoKFN0cmluZyhqLnZlcnNpb24pLnNwbGl0KCIuIikpWzBdKTtpZihpPjg1KXtqLndlYmtpdD1qLnZlcnNpb259aWYoaT49NTM4KXtqLnZlcnNpb249IjguMCJ9ZWxzZXtpZihpPj01Mzcpe2oudmVyc2lvbj0iNy4wIn1lbHNle2lmKGk+PTUzNil7ai52ZXJzaW9uPSI2LjAifWVsc2V7aWYoaT49NTM0KXtqLnZlcnNpb249IjUuMSJ9ZWxzZXtpZihpPj01MzMpe2oudmVyc2lvbj0iNS4wIn1lbHNle2lmKGk+PTUyNil7ai52ZXJzaW9uPSI0LjAifWVsc2V7aWYoaT49NTI1KXtqLnZlcnNpb249IjMuMSJ9ZWxzZXtpZihpPjUwMCl7ai52ZXJzaW9uPSIzLjAifWVsc2V7aWYoaT40MDApe2oudmVyc2lvbj0iMi4wIn1lbHNle2lmKGk+ODUpe2oudmVyc2lvbj0iMS4wIn19fX19fX19fX1qLndlYmtpdD0obmF2aWdhdG9yLmFwcFZlcnNpb24ubWF0Y2goL1dlYktpdFwvKFxkKylcLi8pKVsxXTtqLmlzTW9iaWxlPShuYXZpZ2F0b3IuYXBwVmVyc2lvbi5tYXRjaCgvTW9iaWxlL2kpIT1udWxsKTtqLm5vQ29udGV4dE1lbnU9ai5pc01vYmlsZX0sRmlyZWZveDpmdW5jdGlvbihqKXtpZigoai52ZXJzaW9uPT09IjAuMCJ8fGsubWF0Y2goL0ZpcmVmb3gvKT09bnVsbCkmJm5hdmlnYXRvci5wcm9kdWN0PT09IkdlY2tvIil7dmFyIG09ay5tYXRjaCgvW1wvIF1ydjooXGQrXC5cZC4qPylbXCkgXS8pO2lmKG0pe2oudmVyc2lvbj1tWzFdfWVsc2V7dmFyIGk9KG5hdmlnYXRvci5idWlsZElEfHxuYXZpZ2F0b3IucHJvZHVjdFN1Ynx8IjAiKS5zdWJzdHIoMCw4KTtpZihpPj0iMjAxMTEyMjAiKXtqLnZlcnNpb249IjkuMCJ9ZWxzZXtpZihpPj0iMjAxMTExMjAiKXtqLnZlcnNpb249IjguMCJ9ZWxzZXtpZihpPj0iMjAxMTA5MjciKXtqLnZlcnNpb249IjcuMCJ9ZWxzZXtpZihpPj0iMjAxMTA4MTYiKXtqLnZlcnNpb249IjYuMCJ9ZWxzZXtpZihpPj0iMjAxMTA2MjEiKXtqLnZlcnNpb249IjUuMCJ9ZWxzZXtpZihpPj0iMjAxMTAzMjAiKXtqLnZlcnNpb249IjQuMCJ9ZWxzZXtpZihpPj0iMjAxMDAxMjEiKXtqLnZlcnNpb249IjMuNiJ9ZWxzZXtpZihpPj0iMjAwOTA2MzAiKXtqLnZlcnNpb249IjMuNSJ9ZWxzZXtpZihpPj0iMjAwODA2MTciKXtqLnZlcnNpb249IjMuMCJ9ZWxzZXtpZihpPj0iMjAwNjEwMjQiKXtqLnZlcnNpb249IjIuMCJ9fX19fX19fX19fX1qLmlzTW9iaWxlPShuYXZpZ2F0b3IuYXBwVmVyc2lvbi5tYXRjaCgvQW5kcm9pZC9pKSE9bnVsbHx8ay5tYXRjaCgvIEZlbm5lY1wvLykhPW51bGx8fGsubWF0Y2goL01vYmlsZS8pIT1udWxsKX0sQ2hyb21lOmZ1bmN0aW9uKGkpe2kubm9Db250ZXh0TWVudT1pLmlzTW9iaWxlPSEhbmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvIE1vYmlsZVsgXC9dLyl9LE9wZXJhOmZ1bmN0aW9uKGkpe2kudmVyc2lvbj1vcGVyYS52ZXJzaW9uKCl9LEVkZ2U6ZnVuY3Rpb24oaSl7aS5pc01vYmlsZT0hIW5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goLyBQaG9uZS8pfSxNU0lFOmZ1bmN0aW9uKGope2ouaXNNb2JpbGU9ISFuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC8gUGhvbmUvKTtqLmlzSUU5PSEhKGRvY3VtZW50LmRvY3VtZW50TW9kZSYmKHdpbmRvdy5wZXJmb3JtYW5jZXx8d2luZG93Lm1zUGVyZm9ybWFuY2UpKTtNYXRoSmF4LkhUTUwuc2V0U2NyaXB0QnVnPSFqLmlzSUU5fHxkb2N1bWVudC5kb2N1bWVudE1vZGU8OTtNYXRoSmF4Lkh1Yi5tc2llSFRNTENvbGxlY3Rpb25CdWc9KGRvY3VtZW50LmRvY3VtZW50TW9kZTw5KTtpZihkb2N1bWVudC5kb2N1bWVudE1vZGU8MTAmJiFzLnBhcmFtcy5Ob01hdGhQbGF5ZXIpe3RyeXtuZXcgQWN0aXZlWE9iamVjdCgiTWF0aFBsYXllci5GYWN0b3J5LjEiKTtqLmhhc01hdGhQbGF5ZXI9dHJ1ZX1jYXRjaChtKXt9dHJ5e2lmKGouaGFzTWF0aFBsYXllcil7dmFyIGk9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgib2JqZWN0Iik7aS5pZD0ibWF0aHBsYXllciI7aS5jbGFzc2lkPSJjbHNpZDozMkY2NkEyMC03NjE0LTExRDQtQkQxMS0wMDEwNEJEM0Y5ODciO2cuYXBwZW5kQ2hpbGQoaSk7ZG9jdW1lbnQubmFtZXNwYWNlcy5hZGQoIm0iLCJodHRwOi8vd3d3LnczLm9yZy8xOTk4L01hdGgvTWF0aE1MIik7ai5tcE5hbWVzcGFjZT10cnVlO2lmKGRvY3VtZW50LnJlYWR5U3RhdGUmJihkb2N1bWVudC5yZWFkeVN0YXRlPT09ImxvYWRpbmcifHxkb2N1bWVudC5yZWFkeVN0YXRlPT09ImludGVyYWN0aXZlIikpe2RvY3VtZW50LndyaXRlKCc8P2ltcG9ydCBuYW1lc3BhY2U9Im0iIGltcGxlbWVudGF0aW9uPSIjTWF0aFBsYXllciI+Jyk7ai5tcEltcG9ydGVkPXRydWV9fWVsc2V7ZG9jdW1lbnQubmFtZXNwYWNlcy5hZGQoIm1qeF9JRV9maXgiLCJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIil9fWNhdGNoKG0pe319fX0pfWNhdGNoKGMpe2NvbnNvbGUuZXJyb3IoYy5tZXNzYWdlKX1kLkJyb3dzZXIuU2VsZWN0KE1hdGhKYXguTWVzc2FnZS5icm93c2Vycyk7aWYoaC5BdXRob3JDb25maWcmJnR5cGVvZiBoLkF1dGhvckNvbmZpZy5BdXRob3JJbml0PT09ImZ1bmN0aW9uIil7aC5BdXRob3JDb25maWcuQXV0aG9ySW5pdCgpfWQucXVldWU9aC5DYWxsYmFjay5RdWV1ZSgpO2QucXVldWUuUHVzaChbIlBvc3QiLHMuc2lnbmFsLCJCZWdpbiJdLFsiQ29uZmlnIixzXSxbIkNvb2tpZSIsc10sWyJTdHlsZXMiLHNdLFsiTWVzc2FnZSIsc10sZnVuY3Rpb24oKXt2YXIgaT1oLkNhbGxiYWNrLlF1ZXVlKHMuSmF4KCkscy5FeHRlbnNpb25zKCkpO3JldHVybiBpLlB1c2goe30pfSxbIk1lbnUiLHNdLHMub25Mb2FkKCksZnVuY3Rpb24oKXtNYXRoSmF4LmlzUmVhZHk9dHJ1ZX0sWyJUeXBlc2V0IixzXSxbIkhhc2giLHNdLFsiTWVudVpvb20iLHNdLFsiUG9zdCIscy5zaWduYWwsIkVuZCJdKX0pKCJNYXRoSmF4Iil9fTsK" type="text/javascript"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1 id="csce-410">CSCE 410</h1>
<h1 id="history-1-1">history (1-1)</h1>
<ul>
<li>1st gen
<ul>
<li>single user writes program that operates entire computer and manages all hardware
<ul>
<li>TODO? no development except right at the computer?</li>
</ul></li>
<li>no need for relocatable code
<ul>
<li>drivers and such were per-machine? TODO</li>
</ul></li>
</ul></li>
<li>2nd gen
<ul>
<li>move programming off-line (no longer programming in production?)</li>
<li>automated program loading by special monitor program
<ul>
<li>batch programming, but only one program kept in memory at a time</li>
</ul></li>
<li>misbehaving programs could mess with monitor, or other programs though</li>
</ul></li>
<li>3rd gen
<ul>
<li>scheduling of user programs to allow other stuff to happen while one program is waiting for IO
<ul>
<li>time sharing</li>
</ul></li>
<li>created need for time sharing</li>
<li>time sharing brought need for and development of
<ul>
<li>passwords</li>
<li>filesystems</li>
<li>interleaved execution of multiple programs (process scheduling)</li>
<li>remote access (computing as a utility)</li>
<li>virtual memory</li>
</ul></li>
</ul></li>
<li>what is an OS
<ul>
<li>OS controls and coordinates physical resources</li>
<li>abstracts various hardware details
<ul>
<li>IO, networking, processes</li>
</ul></li>
<li>keeps computer efficient
<ul>
<li>scheduling</li>
</ul></li>
</ul></li>
</ul>
<h1 id="architectural-support-1-2">architectural support (1-2)</h1>
<ul>
<li>OSes need hardware to do: asynchronous events, hardware protection (of other processes), address spaces, timers</li>
<li>asynchronous events
<ul>
<li>(nearly) all asynchronous events are handled using interrupts
<ul>
<li>IO, user input, timers, etc...</li>
</ul></li>
<li>when an interrupt happens the CPU does:
<ul>
<li>stop current execution</li>
<li>save state (registers and flags and stuff)</li>
<li>changes to supervisor mode (privileged mode)</li>
<li>branches to predefined location (interrupt handler corresponding to interrupt, in interrupt vector table (IVT))</li>
</ul></li>
<li>return from interrupt (<code>rti</code>) instruction automatically restores state</li>
<li>interrupt can be caused by
<ul>
<li>an asynchronous event (hardware, timer, error)</li>
<li>software (system call)</li>
</ul></li>
</ul></li>
<li>hardware protection
<ul>
<li>some instructions are marked as supervisor-mode-only, so regular user programs can't use them
<ul>
<li>OS then exposes that functionality using system calls</li>
</ul></li>
<li>memory is segmented (base+limit), so user programs can't access out of their bounds
<ul>
<li>also virtual memory allows multiple programs to have the same virtual addresses, but be in different physical memory locations</li>
</ul></li>
<li>hardware-provided timers allow OS to regain control from user programs at a regular interval
<ul>
<li>needed for reliable scheduling</li>
</ul></li>
</ul></li>
</ul>
<h1 id="os-structure-1-3">OS structure (1-3)</h1>
<ul>
<li>onion view of OS
<ul>
<li>view kernel as layered like an onion</li>
<li>innermost layer is lowest level hardware handling code</li>
<li>outermost layer is user programs</li>
<li>each layer can't be any closer to core than it is, due to dependencies on lower layers</li>
<li>from inside to out: hardware, memory, process manger, process coordinator, IPC, RTC, device manager, networking, filesystem, user programs</li>
<li>monolithic</li>
</ul></li>
<li>layering, monolithic kernels
<ul>
<li>monolithic kernel has layers that are all in kernel space and all equally trusted and important</li>
<li>layers are hierarchical</li>
</ul></li>
<li>microkernel
<ul>
<li>kernel has only very most core parts of OS</li>
<li>other stuff (like filesystems, scheduling...) is in user space server processes</li>
<li>more overhead because of context switching</li>
<li>benefits
<ul>
<li>server processes could be in different machines, communicating over a network (distributed system)</li>
<li>portable: kernel is easier to port because kernel core is smaller</li>
<li>robust: server process can fail without crashing the whole kernel</li>
</ul></li>
</ul></li>
<li>exokernel
<ul>
<li>do not abstract/emulate hardware, instead, export hardware securely</li>
<li>library operating system
<ul>
<li>used by apps to abstract the hardware</li>
</ul></li>
</ul></li>
</ul>
<h1 id="system-calls-1-4">system calls (1-4)</h1>
<ul>
<li>skipped</li>
</ul>
<h1 id="interrupts-and-exceptions-9-1-5">interrupts and exceptions (9, 1-5)</h1>
<ul>
<li>hardware interrupts
<ul>
<li>usually some kind of I/O: keyboard input, HDD ready, etc...</li>
</ul></li>
<li>there's an interrupt for periodic hardware timer
<ul>
<li>allows kernel to recover control from user program periodically</li>
</ul></li>
<li>exception: interrupt due to an error
<ul>
<li>may have an error code associated with it</li>
</ul></li>
<li>interrupt descriptor table (IDT)
<ul>
<li>256 elements large</li>
<li>first 32 entries are for exceptions</li>
<li>hardware interrupts can then map to any other interrupt using PIC</li>
</ul></li>
<li>handling interrupt
<ul>
<li>save sate of the calling program</li>
<li>handle interrupt</li>
<li>restore calling program state, return with <code>iret</code></li>
</ul></li>
<li>typical interrupt handling is to have the IDT just be stubs that just push to stack the type of interrupt and call common handling code
<ul>
<li>in our MPs, that common handling code then calls virtual methods of proper handling class</li>
<li>reduces code bloat?</li>
</ul></li>
<li>interrupts are prioritized (somehow)
<ul>
<li>if a higher priority interrupt comes in while handling a lower priority one, the lower priority interrupt is interrupted by the higher priority one</li>
<li>for equal priority, it's FIFO</li>
</ul></li>
<li>8259 programmable interrupt controller (PIC)
<ul>
<li>just need to know that this exists, and is necessary for handling interrupts</li>
</ul></li>
</ul>
<h1 id="allocation-2-1">allocation (2-1)</h1>
<ul>
<li>need to allocate space for:
<ul>
<li>new process (<code>fork()</code>)</li>
<li>new program (<code>execve()</code>)</li>
<li>process stack grows</li>
<li>process expands heap (<code>malloc()</code>)</li>
<li>process creates (attaches to) shared memory(<code>shmat()</code>)</li>
</ul></li>
<li>external vs internal fragmentation
<ul>
<li>external: OS needs to allocate a contiguous block of frames but there is no single contiguous space big enough</li>
<li>internal: you need a specific amount of memory, but maybe you have to round up to a multiple of page size. The difference between needed and what it takes up is internal fragmentation?</li>
</ul></li>
<li>naive allocator
<ul>
<li>TODO is a slab allocator a naive allocator?</li>
<li>TODO</li>
</ul></li>
<li>buddy allocator
<ul>
<li>maintain free lists in power-of-2 sizes</li>
<li>allocate:
<ul>
<li>round up size to next power of 2</li>
<li>lookup in free list of that size</li>
<li>if available, return</li>
<li>if that free list is empty, split a block from the next size up into 2 blocks and repeat
<ul>
<li>may need to split more than one size larger</li>
</ul></li>
</ul></li>
<li>deallocation
<ul>
<li>put back into free list</li>
<li>check buddy (flip bit in offset). if buddy is also free, join the blocks
<ul>
<li>may need to join more than one size larger</li>
</ul></li>
</ul></li>
</ul></li>
<li>different allocators:
<ul>
<li><code>malloc()</code>: virtually contiguous, size in bytes, implemented in user level library</li>
<li><code>kmalloc()</code>: physically contiguous, bytes, kernel, slab allocator</li>
<li><code>vmalloc()</code>: virtually contiguous, bytes, kernel, slab allocator</li>
<li><code>alloc_pages()</code>, <code>__get_free_pages()</code>: contiguous frames/pages, kernel, buddy allocator</li>
</ul></li>
</ul>
<h1 id="paging-7-2-3-8-2-4">paging (7, 2-3) (8, 2-4)</h1>
<ul>
<li>page size:
<ul>
<li>large pages => more fragmentation</li>
<li>small pages => more overhead</li>
</ul></li>
<li>paging allows for address spaces</li>
<li>page table lookup in hardware
<ul>
<li>MMU hardware</li>
<li>hardware uses top few bits of address as index into page table</li>
<li>then get that entry from the page table, add the lower bits of the virtual address (the offset), and go there in memory</li>
</ul></li>
<li>multi-level
<ul>
<li>split the virtual address into multiple indexes</li>
<li>this way you have a hierarchy of page tables, so all page tables below the top level can be lazily allocated
<ul>
<li>saves memory (reduces overhead)</li>
</ul></li>
<li>page table level <span class="math inline">\(n\)</span> at index contains physical address of the page table <span class="math inline">\(n+1\)</span> for use with <span class="math inline">\(n+1\)</span>th index</li>
</ul></li>
<li>inverted
<ul>
<li>linear array indexed by frame number</li>
<li>one table per entire system</li>
<li>maps frame number to (PID, page number)</li>
<li>saves space because there is always exactly one entry per physical frame</li>
<li>very slow because you have to search the entire thing for the PID and virtual address you're looking for</li>
<li>also you cannot have shared memory between processes</li>
</ul></li>
<li>hash page tables
<ul>
<li>one per system</li>
<li>indexed by (PID, page number)</li>
<li>typically collisions are handled with chaining</li>
<li>scales well with physical memory</li>
<li>does not allow for shared memory?</li>
</ul></li>
</ul>
<h1 id="segmentation-10-2-6">segmentation (10, 2-6)</h1>
<ul>
<li>segments are logical for programming (code, data, stack, heap)
<ul>
<li>stuff in segment is semantically related</li>
</ul></li>
<li>segmentation allows for easy data sharing between processes
<ul>
<li>e.g. forked process or shared dynamic library</li>
</ul></li>
<li>can lead to more external fragmentation because segments are larger than pages</li>
<li>segmented paging:
<ul>
<li>split virtual address into segment number, page number, and offset</li>
<li>reduces fragmentation</li>
</ul></li>
</ul>
<h1 id="tlb">TLB</h1>
<ul>
<li>translation look-aside buffer</li>
<li>caches page table lookups</li>
<li>you must clear entries when
<ul>
<li>pages are freed/unmapped</li>
<li>context switch happens</li>
</ul></li>
<li>in x86, it is managed by hardware</li>
<li>indexed by page table number and page table index
<ul>
<li>e.g. just 20 bits, not by the full address</li>
</ul></li>
<li>parameters
<ul>
<li>size</li>
<li>lookup latency</li>
<li>miss penalty (depends on MMU and memory speed)</li>
<li>target miss rate (depends on application)</li>
</ul></li>
<li>MIPS software managed TLB
<ul>
<li>TLB is the only cache</li>
<li>filling the TLB is done in software</li>
<li>TLB miss triggers special TLB refill exception</li>
</ul></li>
</ul>
<h1 id="page-replacement-policies-15-2-10">page replacement policies (15, 2-10)</h1>
<ul>
<li>cost of page fault, or effective memory access time (ema)
<ul>
<li>ema = (1-p) * ma + p * PageFaultTime</li>
<li>p = probability of a page fault</li>
<li>ma = memory access time</li>
</ul></li>
<li>locality of reference
<ul>
<li>if a program references location <span class="math inline">\(n\)</span>, it is likely to reference <span class="math inline">\(n\)</span> and locations near <span class="math inline">\(n\)</span> in the near future</li>
</ul></li>
<li>when you need more memory, how do you decide which pages to evict (and possibly writ to disk)?</li>
<li>FIFO
<ul>
<li>just evict the page that has been in memory the longest</li>
<li>pro: simple</li>
<li>con: does not exploit principle of locality of reference (assumes that pages resident in memory longer are more likely to continue to be referenced)</li>
</ul></li>
<li>ideal
<ul>
<li>evict page that will be next used farthest in the future (if at all)</li>
<li>pro: proven lowest number of page faults</li>
<li>con: impossible to implement in real life because we cannot see the future</li>
</ul></li>
<li>least recently used (LRU)
<ul>
<li>evict the page that has not been accessed in the longest period of time</li>
<li>pro: good performance</li>
<li>con: difficult to implement (must keep track of all references)</li>
<li>must keep chronological history of page references
<ul>
<li>software: use a stack</li>
<li>hardware: charge a capacitor and let it slowly drain</li>
</ul></li>
</ul></li>
<li>2nd chance
<ul>
<li>approximation to LRU</li>
<li>have a use bit for each page, and keep a pointer to the next candidate victim page
<ul>
<li>use bit is set every time frame is referenced</li>
<li>when a frame is newly loaded, use bit starts at 1</li>
</ul></li>
<li>when reclaiming memory:
<ul>
<li>if pointed-to page has use bit 0: use that frame as victim, and increment pointer to next frame</li>
<li>if pointed-to page has use bit 1: set that use bit to 0, increment pointer, and start over</li>
</ul></li>
<li>when victim pointer reaches end of memory, wrap it around to the beginning</li>
<li>if all frames have use bit 1, you will end up looping through all of them (and setting use bit 0 each time), and finally selecting the one that was pointed to at first</li>
</ul></li>
<li>2nd chance enhanced
<ul>
<li>also track dirty bit
<ul>
<li>dirty bit is only set when frame is written to (and thus the frame is dirty)</li>
</ul></li>
<li>also keep track of dirty frames separately, because we sometimes clear dirty bit in algorithm</li>
<li>choice at each step (bits are u,d)
<ul>
<li><table>
<thead>
<tr class="header">
<th>use, dirty</th>
<th>next</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1,1</td>
<td>0,1</td>
</tr>
<tr class="even">
<td>1,0</td>
<td>0,0</td>
</tr>
<tr class="odd">
<td>0,1</td>
<td>0,0*</td>
</tr>
<tr class="even">
<td>0,0</td>
<td>select as victim</td>
</tr>
</tbody>
</table></li>
<li>when going from 0,1 => 0,0* , you must list that page in the external dirty frames list, because it's still dirty, but it is now not indicated in bits</li>
</ul></li>
<li>the choice steps (above) mean that a dirty page will not be selected as victim until passed over twice
<ul>
<li>this is desirable because dirty frames incur a higher eviction penalty (they must be written to disk)</li>
</ul></li>
</ul></li>
</ul>
<h1 id="working-set-2-11">working set (2-11)</h1>
<ul>
<li>AKA resident set? TODO I think it's a little different</li>
<li>ideal resident set size changes dynamically as program runs
<ul>
<li>but we assume working set is constant</li>
</ul></li>
<li>all pages referenced within a specified time delta
<ul>
<li>because the process doesn't need all of it's pages at once</li>
</ul></li>
<li>rule
<ol style="list-style-type: decimal">
<li>at each reference, working set is determined, and only pages in virtual set are kept in memory</li>
<li>a program can only run if it's entire current resident set is in memory</li>
</ol></li>
<li>note: if all you reference is one page, working set eventually becomes only that page</li>
<li>removing frames
<ul>
<li>remove any frames last referenced longer than (time delta) time ago</li>
<li>victims are not overwritten immediately, instead are put into one of two lists:</li>
<li>free frame list
<ul>
<li>for clean frames (non-dirty) (frames that are ok to overwrite, as they are in sync with the swap)</li>
<li>OS can freely pick frames from here and use them</li>
</ul></li>
<li>modified frame list
<ul>
<li>dirty frames</li>
<li>periodically write these frames to disk, and then move them to the free frame list</li>
</ul></li>
</ul></li>
<li>when a frame not in the current working set is referenced, first check the free frame list and modified frame list
<ul>
<li>if the frame exists in either of those, you can simply reclaim it</li>
</ul></li>
<li>victims:
<ul>
<li>when looking for a victim, first get from free frame list
<ul>
<li>if free frame list is non-empty, just pick one and use it</li>
</ul></li>
<li>if free frame list is empty
<ul>
<li>pick from modified list, <strong>but write it to disk first</strong></li>
</ul></li>
</ul></li>
<li>case study: solaris page buffering
<ul>
<li>TODO do we need to know this?</li>
</ul></li>
<li>demand paging: TODO is this the same as working set?</li>
<li>demand paging on less sophisticated hardware
<ul>
<li>for when you don't have a hardware-managed valid bit?</li>
</ul></li>
</ul>
<h1 id="recursive-paging-17-2-12">recursive paging (17, 2-12)</h1>
<ul>
<li>in x86</li>
<li>allows you to modify page directory and page table entries without mapping them into virtual memory</li>
<li>set the last entry of the page directory to the physical address of the page directory</li>
<li>access <code>n</code>th entry of page directory: use address <code>| 1023 | 1023 | n | 00 |</code>
<ul>
<li><code>1023</code> and <code>n</code> are both 10 bits</li>
</ul></li>
<li>access <code>a</code>th entry of <code>b</code>th page table: use address <code>| 1023 | b | a | 00 |</code>
<ul>
<li><code>1023</code>, <code>a</code>, and <code>b</code> are all 10 bits</li>
</ul></li>
</ul>
</body>
</html>