-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathecen454_refsheet.md.html
734 lines (734 loc) · 116 KB
/
ecen454_refsheet.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
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
<!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" />
<meta name="author" content="https://github.com/joshua-wright" />
<title>ECEN454 refsheet</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>
<div id="header">
<h1 class="title">ECEN454 refsheet</h1>
<h2 class="author">https://github.com/joshua-wright</h2>
</div>
<h1 id="specifically-for-final">specifically for final</h1>
<ul>
<li>exam 1 was on March 8 (2017.03.08)</li>
<li>nothing specifically from previous exam</li>
<li>HW6 was due on March 8, so exam is HW7-HW11</li>
</ul>
<h1 id="propagation-vs-contamination-delay">Propagation vs Contamination delay</h1>
<ul>
<li>contamination delay (<span class="math inline">\(t_{cd}\)</span>): time from input change to <strong>any</strong> output changing value
<ul>
<li>kind of a best-case delay or smallest possible delay</li>
<li>time counted when input crosses 50% of logical high voltage level</li>
</ul></li>
<li>propagation delay: time from when all inputs are stable to when all outputs are stable
<ul>
<li>kind of like a worst-case delay</li>
</ul></li>
</ul>
<h1 id="static-vs-dynamic-power">static vs dynamic power</h1>
<ul>
<li>static power
<ul>
<li>consumed when circuit is not active</li>
<li>e.g. leakage current</li>
<li>static because no inputs are changing</li>
</ul></li>
<li>dynamic power
<ul>
<li>power consumed due to gates switching and stuff</li>
<li>e.g. charging/discharging parasitic caps, etc...</li>
</ul></li>
</ul>
<h1 id="latch-vs-flip-flop">Latch vs Flip Flop</h1>
<ul>
<li>Latch is level-sensitive, flip-flop is edge-sensitive</li>
<li>register is flip-flop</li>
</ul>
<h1 id="latchflip-flop-designs">Latch/flip flop designs</h1>
<ul>
<li>pass transistor latch
<ul>
<li>pros: tiny, low clock load</li>
<li>con: voltage drop across is <span class="math inline">\(V_t\)</span>, it's non-restoring</li>
<li>con: not really a latch because doesn't hold signal</li>
</ul></li>
<li>transmission gate
<ul>
<li>pro: no <span class="math inline">\(V_t\)</span> drop</li>
<li>con: requires inverted clock</li>
</ul></li>
<li>inverting buffer
<ul>
<li>TODO</li>
</ul></li>
<li>tristate feedback
<ul>
<li>first complete latch here</li>
<li>risk of backdriving: downstream could change state if it is very strong</li>
</ul></li>
<li>buffered output
<ul>
<li>no backdrifing problem</li>
<li>widely used</li>
<li>rather large and slow though, and large load on clock</li>
</ul></li>
<li>a flip-flop is just two latches back-to-back</li>
</ul>
<h1 id="metastability">Metastability</h1>
<ul>
<li>stable works if it's not at a strong high or low but will settle somewhere</li>
<li>metastable is where it might sit there, but if it must settle, you don't know which one it will settle to when perturbed</li>
</ul>
<h2 id="section">2017.03.22</h2>
<h1 id="interconnect">Interconnect</h1>
<ul>
<li>contacts
<ul>
<li>have resistance <span class="math inline">\(2-20\Omega\)</span></li>
<li>so use a bunch of them to reduce resistance between layers</li>
</ul></li>
<li>lumped RC model
<ul>
<li>when you lump together RC sections for speed</li>
<li><span class="math inline">\(\pi\)</span>-model (pi-model) is most commonly used</li>
</ul></li>
<li>distributed RC model: opposite of lumped model</li>
<li>crosstalk
<ul>
<li>caused by parasitic cap between wires</li>
<li>one wire changing voltage can induce noise on adjacent wires and/or increase delay</li>
</ul></li>
</ul>
<table>
<thead>
<tr class="header">
<th>B</th>
<th><span class="math inline">\(\Delta V\)</span></th>
<th><span class="math inline">\(C_{eff}(A)\)</span></th>
<th>MCF</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Constant</td>
<td><span class="math inline">\(V_{DD}\)</span></td>
<td><span class="math inline">\(C_{gnd} + C_{adj}\)</span></td>
<td>1</td>
</tr>
<tr class="even">
<td>With A</td>
<td>0</td>
<td><span class="math inline">\(C_{gnd}\)</span></td>
<td>0</td>
</tr>
<tr class="odd">
<td>Opposite A</td>
<td><span class="math inline">\(2V_{DD}\)</span></td>
<td><span class="math inline">\(C_{gnd} + 2C_{adj}\)</span></td>
<td>2</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>MCF: Miller Effect</strong>: effect of crosstalk
<ul>
<li>quantifies crosstalk delay</li>
<li>use MCF factor to determine effective parasitic capacitance between two signal wires</li>
</ul></li>
<li>Elmore delay: split into segments and use pi-model (or some other model)
<ul>
<li>wire delay is quadratically proportional to length of wire</li>
<li>by each C: <span class="math inline">\(t_{pd} = \sum_{i:=caps}\)</span> <span class="math inline">\(R_{i-to-source} C_i\)</span></li>
<li>by each R: <span class="math inline">\(t_{pd} = \sum_{i:=resistors}\)</span> <span class="math inline">\(R_i C_{downstream}\)</span>
<ul>
<li>downstream capacitors: if the cap is not along the direct path between the source and the point you're interested in, you just ignore that R for some reason (based on HW)</li>
</ul></li>
</ul></li>
<li>repeaters/buffers:
<ul>
<li>worth it only if wire is sufficiently long</li>
<li><span class="math inline">\(t_{unbuf} = R(cx + C) + rx(cx/2 + C)\)</span></li>
<li><span class="math inline">\(t_{buf} = 2R(cx/2 + C) + rx(cx/4 + C) + t_b\)</span>
<ul>
<li><span class="math inline">\(x\)</span>: wire length</li>
<li><span class="math inline">\(R\)</span>: buffer output resistance</li>
<li><span class="math inline">\(C\)</span>: buffer input capacitance</li>
<li><span class="math inline">\(r\)</span>: wire unit length resistance</li>
<li><span class="math inline">\(c\)</span>: wire unit length capacitance</li>
<li><span class="math inline">\(t_b\)</span>: buffer delay time</li>
</ul></li>
<li>time difference: <span class="math inline">\(\Delta t = t_{buf} - t_{unbuf} = RC + t_b - rcx^2/4\)</span></li>
<li>buffers help slack because they decouple parasitic capacitance</li>
</ul></li>
</ul>
<h2 id="section-1">2017.03.27</h2>
<h1 id="sequential-circuits">Sequential Circuits</h1>
<ul>
<li>sequential means that the circuit holds state: the output depends on both current and past input</li>
<li>to model a state machine, you can unroll it to [register] <span class="math inline">\(\rightarrow\)</span> [combinational] <span class="math inline">\(\rightarrow\)</span> ...
<ul>
<li>this way you can use regular timing stuff for it: arrival time, slack, etc...</li>
</ul></li>
<li>Mealy FSM: output of circuit is from combinational logic</li>
<li>Moore FSM: output is from registers</li>
<li>pipelined circuit: uses registers to hold state between clock cycles, because not all of the combinational logic can happen fast enough to work in a single clock cycle
<ul>
<li>pipelined circuits can use flip-flops or latches?</li>
</ul></li>
<li>the clock consumes 20-30% of the power on a chip</li>
<li>the whole reason that registers are needed is because data (signals) moves through components at non-constant speed</li>
<li>reset
<ul>
<li>can be sync or async</li>
<li>force low output when reset is high</li>
</ul></li>
<li>sequencing: it is (generally) equivalent to split the sequential logic in two, and then use two latches (one halfway through) instead of one large section of sequential logic with flip-flops at either end
<ul>
<li>this is called two phase clocking</li>
<li>you have to make sure the middle latch operates on clock-bar instead of clock</li>
</ul></li>
</ul>
<table>
<thead>
<tr class="header">
<th>symbol</th>
<th>definition</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><span class="math inline">\(t_{pd}\)</span></td>
<td>logic propagation delay</td>
</tr>
<tr class="even">
<td><span class="math inline">\(t_{cd}\)</span></td>
<td>logic contamination delay</td>
</tr>
<tr class="odd">
<td><span class="math inline">\(t_{pcq}\)</span></td>
<td>Clk<span class="math inline">\(\rightarrow\)</span>Q propagation delay</td>
</tr>
<tr class="even">
<td><span class="math inline">\(t_{ccq}\)</span></td>
<td>Clk<span class="math inline">\(\rightarrow\)</span>Q contamination delay</td>
</tr>
<tr class="odd">
<td><span class="math inline">\(t_{pdq}\)</span></td>
<td>D<span class="math inline">\(\rightarrow\)</span>Q propagation delay</td>
</tr>
<tr class="even">
<td><span class="math inline">\(t_{setup}\)</span></td>
<td>setup time of flip-flop/latch</td>
</tr>
<tr class="odd">
<td><span class="math inline">\(t_{hold}\)</span></td>
<td>hold time of flip-flop/latch</td>
</tr>
</tbody>
</table>
<ul>
<li>timing:
<ul>
<li>D<span class="math inline">\(\rightarrow\)</span>Q delay only makes sense for latches, since for flip-flops it is simply one clock cycle</li>
</ul></li>
<li>sequencing overhead and max delay:
<ul>
<li><span class="math inline">\(T_c\)</span>: cycle time</li>
<li>need for combinational logic to be fast enough</li>
<li>for single phase flip flop: <span class="math inline">\(t_{pd} < T_c - (T_{setup} + T_{pcq})\)</span></li>
<li>for two-phase latch: <span class="math inline">\(t_{pd} = t_{pd1} + t_{pd2} < T_c - 2t_{pdq}\)</span></li>
<li>max delay is dictated by cycle time and sequencing overhead; sequencing overhead does not effect minimum delay</li>
</ul></li>
<li>minimum delay:
<ul>
<li>for single phase flip flop: <span class="math inline">\(t_{cd} > t_{hold} - t_{ccq}\)</span>
<ul>
<li>combinational stuff must be slow enough that it doesn't violate hold time of second flip flop</li>
</ul></li>
<li>for two-phase latch: <span class="math inline">\(t_{cd1},t_{cd2} > t_{hold} - t_{ccq} - t_{non-overlap}\)</span>
<ul>
<li>hold time applies twice each cycle, once per each combinational circuit</li>
<li><span class="math inline">\(t_{non-overlap}\)</span>: phase between clock signals</li>
</ul></li>
</ul></li>
<li>time borrowing: for two-phase latch-based system, you can borrow time from one segment to the other while the latch is transparent
<ul>
<li>works (is possible) as long as the total circuit still completes within one clock cycle</li>
<li>will need to change the phase the phase of the second clock</li>
</ul></li>
<li>clock skew:
<ul>
<li>when uncertain: causes tighter required CL propagation delay and minimum CL contamination delay, and reduces opportunity for time borrowing.</li>
<li>when know constant skew: can help with same effect as time borrowing, except it can also work for flip-flop based systems</li>
</ul></li>
<li>skew tolerance:
<ul>
<li>flip-flop circuits are not very skew tolerant because the setup and hold times define a specific window of time in which the data must arrive</li>
<li>latch circuits are more hold-time-tolerant because the data can arrive any time that the latch is transparent</li>
</ul></li>
<li>if setup times are violated, you can reduce clock speed to fix it</li>
<li>if hold times are violated, it won't work at any clock speed</li>
</ul>
<h2 id="section-2">2017.03.29</h2>
<h1 id="clocking">Clocking</h1>
<ul>
<li>H-Tree (clock distribution network)
<ul>
<li>laid out in such a way that the delay from the center to any leaf node is equal</li>
<li>if you're missing one of the nodes, just don't draw that part. Make sure the rest of the H-tree is the exact same shape though, so that the distances are the same</li>
</ul></li>
<li>Grid clock distribution
<ul>
<li>grid on two or more levels</li>
<li>ensures low local skew, but there could still be larger chip-wide skew</li>
</ul></li>
<li>generally, the longer the delay between two point, the larger the worst-case clock skew</li>
<li>Domino circuit: TODO
<ul>
<li>a kind of dynamic logic</li>
<li>when the clock pulse cascades through the circuit, activating the pMOS at each stage?</li>
</ul></li>
</ul>
<h2 id="more">2017.04.03 (+more)</h2>
<h1 id="memory">Memory</h1>
<ul>
<li>random access or sequential access, or content addressable</li>
<li>CAM: content-addressable memory
<ul>
<li>basically like an associative array, or database</li>
<li>designed to search all memory at once in a single operation (wikipedia)</li>
<li>used in caches</li>
</ul></li>
<li>SRAM:
<ul>
<li>12T and 6T cell designs</li>
<li>12T design: just a latch connected to a bitline
<ul>
<li>boring and impractical because it's too large</li>
</ul></li>
<li>6T design: cross-coupled inverters (3T each) +2T for bit and bit-bar lines
<ul>
<li>we focus on 6T design</li>
</ul></li>
<li>read: pre-charge bit and bit-bar, raise wordline, read result
<ul>
<li>need to pre-charge both bit and bit-bar to 1 or else read is destructive</li>
<li>need sense amplifiers at the end of the bitlines because the signal will be weak</li>
<li>the parasitic capacitance of the bitline depends on how many cells are 0 or 1</li>
</ul></li>
<li>write: drive data onto bit and bit-bar and raise wordline to write</li>
<li>cross coupled inverters must be much larger than the bitline transistors so that it doesn't flip while reading</li>
<li>per each column, you need:
<ul>
<li>piece of decoder</li>
<li>bitline sense amplifier</li>
<li>column multiplexer</li>
</ul></li>
<li>multi-port: means you can read from and write to the same cell in the same clock cycle and it works
<ul>
<li>implement by having multiple sequential read/write per cycle?</li>
</ul></li>
</ul></li>
<li>decoders:
<ul>
<li>must be pitch-matched to SRAM cell width for layout efficiency/simplicity (requires very skinny gates)</li>
<li>large (<span class="math inline">\(n>4\)</span>) decoders are inefficient, thus it is often helpful to use predecoding: factor out common gates into a second stage of decoders.
<ul>
<li>smaller area as alternative, but same logical effort (since same number of gates traversed)</li>
</ul></li>
</ul></li>
<li>twisted bitlines: bitlines are long and right next to each other, so there will be significant crosstalk and parasitic cap
<ul>
<li>solution: swap adjacent bit and bit-bar lines occasionally</li>
<li>reduces Miller factor (MCF)</li>
</ul></li>
<li>DRAM:
<ul>
<li>one transistor and one capacitor
<ul>
<li>transistor gates capacitor</li>
</ul></li>
<li>no charge is 0, charge is 1</li>
<li>open transistor to read/write</li>
<li>read is destructive</li>
<li>must be refreshed periodically due to leakage
<ul>
<li>thus, it's always consuming power</li>
</ul></li>
</ul></li>
<li>shift register:
<ul>
<li>can be implemented with cascade of flip-flops
<ul>
<li>can lead to hold time violations because no delay from clock to next data line
<ul>
<li>problems when the Clk<span class="math inline">\(\rightarrow\)</span>Q time is less than the hold time of the flip-flop</li>
</ul></li>
<li>not very dense</li>
</ul></li>
<li>store data in SRAM and store begin/end pointers
<ul>
<li>more dense than individual flip-flops</li>
</ul></li>
</ul></li>
<li>Tapped Delay Line
<ul>
<li>shift register with programmable number of stages</li>
<li>implement using sequence of flip-flops, each with a bypass MUX from data in to out</li>
</ul></li>
<li>Queues: are a thing (TODO)</li>
<li>ROM: Read Only Memory:
<ul>
<li>mask-programmed ROMs are one transistor per bit</li>
</ul></li>
<li>PROMs, EPROMS, etc
<ul>
<li>generally burn out specific fuses to program ROM</li>
<li>E for erasable</li>
</ul></li>
</ul>
<h2 id="section-3">2017.04.10, 2017.04.12</h2>
<h1 id="low-power-design">Low Power Design</h1>
<ul>
<li>not so useful when running from a battery since batteries store energy, not power
<ul>
<li>doing the same computation slower will use the same energy from the battery (generally)</li>
</ul></li>
<li>peak power
<ul>
<li>determines power/ground wiring and packaging limits</li>
<li>impacts signal/noise ratio</li>
</ul></li>
<li>reduce dynamic power: (AKA active power)
<ul>
<li>use smaller transistors</li>
<li>clock gating</li>
<li>reduce <span class="math inline">\(V_{DD}\)</span></li>
<li>reduce frequency
<ul>
<li>but be careful because that will make the computations take longer</li>
</ul></li>
</ul></li>
<li>reduce static power
<ul>
<li>power gating</li>
<li>selectively use lower <span class="math inline">\(V_{DD}\)</span> devices</li>
<li>stacked devices</li>
<li>body bias</li>
</ul></li>
<li>clock gating: disable the clock signal to an expensive component
<ul>
<li>eliminates that component's dynamic power (but of course you can't use it)</li>
<li>doesn't change static power</li>
</ul></li>
<li>voltage islands: different <span class="math inline">\(V_{DD}\)</span> for different devices
<ul>
<li>allow low <span class="math inline">\(V_{DD}\)</span> devices to run slower because they don't need to be fast (maybe they're not in the critical path)</li>
<li>often different voltage levels are alternated row by row in standard-cell layouts</li>
<li>you must convert from one logic level to another, because high/low will be different
<ul>
<li>sometimes it's possible to avoid conversion, e.g. by using a buffer that you would have anyway, with inverters built from half high-<span class="math inline">\(V_{DD}\)</span> transistors and half low-<span class="math inline">\(V_{DD}\)</span> transistors</li>
</ul></li>
<li>there are all kinds of tricks for determining which components should be high/low voltage and where to put voltage islands and level converters</li>
</ul></li>
<li>DFVS: Dynamic Frequency and Voltage Scaling
<ul>
<li>requires:
<ul>
<li>programmable clock generator (PLL)</li>
<li>supply regulation loop to for setting minimum <span class="math inline">\(V_{DD}\)</span></li>
<li>software support for deciding best stable frequency and voltage for given load and performance goals</li>
</ul></li>
<li>voltage regulation loop (charge pump)
<ul>
<li>voltage divider would be horribly inefficient</li>
<li>instead, rapidly charge/discharge capacitor</li>
</ul></li>
</ul></li>
<li>stacked devices:
<ul>
<li>stacking devices reduces leakage</li>
<li>because leakage is exponentially proportional to <span class="math inline">\(V_{ds}\)</span></li>
</ul></li>
<li>body bias AKA dual <span class="math inline">\(V_t\)</span>
<ul>
<li>changing <span class="math inline">\(V_t\)</span> at runtime is called Adaptive Body-Biasing (ABB) or Dynamic Threshold Scaling (DTS)
<ul>
<li>requires triple well fabrication process, because what would have been lowest level substrate must itself sit inside a well that will be biased</li>
</ul></li>
<li>design with low and high <span class="math inline">\(V_t\)</span></li>
<li>low <span class="math inline">\(V_t\)</span> is faster than high <span class="math inline">\(V_t\)</span> but consumes 10x more power
<ul>
<li>because reducing <span class="math inline">\(V_t\)</span> increases sub-threshold leakage exponentially</li>
<li>but reducing <span class="math inline">\(V_t\)</span> decreases gate delay (increasing performance)</li>
</ul></li>
<li>to increase <span class="math inline">\(V_t\)</span>, put a negative bias on <span class="math inline">\(V_{SB}\)</span> of nMOS
<ul>
<li>use DC charge pump to get desired voltage</li>
</ul></li>
</ul></li>
<li>power gating: use sleep transistors
<ul>
<li>basically cut off <span class="math inline">\(V_{DD}\)</span> from power-hungry circuits when not in use</li>
<li>in sleep mode, the sleeping transistors are stacked with the transistors that are causing them to sleep, thus reducing leakage even more</li>
</ul></li>
<li>MTCMOS sleep transistors
<ul>
<li>combines power gating and dual <span class="math inline">\(V_t\)</span></li>
<li>TODO what is this?</li>
</ul></li>
</ul>
<h2 id="section-4">2017.04.17</h2>
<h1 id="packaging">Packaging</h1>
<ul>
<li>provides:
<ul>
<li>heat dispersion</li>
<li>mechanical stability</li>
<li>prevent thermal expansion</li>
<li>IO</li>
</ul></li>
<li>SMD: Surface Mount Device</li>
<li>SMT: Surface Mount Technology</li>
<li>package types
<ul>
<li>DIP: Dual In-line Package</li>
<li>QFP: Quad Flat Package</li>
<li>PLCC: Plastic leaded chip Carrier</li>
<li>BGA: Ball Grid Array</li>
<li>PGA: Pin Grid Array</li>
<li>MCM: Multi Chip Module</li>
</ul></li>
<li>DIP: Dual In-line Package
<ul>
<li>basic chip with two sides and pins pointing either down (through hole) or out to the sides (surface mount)</li>
</ul></li>
<li>QFP: Quad Flat Package
<ul>
<li>looks about the same as DIP with SMD pins but has pins pointing out of all 4 sides</li>
</ul></li>
<li>PLCC: Plastic leaded chip Carrier
<ul>
<li>like QFP but instead of pins has tiny pads (J-leads) on perimeter of chip.</li>
<li>can sit in a socket with spring connectors that contact those pads</li>
</ul></li>
<li>BGA: Ball Grid Array
<ul>
<li>can have lots of pins</li>
<li>can attach to substrate with flip chip or wires</li>
<li>underside has pads for where solder balls go to connect to board</li>
</ul></li>
<li>PGA: Pin Grid Array
<ul>
<li>like BGA but with pins</li>
</ul></li>
<li>MCM: Multi Chip Module
<ul>
<li>when you put multiple dies on a single chip</li>
<li>advantage over very large single die: you can then select just the working ones of each die component</li>
<li>disadvantage: means you'll probably want to test chips before you package them</li>
</ul></li>
<li>flip-chip
<ul>
<li>also called C4: Controlled Collapse Chip Connection</li>
<li>just flip the chip over, thus placing the connecting pads on the highest metal layer</li>
<li>affix chip to package using a BGA-style connection</li>
<li>advantages
<ul>
<li>higher pin density</li>
<li>can put pins anywhere without worrying about routing</li>
</ul></li>
</ul></li>
<li>package parasitics
<ul>
<li>parasitics inductance isn't really a problem inside the chip, but is for connecting wires in packaging</li>
</ul></li>
<li>heat dissipation
<ul>
<li>formula: <span class="math inline">\(\Delta T = \theta_{ja} P\)</span>
<ul>
<li><span class="math inline">\(\Delta T\)</span>: change in temperature on chip</li>
<li><span class="math inline">\(\theta_{ja}\)</span>: thermal resistance of chip junction to ambient</li>
<li><span class="math inline">\(P\)</span>: power dissipation on chip</li>
<li><span class="math inline">\(\theta\)</span> adds in series for chip<span class="math inline">\(\rightarrow\)</span>package and package<span class="math inline">\(\rightarrow\)</span>headsink</li>
</ul></li>
<li>must cool chip to avoid things like thermal resistance and electro-migration</li>
<li>thermal resistance can cause the chip to fail, but that's only temporary
<ul>
<li>should work again after cooling</li>
</ul></li>
<li>electro-migration: electrons moving where they shouldn't inside the chip
<ul>
<li>permanent build-up of problem</li>
</ul></li>
</ul></li>
<li>power distribution
<ul>
<li>want to minimize power noise</li>
<li>voltage will drop due to
<ul>
<li><span class="math inline">\(IR\)</span> drop</li>
<li><span class="math inline">\(L*(di/dt)\)</span> noise (from parasitics inductance)</li>
</ul></li>
<li>decoupling capacitors
<ul>
<li>aka bypass caps</li>
<li>cap between <span class="math inline">\(V_{DD}\)</span> and ground to smooth out voltage supply</li>
<li>use multiple caps in series to avoid problems with the resonant frequency of any single cap</li>
</ul></li>
</ul></li>
<li>I/O
<ul>
<li>must protect against ESD</li>
<li>pad types:
<ul>
<li><span class="math inline">\(V_{DD}\)</span>/GND</li>
<li>output</li>
<li>input</li>
<li>bidirectional</li>
<li>analog</li>
</ul></li>
<li>latch-up
<ul>
<li>when noise or density or something causes transistors to do weird things or something</li>
<li>TODO</li>
</ul></li>
<li>output
<ul>
<li>need to drive relatively large off-chip loads, so usually require chain of successively larger buffers</li>
<li>protect against latch-up using guard ring: p+ inner ring and n+ outer ring (in n-well)</li>
</ul></li>
<li>input
<ul>
<li>must do level conversion</li>
<li>must filter noise
<ul>
<li>use Schmitt trigger: basically doesn't cross threshold unless extra oomph provided (it's sticky)</li>
</ul></li>
</ul></li>
<li>bidirectional
<ul>
<li>combined input/output pad</li>
<li>chip has enable signal to decide direction</li>
</ul></li>
<li>analog
<ul>
<li>must avoid distorting or delaying the signal at all (no buffering)</li>
<li>ESD protection circuit must not distort the signal</li>
</ul></li>
</ul></li>
<li>ESD protection: TODO
<ul>
<li>ESD: Electro-Static Discharge</li>
<li>can damage circuits with too much current and voltage</li>
<li>limit current using resistor in series</li>
<li>limit voltage using two diodes:
<ul>
<li>one from ground to signal line (pointing toward signal line),</li>
<li>one from signal line to <span class="math inline">\(V_{DD}\)</span> (pointing toward <span class="math inline">\(V_{DD}\)</span>)</li>
</ul></li>
</ul></li>
<li>MOSIS IO pads
<ul>
<li>library of IO pad designs</li>
<li>provides IO protection and stuff</li>
</ul></li>
</ul>
<h2 id="section-5">2017.04.26</h2>
<h1 id="testing">Testing</h1>
<ul>
<li>logic verification is very important
<ul>
<li>consumes 50% of total IC development time</li>
</ul></li>
<li>3 types:
<ul>
<li>LV: Logic Verification</li>
<li>SD: Silicon Debug</li>
<li>MT: Manufacturing Test</li>
</ul></li>
<li>LV: Logic Verification
<ul>
<li>simulate chip and see if implementation is correct (does what expected)</li>
<li>when you can't test every possible combination (because too many bits and/or too much state), test edge cases</li>
</ul></li>
<li>SD: Silicon Debug
<ul>
<li>test fabricated chips</li>
<li>check for logic failures and electrical failures</li>
<li>logic: bad implementation</li>
<li>electrical: crosstalk, leakage, charge sharing, etc...</li>
<li>fixing bugs requires redesigning and re-fabricating the chip</li>
</ul></li>
<li>MT: Manufacturing Test
<ul>
<li>check that the chip was fabricated without error
<ul>
<li>e.g. no speck of dust came in and killed the chip</li>
</ul></li>
<li>yield is always <100% because fabrication is never perfect</li>
<li>testing machines are super expensive so you gotta balance number of test cases (test coverage) vs cost</li>
</ul></li>
<li>Smoo Plot
<ul>
<li>used to diagnose chip failures</li>
<li>2D plot of frequency vs <span class="math inline">\(V_{DD}\)</span></li>
<li>X or not depending if chip passed test at that frequency and supply voltage</li>
<li>can help to tell what is causing failures</li>
</ul></li>
<li>stuck-at fault
<ul>
<li>model a failure as stuck at 0 or 1</li>
<li>there's a whole bunch of ways that silicon could be manufactured incorrectly, but stuck-at fault models most of these approximately right</li>
</ul></li>
<li>observability: how easy it it is to observe a node at the output
<ul>
<li>to observe a node at the output, the output must be determined by that node</li>
</ul></li>
<li>controllability: how easy it is to force a node to a specific value</li>
<li>combinational logic has good observability and controllability, finite state machines (FSMs) do not</li>
<li>test pattern generation:
<ul>
<li>apply smallest possible sequence of test vectors necessary to show that each node is not stuck</li>
<li>circuits with better controllability and observability are more testable (can be fully tested with fewer test patterns)</li>
</ul></li>
<li>scan register, scan chain
<ul>
<li>add a mux to the input of all registers, linking them together in a big optional shift register</li>
<li>then you can shift pre-defined values into all registers for testing, and shift out the test results</li>
<li>makes the circuit more testable</li>
</ul></li>
<li>ATPG: Automatic Test Pattern Generation
<ul>
<li>given blocks of combinational logic, generates test patterns for use with scan chains</li>
</ul></li>
<li>built in self test
<ul>
<li>circuits that test themselves using built-in test pattern generators and verifiers</li>
</ul></li>
<li>PRSG: Pseudo-Random Sequence Generator
<ul>
<li>just a linear feedback shift register with input as XOR of state</li>
<li>used for random testing</li>
</ul></li>
<li>BILBO: Built-in Logic Block Observer
<ul>
<li>automatic tester</li>
</ul></li>
<li>boundary scan
<ul>
<li>basically a scan chain for all the pins (boundaries)</li>
<li>because some packaging types (e.g. BGA) are hard to make temporary sockets for</li>
</ul></li>
</ul>
</body>
</html>