forked from underscoreio/shapeless-guide
-
Notifications
You must be signed in to change notification settings - Fork 2
/
shapeless-guide.html
2178 lines (2015 loc) · 807 KB
/
shapeless-guide.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
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!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 http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="pandoc" />
<meta name="author" content="Dave Gurnell" />
<title>The Type Astronaut’s Guide to Shapeless</title>
<link href="data:text/css;charset=utf-8,%0Ahtml%20%7B%0Afont%2Dfamily%3A%20sans%2Dserif%3B%0A%2Dms%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%0A%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A%20100%25%3B%0A%7D%0Abody%20%7B%0Amargin%3A%200%3B%0A%7D%0Aarticle%2C%0Aaside%2C%0Adetails%2C%0Afigcaption%2C%0Afigure%2C%0Afooter%2C%0Aheader%2C%0Ahgroup%2C%0Amain%2C%0Amenu%2C%0Anav%2C%0Asection%2C%0Asummary%20%7B%0Adisplay%3A%20block%3B%0A%7D%0Aaudio%2C%0Acanvas%2C%0Aprogress%2C%0Avideo%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Avertical%2Dalign%3A%20baseline%3B%0A%7D%0Aaudio%3Anot%28%5Bcontrols%5D%29%20%7B%0Adisplay%3A%20none%3B%0Aheight%3A%200%3B%0A%7D%0A%5Bhidden%5D%2C%0Atemplate%20%7B%0Adisplay%3A%20none%3B%0A%7D%0Aa%20%7B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0Aa%3Aactive%2C%0Aa%3Ahover%20%7B%0Aoutline%3A%200%3B%0A%7D%0Aabbr%5Btitle%5D%20%7B%0Aborder%2Dbottom%3A%201px%20dotted%3B%0A%7D%0Ab%2C%0Astrong%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Adfn%20%7B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0Ah1%20%7B%0Afont%2Dsize%3A%202em%3B%0Amargin%3A%200%2E67em%200%3B%0A%7D%0Amark%20%7B%0Abackground%3A%20%23ff0%3B%0Acolor%3A%20%23000%3B%0A%7D%0Asmall%20%7B%0Afont%2Dsize%3A%2080%25%3B%0A%7D%0Asub%2C%0Asup%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%0Aimg%20%7B%0Aborder%3A%200%3B%0A%7D%0Asvg%3Anot%28%3Aroot%29%20%7B%0Aoverflow%3A%20hidden%3B%0A%7D%0Afigure%20%7B%0Amargin%3A%201em%2040px%3B%0A%7D%0Ahr%20%7B%0A%2Dmoz%2Dbox%2Dsizing%3A%20content%2Dbox%3B%0Abox%2Dsizing%3A%20content%2Dbox%3B%0Aheight%3A%200%3B%0A%7D%0Apre%20%7B%0Aoverflow%3A%20auto%3B%0A%7D%0Acode%2C%0Akbd%2C%0Apre%2C%0Asamp%20%7B%0Afont%2Dfamily%3A%20monospace%2C%20monospace%3B%0Afont%2Dsize%3A%201em%3B%0A%7D%0Abutton%2C%0Ainput%2C%0Aoptgroup%2C%0Aselect%2C%0Atextarea%20%7B%0Acolor%3A%20inherit%3B%0Afont%3A%20inherit%3B%0Amargin%3A%200%3B%0A%7D%0Abutton%20%7B%0Aoverflow%3A%20visible%3B%0A%7D%0Abutton%2C%0Aselect%20%7B%0Atext%2Dtransform%3A%20none%3B%0A%7D%0Abutton%2C%0Ahtml%20input%5Btype%3D%22button%22%5D%2C%0Ainput%5Btype%3D%22reset%22%5D%2C%0Ainput%5Btype%3D%22submit%22%5D%20%7B%0A%2Dwebkit%2Dappearance%3A%20button%3B%0Acursor%3A%20pointer%3B%0A%7D%0Abutton%5Bdisabled%5D%2C%0Ahtml%20input%5Bdisabled%5D%20%7B%0Acursor%3A%20default%3B%0A%7D%0Abutton%3A%3A%2Dmoz%2Dfocus%2Dinner%2C%0Ainput%3A%3A%2Dmoz%2Dfocus%2Dinner%20%7B%0Aborder%3A%200%3B%0Apadding%3A%200%3B%0A%7D%0Ainput%20%7B%0Aline%2Dheight%3A%20normal%3B%0A%7D%0Ainput%5Btype%3D%22checkbox%22%5D%2C%0Ainput%5Btype%3D%22radio%22%5D%20%7B%0Abox%2Dsizing%3A%20border%2Dbox%3B%0Apadding%3A%200%3B%0A%7D%0Ainput%5Btype%3D%22number%22%5D%3A%3A%2Dwebkit%2Dinner%2Dspin%2Dbutton%2C%0Ainput%5Btype%3D%22number%22%5D%3A%3A%2Dwebkit%2Douter%2Dspin%2Dbutton%20%7B%0Aheight%3A%20auto%3B%0A%7D%0Ainput%5Btype%3D%22search%22%5D%20%7B%0A%2Dwebkit%2Dappearance%3A%20textfield%3B%0A%2Dmoz%2Dbox%2Dsizing%3A%20content%2Dbox%3B%0A%2Dwebkit%2Dbox%2Dsizing%3A%20content%2Dbox%3B%0Abox%2Dsizing%3A%20content%2Dbox%3B%0A%7D%0Ainput%5Btype%3D%22search%22%5D%3A%3A%2Dwebkit%2Dsearch%2Dcancel%2Dbutton%2C%0Ainput%5Btype%3D%22search%22%5D%3A%3A%2Dwebkit%2Dsearch%2Ddecoration%20%7B%0A%2Dwebkit%2Dappearance%3A%20none%3B%0A%7D%0Afieldset%20%7B%0Aborder%3A%201px%20solid%20%23c0c0c0%3B%0Amargin%3A%200%202px%3B%0Apadding%3A%200%2E35em%200%2E625em%200%2E75em%3B%0A%7D%0Alegend%20%7B%0Aborder%3A%200%3B%0Apadding%3A%200%3B%0A%7D%0Atextarea%20%7B%0Aoverflow%3A%20auto%3B%0A%7D%0Aoptgroup%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Atable%20%7B%0Aborder%2Dcollapse%3A%20collapse%3B%0Aborder%2Dspacing%3A%200%3B%0A%7D%0Atd%2C%0Ath%20%7B%0Apadding%3A%200%3B%0A%7D%0A%0A%40media%20print%20%7B%0A%2A%2C%0A%2A%3Abefore%2C%0A%2A%3Aafter%20%7B%0Abackground%3A%20transparent%20%21important%3B%0Acolor%3A%20%23000%20%21important%3B%0Abox%2Dshadow%3A%20none%20%21important%3B%0Atext%2Dshadow%3A%20none%20%21important%3B%0A%7D%0Aa%2C%0Aa%3Avisited%20%7B%0Atext%2Ddecoration%3A%20underline%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%0Aa%5Bhref%5E%3D%22%23%22%5D%3Aafter%2C%0Aa%5Bhref%5E%3D%22javascript%3A%22%5D%3Aafter%20%7B%0Acontent%3A%20%22%22%3B%0A%7D%0Apre%2C%0Ablockquote%20%7B%0Aborder%3A%201px%20solid%20%23999%3B%0Apage%2Dbreak%2Dinside%3A%20avoid%3B%0A%7D%0Athead%20%7B%0Adisplay%3A%20table%2Dheader%2Dgroup%3B%0A%7D%0Atr%2C%0Aimg%20%7B%0Apage%2Dbreak%2Dinside%3A%20avoid%3B%0A%7D%0Aimg%20%7B%0Amax%2Dwidth%3A%20100%25%20%21important%3B%0A%7D%0Ap%2C%0Ah2%2C%0Ah3%20%7B%0Aorphans%3A%203%3B%0Awidows%3A%203%3B%0A%7D%0Ah2%2C%0Ah3%20%7B%0Apage%2Dbreak%2Dafter%3A%20avoid%3B%0A%7D%0Aselect%20%7B%0Abackground%3A%20%23fff%20%21important%3B%0A%7D%0A%2Enavbar%20%7B%0Adisplay%3A%20none%3B%0A%7D%0A%2Ebtn%20%3E%20%2Ecaret%2C%0A%2Edropup%20%3E%20%2Ebtn%20%3E%20%2Ecaret%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23000%20%21important%3B%0A%7D%0A%2Elabel%20%7B%0Aborder%3A%201px%20solid%20%23000%3B%0A%7D%0A%2Etable%20%7B%0Aborder%2Dcollapse%3A%20collapse%20%21important%3B%0A%7D%0A%2Etable%20td%2C%0A%2Etable%20th%20%7B%0Abackground%2Dcolor%3A%20%23fff%20%21important%3B%0A%7D%0A%2Etable%2Dbordered%20th%2C%0A%2Etable%2Dbordered%20td%20%7B%0Aborder%3A%201px%20solid%20%23ddd%20%21important%3B%0A%7D%0A%7D%0A%2A%20%7B%0A%2Dwebkit%2Dbox%2Dsizing%3A%20border%2Dbox%3B%0A%2Dmoz%2Dbox%2Dsizing%3A%20border%2Dbox%3B%0Abox%2Dsizing%3A%20border%2Dbox%3B%0A%7D%0A%2A%3Abefore%2C%0A%2A%3Aafter%20%7B%0A%2Dwebkit%2Dbox%2Dsizing%3A%20border%2Dbox%3B%0A%2Dmoz%2Dbox%2Dsizing%3A%20border%2Dbox%3B%0Abox%2Dsizing%3A%20border%2Dbox%3B%0A%7D%0Ahtml%20%7B%0Afont%2Dsize%3A%2010px%3B%0A%2Dwebkit%2Dtap%2Dhighlight%2Dcolor%3A%20rgba%280%2C%200%2C%200%2C%200%29%3B%0A%7D%0Abody%20%7B%0Afont%2Dfamily%3A%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2020px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Acolor%3A%20%23333333%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0Ainput%2C%0Abutton%2C%0Aselect%2C%0Atextarea%20%7B%0Afont%2Dfamily%3A%20inherit%3B%0Afont%2Dsize%3A%20inherit%3B%0Aline%2Dheight%3A%20inherit%3B%0A%7D%0Aa%20%7B%0Acolor%3A%20%23337ab7%3B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0Aa%3Ahover%2C%0Aa%3Afocus%20%7B%0Acolor%3A%20%2323527c%3B%0Atext%2Ddecoration%3A%20underline%3B%0A%7D%0Aa%3Afocus%20%7B%0Aoutline%3A%20thin%20dotted%3B%0Aoutline%3A%205px%20auto%20%2Dwebkit%2Dfocus%2Dring%2Dcolor%3B%0Aoutline%2Doffset%3A%20%2D2px%3B%0A%7D%0Afigure%20%7B%0Amargin%3A%200%3B%0A%7D%0Aimg%20%7B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Eimg%2Dresponsive%20%7B%0Adisplay%3A%20block%3B%0Amax%2Dwidth%3A%20100%25%3B%0Aheight%3A%20auto%3B%0A%7D%0A%2Eimg%2Drounded%20%7B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Eimg%2Dthumbnail%20%7B%0Apadding%3A%204px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0Aborder%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dradius%3A%200px%3B%0A%2Dwebkit%2Dtransition%3A%20all%200%2E2s%20ease%2Din%2Dout%3B%0A%2Do%2Dtransition%3A%20all%200%2E2s%20ease%2Din%2Dout%3B%0Atransition%3A%20all%200%2E2s%20ease%2Din%2Dout%3B%0Adisplay%3A%20inline%2Dblock%3B%0Amax%2Dwidth%3A%20100%25%3B%0Aheight%3A%20auto%3B%0A%7D%0A%2Eimg%2Dcircle%20%7B%0Aborder%2Dradius%3A%2050%25%3B%0A%7D%0Ahr%20%7B%0Amargin%2Dtop%3A%2035px%3B%0Amargin%2Dbottom%3A%2035px%3B%0Aborder%3A%200%3B%0Aborder%2Dtop%3A%201px%20solid%20%23eeeeee%3B%0A%7D%0A%2Esr%2Donly%20%7B%0Aposition%3A%20absolute%3B%0Awidth%3A%201px%3B%0Aheight%3A%201px%3B%0Amargin%3A%20%2D1px%3B%0Apadding%3A%200%3B%0Aoverflow%3A%20hidden%3B%0Aclip%3A%20rect%280%2C%200%2C%200%2C%200%29%3B%0Aborder%3A%200%3B%0A%7D%0A%2Esr%2Donly%2Dfocusable%3Aactive%2C%0A%2Esr%2Donly%2Dfocusable%3Afocus%20%7B%0Aposition%3A%20static%3B%0Awidth%3A%20auto%3B%0Aheight%3A%20auto%3B%0Amargin%3A%200%3B%0Aoverflow%3A%20visible%3B%0Aclip%3A%20auto%3B%0A%7D%0Ah1%2C%0Ah2%2C%0Ah3%2C%0Ah4%2C%0Ah5%2C%0Ah6%2C%0A%2Eh1%2C%0A%2Eh2%2C%0A%2Eh3%2C%0A%2Eh4%2C%0A%2Eh5%2C%0A%2Eh6%20%7B%0Afont%2Dfamily%3A%20inherit%3B%0Afont%2Dweight%3A%20200%3B%0Aline%2Dheight%3A%201%2E75%3B%0Acolor%3A%20inherit%3B%0A%7D%0Ah1%20small%2C%0Ah2%20small%2C%0Ah3%20small%2C%0Ah4%20small%2C%0Ah5%20small%2C%0Ah6%20small%2C%0A%2Eh1%20small%2C%0A%2Eh2%20small%2C%0A%2Eh3%20small%2C%0A%2Eh4%20small%2C%0A%2Eh5%20small%2C%0A%2Eh6%20small%2C%0Ah1%20%2Esmall%2C%0Ah2%20%2Esmall%2C%0Ah3%20%2Esmall%2C%0Ah4%20%2Esmall%2C%0Ah5%20%2Esmall%2C%0Ah6%20%2Esmall%2C%0A%2Eh1%20%2Esmall%2C%0A%2Eh2%20%2Esmall%2C%0A%2Eh3%20%2Esmall%2C%0A%2Eh4%20%2Esmall%2C%0A%2Eh5%20%2Esmall%2C%0A%2Eh6%20%2Esmall%20%7B%0Afont%2Dweight%3A%20normal%3B%0Aline%2Dheight%3A%201%3B%0Acolor%3A%20%23777777%3B%0A%7D%0Ah1%2C%0A%2Eh1%2C%0Ah2%2C%0A%2Eh2%2C%0Ah3%2C%0A%2Eh3%20%7B%0Amargin%2Dtop%3A%2035px%3B%0Amargin%2Dbottom%3A%2017%2E5px%3B%0A%7D%0Ah1%20small%2C%0A%2Eh1%20small%2C%0Ah2%20small%2C%0A%2Eh2%20small%2C%0Ah3%20small%2C%0A%2Eh3%20small%2C%0Ah1%20%2Esmall%2C%0A%2Eh1%20%2Esmall%2C%0Ah2%20%2Esmall%2C%0A%2Eh2%20%2Esmall%2C%0Ah3%20%2Esmall%2C%0A%2Eh3%20%2Esmall%20%7B%0Afont%2Dsize%3A%2065%25%3B%0A%7D%0Ah4%2C%0A%2Eh4%2C%0Ah5%2C%0A%2Eh5%2C%0Ah6%2C%0A%2Eh6%20%7B%0Amargin%2Dtop%3A%2017%2E5px%3B%0Amargin%2Dbottom%3A%2017%2E5px%3B%0A%7D%0Ah4%20small%2C%0A%2Eh4%20small%2C%0Ah5%20small%2C%0A%2Eh5%20small%2C%0Ah6%20small%2C%0A%2Eh6%20small%2C%0Ah4%20%2Esmall%2C%0A%2Eh4%20%2Esmall%2C%0Ah5%20%2Esmall%2C%0A%2Eh5%20%2Esmall%2C%0Ah6%20%2Esmall%2C%0A%2Eh6%20%2Esmall%20%7B%0Afont%2Dsize%3A%2075%25%3B%0A%7D%0Ah1%2C%0A%2Eh1%20%7B%0Afont%2Dsize%3A%2052px%3B%0A%7D%0Ah2%2C%0A%2Eh2%20%7B%0Afont%2Dsize%3A%2043px%3B%0A%7D%0Ah3%2C%0A%2Eh3%20%7B%0Afont%2Dsize%3A%2034px%3B%0A%7D%0Ah4%2C%0A%2Eh4%20%7B%0Afont%2Dsize%3A%2025px%3B%0A%7D%0Ah5%2C%0A%2Eh5%20%7B%0Afont%2Dsize%3A%2020px%3B%0A%7D%0Ah6%2C%0A%2Eh6%20%7B%0Afont%2Dsize%3A%2017px%3B%0A%7D%0Ap%20%7B%0Amargin%3A%200%200%2017%2E5px%3B%0A%7D%0A%2Elead%20%7B%0Amargin%2Dbottom%3A%2035px%3B%0Afont%2Dsize%3A%2023px%3B%0Afont%2Dweight%3A%20300%3B%0Aline%2Dheight%3A%201%2E4%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Elead%20%7B%0Afont%2Dsize%3A%2030px%3B%0A%7D%0A%7D%0Asmall%2C%0A%2Esmall%20%7B%0Afont%2Dsize%3A%2085%25%3B%0A%7D%0Amark%2C%0A%2Emark%20%7B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0Apadding%3A%20%2E2em%3B%0A%7D%0A%2Etext%2Dleft%20%7B%0Atext%2Dalign%3A%20left%3B%0A%7D%0A%2Etext%2Dright%20%7B%0Atext%2Dalign%3A%20right%3B%0A%7D%0A%2Etext%2Dcenter%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%2Etext%2Djustify%20%7B%0Atext%2Dalign%3A%20justify%3B%0A%7D%0A%2Etext%2Dnowrap%20%7B%0Awhite%2Dspace%3A%20nowrap%3B%0A%7D%0A%2Etext%2Dlowercase%20%7B%0Atext%2Dtransform%3A%20lowercase%3B%0A%7D%0A%2Etext%2Duppercase%20%7B%0Atext%2Dtransform%3A%20uppercase%3B%0A%7D%0A%2Etext%2Dcapitalize%20%7B%0Atext%2Dtransform%3A%20capitalize%3B%0A%7D%0A%2Etext%2Dmuted%20%7B%0Acolor%3A%20%23777777%3B%0A%7D%0A%2Etext%2Dprimary%20%7B%0Acolor%3A%20%23337ab7%3B%0A%7D%0Aa%2Etext%2Dprimary%3Ahover%20%7B%0Acolor%3A%20%23286090%3B%0A%7D%0A%2Etext%2Dsuccess%20%7B%0Acolor%3A%20%233c763d%3B%0A%7D%0Aa%2Etext%2Dsuccess%3Ahover%20%7B%0Acolor%3A%20%232b542c%3B%0A%7D%0A%2Etext%2Dinfo%20%7B%0Acolor%3A%20%2331708f%3B%0A%7D%0Aa%2Etext%2Dinfo%3Ahover%20%7B%0Acolor%3A%20%23245269%3B%0A%7D%0A%2Etext%2Dwarning%20%7B%0Acolor%3A%20%238a6d3b%3B%0A%7D%0Aa%2Etext%2Dwarning%3Ahover%20%7B%0Acolor%3A%20%2366512c%3B%0A%7D%0A%2Etext%2Ddanger%20%7B%0Acolor%3A%20%23a94442%3B%0A%7D%0Aa%2Etext%2Ddanger%3Ahover%20%7B%0Acolor%3A%20%23843534%3B%0A%7D%0A%2Ebg%2Dprimary%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0A%7D%0Aa%2Ebg%2Dprimary%3Ahover%20%7B%0Abackground%2Dcolor%3A%20%23286090%3B%0A%7D%0A%2Ebg%2Dsuccess%20%7B%0Abackground%2Dcolor%3A%20%23dff0d8%3B%0A%7D%0Aa%2Ebg%2Dsuccess%3Ahover%20%7B%0Abackground%2Dcolor%3A%20%23c1e2b3%3B%0A%7D%0A%2Ebg%2Dinfo%20%7B%0Abackground%2Dcolor%3A%20%23d9edf7%3B%0A%7D%0Aa%2Ebg%2Dinfo%3Ahover%20%7B%0Abackground%2Dcolor%3A%20%23afd9ee%3B%0A%7D%0A%2Ebg%2Dwarning%20%7B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0A%7D%0Aa%2Ebg%2Dwarning%3Ahover%20%7B%0Abackground%2Dcolor%3A%20%23f7ecb5%3B%0A%7D%0A%2Ebg%2Ddanger%20%7B%0Abackground%2Dcolor%3A%20%23f2dede%3B%0A%7D%0Aa%2Ebg%2Ddanger%3Ahover%20%7B%0Abackground%2Dcolor%3A%20%23e4b9b9%3B%0A%7D%0A%2Epage%2Dheader%20%7B%0Apadding%2Dbottom%3A%2016%2E5px%3B%0Amargin%3A%2070px%200%2035px%3B%0Aborder%2Dbottom%3A%201px%20solid%20%23eeeeee%3B%0A%7D%0Aul%2C%0Aol%20%7B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dbottom%3A%2017%2E5px%3B%0A%7D%0Aul%20ul%2C%0Aol%20ul%2C%0Aul%20ol%2C%0Aol%20ol%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Elist%2Dunstyled%20%7B%0Apadding%2Dleft%3A%200%3B%0Alist%2Dstyle%3A%20none%3B%0A%7D%0A%2Elist%2Dinline%20%7B%0Apadding%2Dleft%3A%200%3B%0Alist%2Dstyle%3A%20none%3B%0Amargin%2Dleft%3A%20%2D5px%3B%0A%7D%0A%2Elist%2Dinline%20%3E%20li%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Apadding%2Dleft%3A%205px%3B%0Apadding%2Dright%3A%205px%3B%0A%7D%0Adl%20%7B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dbottom%3A%2035px%3B%0A%7D%0Adt%2C%0Add%20%7B%0Aline%2Dheight%3A%201%2E75%3B%0A%7D%0Adt%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Add%20%7B%0Amargin%2Dleft%3A%200%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Edl%2Dhorizontal%20dt%20%7B%0Afloat%3A%20left%3B%0Awidth%3A%20160px%3B%0Aclear%3A%20left%3B%0Atext%2Dalign%3A%20right%3B%0Aoverflow%3A%20hidden%3B%0Atext%2Doverflow%3A%20ellipsis%3B%0Awhite%2Dspace%3A%20nowrap%3B%0A%7D%0A%2Edl%2Dhorizontal%20dd%20%7B%0Amargin%2Dleft%3A%20180px%3B%0A%7D%0A%7D%0Aabbr%5Btitle%5D%2C%0Aabbr%5Bdata%2Doriginal%2Dtitle%5D%20%7B%0Acursor%3A%20help%3B%0Aborder%2Dbottom%3A%201px%20dotted%20%23777777%3B%0A%7D%0A%2Einitialism%20%7B%0Afont%2Dsize%3A%2090%25%3B%0Atext%2Dtransform%3A%20uppercase%3B%0A%7D%0Ablockquote%20%7B%0Apadding%3A%2017%2E5px%2035px%3B%0Amargin%3A%200%200%2035px%3B%0Afont%2Dsize%3A%2025px%3B%0Aborder%2Dleft%3A%205px%20solid%20%23eeeeee%3B%0A%7D%0Ablockquote%20p%3Alast%2Dchild%2C%0Ablockquote%20ul%3Alast%2Dchild%2C%0Ablockquote%20ol%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0Ablockquote%20footer%2C%0Ablockquote%20small%2C%0Ablockquote%20%2Esmall%20%7B%0Adisplay%3A%20block%3B%0Afont%2Dsize%3A%2080%25%3B%0Aline%2Dheight%3A%201%2E75%3B%0Acolor%3A%20%23777777%3B%0A%7D%0Ablockquote%20footer%3Abefore%2C%0Ablockquote%20small%3Abefore%2C%0Ablockquote%20%2Esmall%3Abefore%20%7B%0Acontent%3A%20%27%5C2014%20%5C00A0%27%3B%0A%7D%0A%2Eblockquote%2Dreverse%2C%0Ablockquote%2Epull%2Dright%20%7B%0Apadding%2Dright%3A%2015px%3B%0Apadding%2Dleft%3A%200%3B%0Aborder%2Dright%3A%205px%20solid%20%23eeeeee%3B%0Aborder%2Dleft%3A%200%3B%0Atext%2Dalign%3A%20right%3B%0A%7D%0A%2Eblockquote%2Dreverse%20footer%3Abefore%2C%0Ablockquote%2Epull%2Dright%20footer%3Abefore%2C%0A%2Eblockquote%2Dreverse%20small%3Abefore%2C%0Ablockquote%2Epull%2Dright%20small%3Abefore%2C%0A%2Eblockquote%2Dreverse%20%2Esmall%3Abefore%2C%0Ablockquote%2Epull%2Dright%20%2Esmall%3Abefore%20%7B%0Acontent%3A%20%27%27%3B%0A%7D%0A%2Eblockquote%2Dreverse%20footer%3Aafter%2C%0Ablockquote%2Epull%2Dright%20footer%3Aafter%2C%0A%2Eblockquote%2Dreverse%20small%3Aafter%2C%0Ablockquote%2Epull%2Dright%20small%3Aafter%2C%0A%2Eblockquote%2Dreverse%20%2Esmall%3Aafter%2C%0Ablockquote%2Epull%2Dright%20%2Esmall%3Aafter%20%7B%0Acontent%3A%20%27%5C00A0%20%5C2014%27%3B%0A%7D%0Aaddress%20%7B%0Amargin%2Dbottom%3A%2035px%3B%0Afont%2Dstyle%3A%20normal%3B%0Aline%2Dheight%3A%201%2E75%3B%0A%7D%0Acode%2C%0Akbd%2C%0Apre%2C%0Asamp%20%7B%0Afont%2Dfamily%3A%20Menlo%2C%20Monaco%2C%20Consolas%2C%20%22Courier%20New%22%2C%20monospace%3B%0A%7D%0Acode%20%7B%0Apadding%3A%202px%204px%3B%0Afont%2Dsize%3A%2090%25%3B%0Acolor%3A%20%23c7254e%3B%0Abackground%2Dcolor%3A%20%23f9f2f4%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0Akbd%20%7B%0Apadding%3A%202px%204px%3B%0Afont%2Dsize%3A%2090%25%3B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23333%3B%0Aborder%2Dradius%3A%200px%3B%0Abox%2Dshadow%3A%20inset%200%20%2D1px%200%20rgba%280%2C%200%2C%200%2C%200%2E25%29%3B%0A%7D%0Akbd%20kbd%20%7B%0Apadding%3A%200%3B%0Afont%2Dsize%3A%20100%25%3B%0Afont%2Dweight%3A%20bold%3B%0Abox%2Dshadow%3A%20none%3B%0A%7D%0Apre%20%7B%0Adisplay%3A%20block%3B%0Apadding%3A%2017px%3B%0Amargin%3A%200%200%2017%2E5px%3B%0Afont%2Dsize%3A%2019px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Aword%2Dbreak%3A%20break%2Dall%3B%0Aword%2Dwrap%3A%20break%2Dword%3B%0Acolor%3A%20%23333333%3B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0Aborder%3A%201px%20solid%20transparent%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0Apre%20code%20%7B%0Apadding%3A%200%3B%0Afont%2Dsize%3A%20inherit%3B%0Acolor%3A%20inherit%3B%0Awhite%2Dspace%3A%20pre%2Dwrap%3B%0Abackground%2Dcolor%3A%20transparent%3B%0Aborder%2Dradius%3A%200%3B%0A%7D%0A%2Epre%2Dscrollable%20%7B%0Amax%2Dheight%3A%20340px%3B%0Aoverflow%2Dy%3A%20scroll%3B%0A%7D%0A%2Econtainer%20%7B%0Amargin%2Dright%3A%20auto%3B%0Amargin%2Dleft%3A%20auto%3B%0Apadding%2Dleft%3A%2015px%3B%0Apadding%2Dright%3A%2015px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Econtainer%20%7B%0Awidth%3A%20750px%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20992px%29%20%7B%0A%2Econtainer%20%7B%0Awidth%3A%20970px%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%201200px%29%20%7B%0A%2Econtainer%20%7B%0Awidth%3A%20970px%3B%0A%7D%0A%7D%0A%2Econtainer%2Dfluid%20%7B%0Amargin%2Dright%3A%20auto%3B%0Amargin%2Dleft%3A%20auto%3B%0Apadding%2Dleft%3A%2015px%3B%0Apadding%2Dright%3A%2015px%3B%0A%7D%0A%2Erow%20%7B%0Amargin%2Dleft%3A%20%2D15px%3B%0Amargin%2Dright%3A%20%2D15px%3B%0A%7D%0A%2Ecol%2Dxs%2D1%2C%20%2Ecol%2Dsm%2D1%2C%20%2Ecol%2Dmd%2D1%2C%20%2Ecol%2Dlg%2D1%2C%20%2Ecol%2Dxs%2D2%2C%20%2Ecol%2Dsm%2D2%2C%20%2Ecol%2Dmd%2D2%2C%20%2Ecol%2Dlg%2D2%2C%20%2Ecol%2Dxs%2D3%2C%20%2Ecol%2Dsm%2D3%2C%20%2Ecol%2Dmd%2D3%2C%20%2Ecol%2Dlg%2D3%2C%20%2Ecol%2Dxs%2D4%2C%20%2Ecol%2Dsm%2D4%2C%20%2Ecol%2Dmd%2D4%2C%20%2Ecol%2Dlg%2D4%2C%20%2Ecol%2Dxs%2D5%2C%20%2Ecol%2Dsm%2D5%2C%20%2Ecol%2Dmd%2D5%2C%20%2Ecol%2Dlg%2D5%2C%20%2Ecol%2Dxs%2D6%2C%20%2Ecol%2Dsm%2D6%2C%20%2Ecol%2Dmd%2D6%2C%20%2Ecol%2Dlg%2D6%2C%20%2Ecol%2Dxs%2D7%2C%20%2Ecol%2Dsm%2D7%2C%20%2Ecol%2Dmd%2D7%2C%20%2Ecol%2Dlg%2D7%2C%20%2Ecol%2Dxs%2D8%2C%20%2Ecol%2Dsm%2D8%2C%20%2Ecol%2Dmd%2D8%2C%20%2Ecol%2Dlg%2D8%2C%20%2Ecol%2Dxs%2D9%2C%20%2Ecol%2Dsm%2D9%2C%20%2Ecol%2Dmd%2D9%2C%20%2Ecol%2Dlg%2D9%2C%20%2Ecol%2Dxs%2D10%2C%20%2Ecol%2Dsm%2D10%2C%20%2Ecol%2Dmd%2D10%2C%20%2Ecol%2Dlg%2D10%2C%20%2Ecol%2Dxs%2D11%2C%20%2Ecol%2Dsm%2D11%2C%20%2Ecol%2Dmd%2D11%2C%20%2Ecol%2Dlg%2D11%2C%20%2Ecol%2Dxs%2D12%2C%20%2Ecol%2Dsm%2D12%2C%20%2Ecol%2Dmd%2D12%2C%20%2Ecol%2Dlg%2D12%20%7B%0Aposition%3A%20relative%3B%0Amin%2Dheight%3A%201px%3B%0Apadding%2Dleft%3A%2015px%3B%0Apadding%2Dright%3A%2015px%3B%0A%7D%0A%2Ecol%2Dxs%2D1%2C%20%2Ecol%2Dxs%2D2%2C%20%2Ecol%2Dxs%2D3%2C%20%2Ecol%2Dxs%2D4%2C%20%2Ecol%2Dxs%2D5%2C%20%2Ecol%2Dxs%2D6%2C%20%2Ecol%2Dxs%2D7%2C%20%2Ecol%2Dxs%2D8%2C%20%2Ecol%2Dxs%2D9%2C%20%2Ecol%2Dxs%2D10%2C%20%2Ecol%2Dxs%2D11%2C%20%2Ecol%2Dxs%2D12%20%7B%0Afloat%3A%20left%3B%0A%7D%0A%2Ecol%2Dxs%2D12%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dxs%2D11%20%7B%0Awidth%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2D10%20%7B%0Awidth%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2D9%20%7B%0Awidth%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dxs%2D8%20%7B%0Awidth%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2D7%20%7B%0Awidth%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2D6%20%7B%0Awidth%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dxs%2D5%20%7B%0Awidth%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2D4%20%7B%0Awidth%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2D3%20%7B%0Awidth%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dxs%2D2%20%7B%0Awidth%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2D1%20%7B%0Awidth%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D12%20%7B%0Aright%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D11%20%7B%0Aright%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D10%20%7B%0Aright%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D9%20%7B%0Aright%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D8%20%7B%0Aright%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D7%20%7B%0Aright%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D6%20%7B%0Aright%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D5%20%7B%0Aright%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D4%20%7B%0Aright%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D3%20%7B%0Aright%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D2%20%7B%0Aright%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D1%20%7B%0Aright%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpull%2D0%20%7B%0Aright%3A%20auto%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D12%20%7B%0Aleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D11%20%7B%0Aleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D10%20%7B%0Aleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D9%20%7B%0Aleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D8%20%7B%0Aleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D7%20%7B%0Aleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D6%20%7B%0Aleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D5%20%7B%0Aleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D4%20%7B%0Aleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D3%20%7B%0Aleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D2%20%7B%0Aleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D1%20%7B%0Aleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Dpush%2D0%20%7B%0Aleft%3A%20auto%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D12%20%7B%0Amargin%2Dleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D11%20%7B%0Amargin%2Dleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D10%20%7B%0Amargin%2Dleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D9%20%7B%0Amargin%2Dleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D8%20%7B%0Amargin%2Dleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D7%20%7B%0Amargin%2Dleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D6%20%7B%0Amargin%2Dleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D5%20%7B%0Amargin%2Dleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D4%20%7B%0Amargin%2Dleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D3%20%7B%0Amargin%2Dleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D2%20%7B%0Amargin%2Dleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D1%20%7B%0Amargin%2Dleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dxs%2Doffset%2D0%20%7B%0Amargin%2Dleft%3A%200%25%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Ecol%2Dsm%2D1%2C%20%2Ecol%2Dsm%2D2%2C%20%2Ecol%2Dsm%2D3%2C%20%2Ecol%2Dsm%2D4%2C%20%2Ecol%2Dsm%2D5%2C%20%2Ecol%2Dsm%2D6%2C%20%2Ecol%2Dsm%2D7%2C%20%2Ecol%2Dsm%2D8%2C%20%2Ecol%2Dsm%2D9%2C%20%2Ecol%2Dsm%2D10%2C%20%2Ecol%2Dsm%2D11%2C%20%2Ecol%2Dsm%2D12%20%7B%0Afloat%3A%20left%3B%0A%7D%0A%2Ecol%2Dsm%2D12%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dsm%2D11%20%7B%0Awidth%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2D10%20%7B%0Awidth%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2D9%20%7B%0Awidth%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dsm%2D8%20%7B%0Awidth%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2D7%20%7B%0Awidth%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2D6%20%7B%0Awidth%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dsm%2D5%20%7B%0Awidth%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2D4%20%7B%0Awidth%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2D3%20%7B%0Awidth%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dsm%2D2%20%7B%0Awidth%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2D1%20%7B%0Awidth%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D12%20%7B%0Aright%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D11%20%7B%0Aright%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D10%20%7B%0Aright%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D9%20%7B%0Aright%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D8%20%7B%0Aright%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D7%20%7B%0Aright%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D6%20%7B%0Aright%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D5%20%7B%0Aright%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D4%20%7B%0Aright%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D3%20%7B%0Aright%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D2%20%7B%0Aright%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D1%20%7B%0Aright%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpull%2D0%20%7B%0Aright%3A%20auto%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D12%20%7B%0Aleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D11%20%7B%0Aleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D10%20%7B%0Aleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D9%20%7B%0Aleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D8%20%7B%0Aleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D7%20%7B%0Aleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D6%20%7B%0Aleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D5%20%7B%0Aleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D4%20%7B%0Aleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D3%20%7B%0Aleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D2%20%7B%0Aleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D1%20%7B%0Aleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Dpush%2D0%20%7B%0Aleft%3A%20auto%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D12%20%7B%0Amargin%2Dleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D11%20%7B%0Amargin%2Dleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D10%20%7B%0Amargin%2Dleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D9%20%7B%0Amargin%2Dleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D8%20%7B%0Amargin%2Dleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D7%20%7B%0Amargin%2Dleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D6%20%7B%0Amargin%2Dleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D5%20%7B%0Amargin%2Dleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D4%20%7B%0Amargin%2Dleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D3%20%7B%0Amargin%2Dleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D2%20%7B%0Amargin%2Dleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D1%20%7B%0Amargin%2Dleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dsm%2Doffset%2D0%20%7B%0Amargin%2Dleft%3A%200%25%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20992px%29%20%7B%0A%2Ecol%2Dmd%2D1%2C%20%2Ecol%2Dmd%2D2%2C%20%2Ecol%2Dmd%2D3%2C%20%2Ecol%2Dmd%2D4%2C%20%2Ecol%2Dmd%2D5%2C%20%2Ecol%2Dmd%2D6%2C%20%2Ecol%2Dmd%2D7%2C%20%2Ecol%2Dmd%2D8%2C%20%2Ecol%2Dmd%2D9%2C%20%2Ecol%2Dmd%2D10%2C%20%2Ecol%2Dmd%2D11%2C%20%2Ecol%2Dmd%2D12%20%7B%0Afloat%3A%20left%3B%0A%7D%0A%2Ecol%2Dmd%2D12%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dmd%2D11%20%7B%0Awidth%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2D10%20%7B%0Awidth%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2D9%20%7B%0Awidth%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dmd%2D8%20%7B%0Awidth%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2D7%20%7B%0Awidth%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2D6%20%7B%0Awidth%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dmd%2D5%20%7B%0Awidth%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2D4%20%7B%0Awidth%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2D3%20%7B%0Awidth%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dmd%2D2%20%7B%0Awidth%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2D1%20%7B%0Awidth%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D12%20%7B%0Aright%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D11%20%7B%0Aright%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D10%20%7B%0Aright%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D9%20%7B%0Aright%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D8%20%7B%0Aright%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D7%20%7B%0Aright%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D6%20%7B%0Aright%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D5%20%7B%0Aright%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D4%20%7B%0Aright%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D3%20%7B%0Aright%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D2%20%7B%0Aright%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D1%20%7B%0Aright%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpull%2D0%20%7B%0Aright%3A%20auto%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D12%20%7B%0Aleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D11%20%7B%0Aleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D10%20%7B%0Aleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D9%20%7B%0Aleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D8%20%7B%0Aleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D7%20%7B%0Aleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D6%20%7B%0Aleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D5%20%7B%0Aleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D4%20%7B%0Aleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D3%20%7B%0Aleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D2%20%7B%0Aleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D1%20%7B%0Aleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Dpush%2D0%20%7B%0Aleft%3A%20auto%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D12%20%7B%0Amargin%2Dleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D11%20%7B%0Amargin%2Dleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D10%20%7B%0Amargin%2Dleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D9%20%7B%0Amargin%2Dleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D8%20%7B%0Amargin%2Dleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D7%20%7B%0Amargin%2Dleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D6%20%7B%0Amargin%2Dleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D5%20%7B%0Amargin%2Dleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D4%20%7B%0Amargin%2Dleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D3%20%7B%0Amargin%2Dleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D2%20%7B%0Amargin%2Dleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D1%20%7B%0Amargin%2Dleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dmd%2Doffset%2D0%20%7B%0Amargin%2Dleft%3A%200%25%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%201200px%29%20%7B%0A%2Ecol%2Dlg%2D1%2C%20%2Ecol%2Dlg%2D2%2C%20%2Ecol%2Dlg%2D3%2C%20%2Ecol%2Dlg%2D4%2C%20%2Ecol%2Dlg%2D5%2C%20%2Ecol%2Dlg%2D6%2C%20%2Ecol%2Dlg%2D7%2C%20%2Ecol%2Dlg%2D8%2C%20%2Ecol%2Dlg%2D9%2C%20%2Ecol%2Dlg%2D10%2C%20%2Ecol%2Dlg%2D11%2C%20%2Ecol%2Dlg%2D12%20%7B%0Afloat%3A%20left%3B%0A%7D%0A%2Ecol%2Dlg%2D12%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dlg%2D11%20%7B%0Awidth%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2D10%20%7B%0Awidth%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2D9%20%7B%0Awidth%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dlg%2D8%20%7B%0Awidth%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2D7%20%7B%0Awidth%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2D6%20%7B%0Awidth%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dlg%2D5%20%7B%0Awidth%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2D4%20%7B%0Awidth%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2D3%20%7B%0Awidth%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dlg%2D2%20%7B%0Awidth%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2D1%20%7B%0Awidth%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D12%20%7B%0Aright%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D11%20%7B%0Aright%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D10%20%7B%0Aright%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D9%20%7B%0Aright%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D8%20%7B%0Aright%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D7%20%7B%0Aright%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D6%20%7B%0Aright%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D5%20%7B%0Aright%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D4%20%7B%0Aright%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D3%20%7B%0Aright%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D2%20%7B%0Aright%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D1%20%7B%0Aright%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpull%2D0%20%7B%0Aright%3A%20auto%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D12%20%7B%0Aleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D11%20%7B%0Aleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D10%20%7B%0Aleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D9%20%7B%0Aleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D8%20%7B%0Aleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D7%20%7B%0Aleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D6%20%7B%0Aleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D5%20%7B%0Aleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D4%20%7B%0Aleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D3%20%7B%0Aleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D2%20%7B%0Aleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D1%20%7B%0Aleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Dpush%2D0%20%7B%0Aleft%3A%20auto%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D12%20%7B%0Amargin%2Dleft%3A%20100%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D11%20%7B%0Amargin%2Dleft%3A%2091%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D10%20%7B%0Amargin%2Dleft%3A%2083%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D9%20%7B%0Amargin%2Dleft%3A%2075%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D8%20%7B%0Amargin%2Dleft%3A%2066%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D7%20%7B%0Amargin%2Dleft%3A%2058%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D6%20%7B%0Amargin%2Dleft%3A%2050%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D5%20%7B%0Amargin%2Dleft%3A%2041%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D4%20%7B%0Amargin%2Dleft%3A%2033%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D3%20%7B%0Amargin%2Dleft%3A%2025%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D2%20%7B%0Amargin%2Dleft%3A%2016%2E66666667%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D1%20%7B%0Amargin%2Dleft%3A%208%2E33333333%25%3B%0A%7D%0A%2Ecol%2Dlg%2Doffset%2D0%20%7B%0Amargin%2Dleft%3A%200%25%3B%0A%7D%0A%7D%0Atable%20%7B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0Acaption%20%7B%0Apadding%2Dtop%3A%208px%3B%0Apadding%2Dbottom%3A%208px%3B%0Acolor%3A%20%23777777%3B%0Atext%2Dalign%3A%20left%3B%0A%7D%0Ath%20%7B%0Atext%2Dalign%3A%20left%3B%0A%7D%0A%2Etable%20%7B%0Awidth%3A%20100%25%3B%0Amax%2Dwidth%3A%20100%25%3B%0Amargin%2Dbottom%3A%2035px%3B%0A%7D%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%20%7B%0Apadding%3A%208px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Avertical%2Dalign%3A%20top%3B%0Aborder%2Dtop%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%20%7B%0Avertical%2Dalign%3A%20bottom%3B%0Aborder%2Dbottom%3A%202px%20solid%20%23ddd%3B%0A%7D%0A%2Etable%20%3E%20caption%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0A%2Etable%20%3E%20colgroup%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0A%2Etable%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0A%2Etable%20%3E%20caption%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0A%2Etable%20%3E%20colgroup%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0A%2Etable%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%20%7B%0Aborder%2Dtop%3A%200%3B%0A%7D%0A%2Etable%20%3E%20tbody%20%2B%20tbody%20%7B%0Aborder%2Dtop%3A%202px%20solid%20%23ddd%3B%0A%7D%0A%2Etable%20%2Etable%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Etable%2Dcondensed%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dcondensed%20%3E%20tbody%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dcondensed%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dcondensed%20%3E%20thead%20%3E%20tr%20%3E%20td%2C%0A%2Etable%2Dcondensed%20%3E%20tbody%20%3E%20tr%20%3E%20td%2C%0A%2Etable%2Dcondensed%20%3E%20tfoot%20%3E%20tr%20%3E%20td%20%7B%0Apadding%3A%205px%3B%0A%7D%0A%2Etable%2Dbordered%20%7B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%2C%0A%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%2C%0A%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%20%7B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%20%7B%0Aborder%2Dbottom%2Dwidth%3A%202px%3B%0A%7D%0A%2Etable%2Dstriped%20%3E%20tbody%20%3E%20tr%3Anth%2Dchild%28odd%29%20%7B%0Abackground%2Dcolor%3A%20%23f9f9f9%3B%0A%7D%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%3Ahover%20%7B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0A%7D%0Atable%20col%5Bclass%2A%3D%22col%2D%22%5D%20%7B%0Aposition%3A%20static%3B%0Afloat%3A%20none%3B%0Adisplay%3A%20table%2Dcolumn%3B%0A%7D%0Atable%20td%5Bclass%2A%3D%22col%2D%22%5D%2C%0Atable%20th%5Bclass%2A%3D%22col%2D%22%5D%20%7B%0Aposition%3A%20static%3B%0Afloat%3A%20none%3B%0Adisplay%3A%20table%2Dcell%3B%0A%7D%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2Eactive%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Eactive%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%2Eactive%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2Eactive%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Eactive%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2Eactive%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Eactive%20%3E%20td%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Eactive%20%3E%20td%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Eactive%20%3E%20td%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Eactive%20%3E%20th%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Eactive%20%3E%20th%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Eactive%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0A%7D%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Eactive%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Eactive%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Eactive%3Ahover%20%3E%20td%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%3Ahover%20%3E%20%2Eactive%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Eactive%3Ahover%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23e8e8e8%3B%0A%7D%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2Esuccess%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Esuccess%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%2Esuccess%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2Esuccess%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Esuccess%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2Esuccess%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Esuccess%20%3E%20td%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Esuccess%20%3E%20td%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Esuccess%20%3E%20td%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Esuccess%20%3E%20th%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Esuccess%20%3E%20th%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Esuccess%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23dff0d8%3B%0A%7D%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Esuccess%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Esuccess%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Esuccess%3Ahover%20%3E%20td%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%3Ahover%20%3E%20%2Esuccess%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Esuccess%3Ahover%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23d0e9c6%3B%0A%7D%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2Einfo%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Einfo%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%2Einfo%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2Einfo%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Einfo%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2Einfo%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Einfo%20%3E%20td%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Einfo%20%3E%20td%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Einfo%20%3E%20td%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Einfo%20%3E%20th%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Einfo%20%3E%20th%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Einfo%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23d9edf7%3B%0A%7D%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Einfo%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Einfo%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Einfo%3Ahover%20%3E%20td%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%3Ahover%20%3E%20%2Einfo%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Einfo%3Ahover%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23c4e3f3%3B%0A%7D%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2Ewarning%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Ewarning%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%2Ewarning%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2Ewarning%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Ewarning%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2Ewarning%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Ewarning%20%3E%20td%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Ewarning%20%3E%20td%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Ewarning%20%3E%20td%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Ewarning%20%3E%20th%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Ewarning%20%3E%20th%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Ewarning%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0A%7D%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Ewarning%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Ewarning%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Ewarning%3Ahover%20%3E%20td%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%3Ahover%20%3E%20%2Ewarning%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Ewarning%3Ahover%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23faf2cc%3B%0A%7D%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2Edanger%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Edanger%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%2Edanger%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2Edanger%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Edanger%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2Edanger%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Edanger%20%3E%20td%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Edanger%20%3E%20td%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Edanger%20%3E%20td%2C%0A%2Etable%20%3E%20thead%20%3E%20tr%2Edanger%20%3E%20th%2C%0A%2Etable%20%3E%20tbody%20%3E%20tr%2Edanger%20%3E%20th%2C%0A%2Etable%20%3E%20tfoot%20%3E%20tr%2Edanger%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23f2dede%3B%0A%7D%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20td%2Edanger%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%20%3E%20th%2Edanger%3Ahover%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Edanger%3Ahover%20%3E%20td%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%3Ahover%20%3E%20%2Edanger%2C%0A%2Etable%2Dhover%20%3E%20tbody%20%3E%20tr%2Edanger%3Ahover%20%3E%20th%20%7B%0Abackground%2Dcolor%3A%20%23ebcccc%3B%0A%7D%0A%2Etable%2Dresponsive%20%7B%0Aoverflow%2Dx%3A%20auto%3B%0Amin%2Dheight%3A%200%2E01%25%3B%0A%7D%0A%40media%20screen%20and%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Etable%2Dresponsive%20%7B%0Awidth%3A%20100%25%3B%0Amargin%2Dbottom%3A%2026%2E25px%3B%0Aoverflow%2Dy%3A%20hidden%3B%0A%2Dms%2Doverflow%2Dstyle%3A%20%2Dms%2Dautohiding%2Dscrollbar%3B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Etable%2Dresponsive%20%3E%20%2Etable%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Etable%2Dresponsive%20%3E%20%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%20%7B%0Awhite%2Dspace%3A%20nowrap%3B%0A%7D%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%7B%0Aborder%3A%200%3B%0A%7D%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%20%7B%0Aborder%2Dleft%3A%200%3B%0A%7D%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Alast%2Dchild%20%7B%0Aborder%2Dright%3A%200%3B%0A%7D%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20th%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20th%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20td%2C%0A%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20td%20%7B%0Aborder%2Dbottom%3A%200%3B%0A%7D%0A%7D%0Afieldset%20%7B%0Apadding%3A%200%3B%0Amargin%3A%200%3B%0Aborder%3A%200%3B%0Amin%2Dwidth%3A%200%3B%0A%7D%0Alegend%20%7B%0Adisplay%3A%20block%3B%0Awidth%3A%20100%25%3B%0Apadding%3A%200%3B%0Amargin%2Dbottom%3A%2035px%3B%0Afont%2Dsize%3A%2030px%3B%0Aline%2Dheight%3A%20inherit%3B%0Acolor%3A%20%23333333%3B%0Aborder%3A%200%3B%0Aborder%2Dbottom%3A%201px%20solid%20%23e5e5e5%3B%0A%7D%0Alabel%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Amax%2Dwidth%3A%20100%25%3B%0Amargin%2Dbottom%3A%205px%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Ainput%5Btype%3D%22search%22%5D%20%7B%0A%2Dwebkit%2Dbox%2Dsizing%3A%20border%2Dbox%3B%0A%2Dmoz%2Dbox%2Dsizing%3A%20border%2Dbox%3B%0Abox%2Dsizing%3A%20border%2Dbox%3B%0A%7D%0Ainput%5Btype%3D%22radio%22%5D%2C%0Ainput%5Btype%3D%22checkbox%22%5D%20%7B%0Amargin%3A%204px%200%200%3B%0Amargin%2Dtop%3A%201px%20%5C9%3B%0Aline%2Dheight%3A%20normal%3B%0A%7D%0Ainput%5Btype%3D%22file%22%5D%20%7B%0Adisplay%3A%20block%3B%0A%7D%0Ainput%5Btype%3D%22range%22%5D%20%7B%0Adisplay%3A%20block%3B%0Awidth%3A%20100%25%3B%0A%7D%0Aselect%5Bmultiple%5D%2C%0Aselect%5Bsize%5D%20%7B%0Aheight%3A%20auto%3B%0A%7D%0Ainput%5Btype%3D%22file%22%5D%3Afocus%2C%0Ainput%5Btype%3D%22radio%22%5D%3Afocus%2C%0Ainput%5Btype%3D%22checkbox%22%5D%3Afocus%20%7B%0Aoutline%3A%20thin%20dotted%3B%0Aoutline%3A%205px%20auto%20%2Dwebkit%2Dfocus%2Dring%2Dcolor%3B%0Aoutline%2Doffset%3A%20%2D2px%3B%0A%7D%0Aoutput%20%7B%0Adisplay%3A%20block%3B%0Apadding%2Dtop%3A%207px%3B%0Afont%2Dsize%3A%2020px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Acolor%3A%20%23555555%3B%0A%7D%0A%2Eform%2Dcontrol%20%7B%0Adisplay%3A%20block%3B%0Awidth%3A%20100%25%3B%0Aheight%3A%2049px%3B%0Apadding%3A%206px%2012px%3B%0Afont%2Dsize%3A%2020px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Acolor%3A%20%23555555%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0Abackground%2Dimage%3A%20none%3B%0Aborder%3A%201px%20solid%20%23ccc%3B%0Aborder%2Dradius%3A%200px%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0A%2Dwebkit%2Dtransition%3A%20border%2Dcolor%20ease%2Din%2Dout%20%2E15s%2C%20box%2Dshadow%20ease%2Din%2Dout%20%2E15s%3B%0A%2Do%2Dtransition%3A%20border%2Dcolor%20ease%2Din%2Dout%20%2E15s%2C%20box%2Dshadow%20ease%2Din%2Dout%20%2E15s%3B%0Atransition%3A%20border%2Dcolor%20ease%2Din%2Dout%20%2E15s%2C%20box%2Dshadow%20ease%2Din%2Dout%20%2E15s%3B%0A%7D%0A%2Eform%2Dcontrol%3Afocus%20%7B%0Aborder%2Dcolor%3A%20%2366afe9%3B%0Aoutline%3A%200%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C%200%200%208px%20rgba%28102%2C%20175%2C%20233%2C%200%2E6%29%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C%200%200%208px%20rgba%28102%2C%20175%2C%20233%2C%200%2E6%29%3B%0A%7D%0A%2Eform%2Dcontrol%3A%3A%2Dmoz%2Dplaceholder%20%7B%0Acolor%3A%20%23999%3B%0Aopacity%3A%201%3B%0A%7D%0A%2Eform%2Dcontrol%3A%2Dms%2Dinput%2Dplaceholder%20%7B%0Acolor%3A%20%23999%3B%0A%7D%0A%2Eform%2Dcontrol%3A%3A%2Dwebkit%2Dinput%2Dplaceholder%20%7B%0Acolor%3A%20%23999%3B%0A%7D%0A%2Eform%2Dcontrol%5Bdisabled%5D%2C%0A%2Eform%2Dcontrol%5Breadonly%5D%2C%0Afieldset%5Bdisabled%5D%20%2Eform%2Dcontrol%20%7B%0Acursor%3A%20not%2Dallowed%3B%0Abackground%2Dcolor%3A%20%23eeeeee%3B%0Aopacity%3A%201%3B%0A%7D%0Atextarea%2Eform%2Dcontrol%20%7B%0Aheight%3A%20auto%3B%0A%7D%0Ainput%5Btype%3D%22search%22%5D%20%7B%0A%2Dwebkit%2Dappearance%3A%20none%3B%0A%7D%0A%40media%20screen%20and%20%28%2Dwebkit%2Dmin%2Ddevice%2Dpixel%2Dratio%3A%200%29%20%7B%0Ainput%5Btype%3D%22date%22%5D%2C%0Ainput%5Btype%3D%22time%22%5D%2C%0Ainput%5Btype%3D%22datetime%2Dlocal%22%5D%2C%0Ainput%5Btype%3D%22month%22%5D%20%7B%0Aline%2Dheight%3A%2049px%3B%0A%7D%0Ainput%5Btype%3D%22date%22%5D%2Einput%2Dsm%2C%0Ainput%5Btype%3D%22time%22%5D%2Einput%2Dsm%2C%0Ainput%5Btype%3D%22datetime%2Dlocal%22%5D%2Einput%2Dsm%2C%0Ainput%5Btype%3D%22month%22%5D%2Einput%2Dsm%20%7B%0Aline%2Dheight%3A%2037px%3B%0A%7D%0Ainput%5Btype%3D%22date%22%5D%2Einput%2Dlg%2C%0Ainput%5Btype%3D%22time%22%5D%2Einput%2Dlg%2C%0Ainput%5Btype%3D%22datetime%2Dlocal%22%5D%2Einput%2Dlg%2C%0Ainput%5Btype%3D%22month%22%5D%2Einput%2Dlg%20%7B%0Aline%2Dheight%3A%2056px%3B%0A%7D%0A%7D%0A%2Eform%2Dgroup%20%7B%0Amargin%2Dbottom%3A%2015px%3B%0A%7D%0A%2Eradio%2C%0A%2Echeckbox%20%7B%0Aposition%3A%20relative%3B%0Adisplay%3A%20block%3B%0Amargin%2Dtop%3A%2010px%3B%0Amargin%2Dbottom%3A%2010px%3B%0A%7D%0A%2Eradio%20label%2C%0A%2Echeckbox%20label%20%7B%0Amin%2Dheight%3A%2035px%3B%0Apadding%2Dleft%3A%2020px%3B%0Amargin%2Dbottom%3A%200%3B%0Afont%2Dweight%3A%20normal%3B%0Acursor%3A%20pointer%3B%0A%7D%0A%2Eradio%20input%5Btype%3D%22radio%22%5D%2C%0A%2Eradio%2Dinline%20input%5Btype%3D%22radio%22%5D%2C%0A%2Echeckbox%20input%5Btype%3D%22checkbox%22%5D%2C%0A%2Echeckbox%2Dinline%20input%5Btype%3D%22checkbox%22%5D%20%7B%0Aposition%3A%20absolute%3B%0Amargin%2Dleft%3A%20%2D20px%3B%0Amargin%2Dtop%3A%204px%20%5C9%3B%0A%7D%0A%2Eradio%20%2B%20%2Eradio%2C%0A%2Echeckbox%20%2B%20%2Echeckbox%20%7B%0Amargin%2Dtop%3A%20%2D5px%3B%0A%7D%0A%2Eradio%2Dinline%2C%0A%2Echeckbox%2Dinline%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Apadding%2Dleft%3A%2020px%3B%0Amargin%2Dbottom%3A%200%3B%0Avertical%2Dalign%3A%20middle%3B%0Afont%2Dweight%3A%20normal%3B%0Acursor%3A%20pointer%3B%0A%7D%0A%2Eradio%2Dinline%20%2B%20%2Eradio%2Dinline%2C%0A%2Echeckbox%2Dinline%20%2B%20%2Echeckbox%2Dinline%20%7B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dleft%3A%2010px%3B%0A%7D%0Ainput%5Btype%3D%22radio%22%5D%5Bdisabled%5D%2C%0Ainput%5Btype%3D%22checkbox%22%5D%5Bdisabled%5D%2C%0Ainput%5Btype%3D%22radio%22%5D%2Edisabled%2C%0Ainput%5Btype%3D%22checkbox%22%5D%2Edisabled%2C%0Afieldset%5Bdisabled%5D%20input%5Btype%3D%22radio%22%5D%2C%0Afieldset%5Bdisabled%5D%20input%5Btype%3D%22checkbox%22%5D%20%7B%0Acursor%3A%20not%2Dallowed%3B%0A%7D%0A%2Eradio%2Dinline%2Edisabled%2C%0A%2Echeckbox%2Dinline%2Edisabled%2C%0Afieldset%5Bdisabled%5D%20%2Eradio%2Dinline%2C%0Afieldset%5Bdisabled%5D%20%2Echeckbox%2Dinline%20%7B%0Acursor%3A%20not%2Dallowed%3B%0A%7D%0A%2Eradio%2Edisabled%20label%2C%0A%2Echeckbox%2Edisabled%20label%2C%0Afieldset%5Bdisabled%5D%20%2Eradio%20label%2C%0Afieldset%5Bdisabled%5D%20%2Echeckbox%20label%20%7B%0Acursor%3A%20not%2Dallowed%3B%0A%7D%0A%2Eform%2Dcontrol%2Dstatic%20%7B%0Apadding%2Dtop%3A%207px%3B%0Apadding%2Dbottom%3A%207px%3B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Eform%2Dcontrol%2Dstatic%2Einput%2Dlg%2C%0A%2Eform%2Dcontrol%2Dstatic%2Einput%2Dsm%20%7B%0Apadding%2Dleft%3A%200%3B%0Apadding%2Dright%3A%200%3B%0A%7D%0A%2Einput%2Dsm%2C%0A%2Eform%2Dgroup%2Dsm%20%2Eform%2Dcontrol%20%7B%0Aheight%3A%2037px%3B%0Apadding%3A%205px%2010px%3B%0Afont%2Dsize%3A%2017px%3B%0Aline%2Dheight%3A%201%2E5%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0Aselect%2Einput%2Dsm%2C%0Aselect%2Eform%2Dgroup%2Dsm%20%2Eform%2Dcontrol%20%7B%0Aheight%3A%2037px%3B%0Aline%2Dheight%3A%2037px%3B%0A%7D%0Atextarea%2Einput%2Dsm%2C%0Atextarea%2Eform%2Dgroup%2Dsm%20%2Eform%2Dcontrol%2C%0Aselect%5Bmultiple%5D%2Einput%2Dsm%2C%0Aselect%5Bmultiple%5D%2Eform%2Dgroup%2Dsm%20%2Eform%2Dcontrol%20%7B%0Aheight%3A%20auto%3B%0A%7D%0A%2Einput%2Dlg%2C%0A%2Eform%2Dgroup%2Dlg%20%2Eform%2Dcontrol%20%7B%0Aheight%3A%2056px%3B%0Apadding%3A%2010px%2016px%3B%0Afont%2Dsize%3A%2025px%3B%0Aline%2Dheight%3A%201%2E33%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0Aselect%2Einput%2Dlg%2C%0Aselect%2Eform%2Dgroup%2Dlg%20%2Eform%2Dcontrol%20%7B%0Aheight%3A%2056px%3B%0Aline%2Dheight%3A%2056px%3B%0A%7D%0Atextarea%2Einput%2Dlg%2C%0Atextarea%2Eform%2Dgroup%2Dlg%20%2Eform%2Dcontrol%2C%0Aselect%5Bmultiple%5D%2Einput%2Dlg%2C%0Aselect%5Bmultiple%5D%2Eform%2Dgroup%2Dlg%20%2Eform%2Dcontrol%20%7B%0Aheight%3A%20auto%3B%0A%7D%0A%2Ehas%2Dfeedback%20%7B%0Aposition%3A%20relative%3B%0A%7D%0A%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%20%7B%0Apadding%2Dright%3A%2061%2E25px%3B%0A%7D%0A%2Eform%2Dcontrol%2Dfeedback%20%7B%0Aposition%3A%20absolute%3B%0Atop%3A%200%3B%0Aright%3A%200%3B%0Az%2Dindex%3A%202%3B%0Adisplay%3A%20block%3B%0Awidth%3A%2049px%3B%0Aheight%3A%2049px%3B%0Aline%2Dheight%3A%2049px%3B%0Atext%2Dalign%3A%20center%3B%0Apointer%2Devents%3A%20none%3B%0A%7D%0A%2Einput%2Dlg%20%2B%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Awidth%3A%2056px%3B%0Aheight%3A%2056px%3B%0Aline%2Dheight%3A%2056px%3B%0A%7D%0A%2Einput%2Dsm%20%2B%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Awidth%3A%2037px%3B%0Aheight%3A%2037px%3B%0Aline%2Dheight%3A%2037px%3B%0A%7D%0A%2Ehas%2Dsuccess%20%2Ehelp%2Dblock%2C%0A%2Ehas%2Dsuccess%20%2Econtrol%2Dlabel%2C%0A%2Ehas%2Dsuccess%20%2Eradio%2C%0A%2Ehas%2Dsuccess%20%2Echeckbox%2C%0A%2Ehas%2Dsuccess%20%2Eradio%2Dinline%2C%0A%2Ehas%2Dsuccess%20%2Echeckbox%2Dinline%2C%0A%2Ehas%2Dsuccess%2Eradio%20label%2C%0A%2Ehas%2Dsuccess%2Echeckbox%20label%2C%0A%2Ehas%2Dsuccess%2Eradio%2Dinline%20label%2C%0A%2Ehas%2Dsuccess%2Echeckbox%2Dinline%20label%20%7B%0Acolor%3A%20%233c763d%3B%0A%7D%0A%2Ehas%2Dsuccess%20%2Eform%2Dcontrol%20%7B%0Aborder%2Dcolor%3A%20%233c763d%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0A%7D%0A%2Ehas%2Dsuccess%20%2Eform%2Dcontrol%3Afocus%20%7B%0Aborder%2Dcolor%3A%20%232b542c%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%2C%200%200%206px%20%2367b168%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%2C%200%200%206px%20%2367b168%3B%0A%7D%0A%2Ehas%2Dsuccess%20%2Einput%2Dgroup%2Daddon%20%7B%0Acolor%3A%20%233c763d%3B%0Aborder%2Dcolor%3A%20%233c763d%3B%0Abackground%2Dcolor%3A%20%23dff0d8%3B%0A%7D%0A%2Ehas%2Dsuccess%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Acolor%3A%20%233c763d%3B%0A%7D%0A%2Ehas%2Dwarning%20%2Ehelp%2Dblock%2C%0A%2Ehas%2Dwarning%20%2Econtrol%2Dlabel%2C%0A%2Ehas%2Dwarning%20%2Eradio%2C%0A%2Ehas%2Dwarning%20%2Echeckbox%2C%0A%2Ehas%2Dwarning%20%2Eradio%2Dinline%2C%0A%2Ehas%2Dwarning%20%2Echeckbox%2Dinline%2C%0A%2Ehas%2Dwarning%2Eradio%20label%2C%0A%2Ehas%2Dwarning%2Echeckbox%20label%2C%0A%2Ehas%2Dwarning%2Eradio%2Dinline%20label%2C%0A%2Ehas%2Dwarning%2Echeckbox%2Dinline%20label%20%7B%0Acolor%3A%20%238a6d3b%3B%0A%7D%0A%2Ehas%2Dwarning%20%2Eform%2Dcontrol%20%7B%0Aborder%2Dcolor%3A%20%238a6d3b%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0A%7D%0A%2Ehas%2Dwarning%20%2Eform%2Dcontrol%3Afocus%20%7B%0Aborder%2Dcolor%3A%20%2366512c%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%2C%200%200%206px%20%23c0a16b%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%2C%200%200%206px%20%23c0a16b%3B%0A%7D%0A%2Ehas%2Dwarning%20%2Einput%2Dgroup%2Daddon%20%7B%0Acolor%3A%20%238a6d3b%3B%0Aborder%2Dcolor%3A%20%238a6d3b%3B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0A%7D%0A%2Ehas%2Dwarning%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Acolor%3A%20%238a6d3b%3B%0A%7D%0A%2Ehas%2Derror%20%2Ehelp%2Dblock%2C%0A%2Ehas%2Derror%20%2Econtrol%2Dlabel%2C%0A%2Ehas%2Derror%20%2Eradio%2C%0A%2Ehas%2Derror%20%2Echeckbox%2C%0A%2Ehas%2Derror%20%2Eradio%2Dinline%2C%0A%2Ehas%2Derror%20%2Echeckbox%2Dinline%2C%0A%2Ehas%2Derror%2Eradio%20label%2C%0A%2Ehas%2Derror%2Echeckbox%20label%2C%0A%2Ehas%2Derror%2Eradio%2Dinline%20label%2C%0A%2Ehas%2Derror%2Echeckbox%2Dinline%20label%20%7B%0Acolor%3A%20%23a94442%3B%0A%7D%0A%2Ehas%2Derror%20%2Eform%2Dcontrol%20%7B%0Aborder%2Dcolor%3A%20%23a94442%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%3B%0A%7D%0A%2Ehas%2Derror%20%2Eform%2Dcontrol%3Afocus%20%7B%0Aborder%2Dcolor%3A%20%23843534%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%2C%200%200%206px%20%23ce8483%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E075%29%2C%200%200%206px%20%23ce8483%3B%0A%7D%0A%2Ehas%2Derror%20%2Einput%2Dgroup%2Daddon%20%7B%0Acolor%3A%20%23a94442%3B%0Aborder%2Dcolor%3A%20%23a94442%3B%0Abackground%2Dcolor%3A%20%23f2dede%3B%0A%7D%0A%2Ehas%2Derror%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Acolor%3A%20%23a94442%3B%0A%7D%0A%2Ehas%2Dfeedback%20label%20%7E%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Atop%3A%2040px%3B%0A%7D%0A%2Ehas%2Dfeedback%20label%2Esr%2Donly%20%7E%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Atop%3A%200%3B%0A%7D%0A%2Ehelp%2Dblock%20%7B%0Adisplay%3A%20block%3B%0Amargin%2Dtop%3A%205px%3B%0Amargin%2Dbottom%3A%2010px%3B%0Acolor%3A%20%23737373%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Eform%2Dinline%20%2Eform%2Dgroup%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Amargin%2Dbottom%3A%200%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Eform%2Dinline%20%2Eform%2Dcontrol%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Awidth%3A%20auto%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Eform%2Dinline%20%2Eform%2Dcontrol%2Dstatic%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0A%7D%0A%2Eform%2Dinline%20%2Einput%2Dgroup%20%7B%0Adisplay%3A%20inline%2Dtable%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Eform%2Dinline%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Daddon%2C%0A%2Eform%2Dinline%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Dbtn%2C%0A%2Eform%2Dinline%20%2Einput%2Dgroup%20%2Eform%2Dcontrol%20%7B%0Awidth%3A%20auto%3B%0A%7D%0A%2Eform%2Dinline%20%2Einput%2Dgroup%20%3E%20%2Eform%2Dcontrol%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Eform%2Dinline%20%2Econtrol%2Dlabel%20%7B%0Amargin%2Dbottom%3A%200%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Eform%2Dinline%20%2Eradio%2C%0A%2Eform%2Dinline%20%2Echeckbox%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dbottom%3A%200%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Eform%2Dinline%20%2Eradio%20label%2C%0A%2Eform%2Dinline%20%2Echeckbox%20label%20%7B%0Apadding%2Dleft%3A%200%3B%0A%7D%0A%2Eform%2Dinline%20%2Eradio%20input%5Btype%3D%22radio%22%5D%2C%0A%2Eform%2Dinline%20%2Echeckbox%20input%5Btype%3D%22checkbox%22%5D%20%7B%0Aposition%3A%20relative%3B%0Amargin%2Dleft%3A%200%3B%0A%7D%0A%2Eform%2Dinline%20%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Atop%3A%200%3B%0A%7D%0A%7D%0A%2Eform%2Dhorizontal%20%2Eradio%2C%0A%2Eform%2Dhorizontal%20%2Echeckbox%2C%0A%2Eform%2Dhorizontal%20%2Eradio%2Dinline%2C%0A%2Eform%2Dhorizontal%20%2Echeckbox%2Dinline%20%7B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dbottom%3A%200%3B%0Apadding%2Dtop%3A%207px%3B%0A%7D%0A%2Eform%2Dhorizontal%20%2Eradio%2C%0A%2Eform%2Dhorizontal%20%2Echeckbox%20%7B%0Amin%2Dheight%3A%2042px%3B%0A%7D%0A%2Eform%2Dhorizontal%20%2Eform%2Dgroup%20%7B%0Amargin%2Dleft%3A%20%2D15px%3B%0Amargin%2Dright%3A%20%2D15px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Eform%2Dhorizontal%20%2Econtrol%2Dlabel%20%7B%0Atext%2Dalign%3A%20right%3B%0Amargin%2Dbottom%3A%200%3B%0Apadding%2Dtop%3A%207px%3B%0A%7D%0A%7D%0A%2Eform%2Dhorizontal%20%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Aright%3A%2015px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Eform%2Dhorizontal%20%2Eform%2Dgroup%2Dlg%20%2Econtrol%2Dlabel%20%7B%0Apadding%2Dtop%3A%2014%2E3px%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Eform%2Dhorizontal%20%2Eform%2Dgroup%2Dsm%20%2Econtrol%2Dlabel%20%7B%0Apadding%2Dtop%3A%206px%3B%0A%7D%0A%7D%0A%2Ebtn%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Amargin%2Dbottom%3A%200%3B%0Afont%2Dweight%3A%20normal%3B%0Atext%2Dalign%3A%20center%3B%0Avertical%2Dalign%3A%20middle%3B%0Atouch%2Daction%3A%20manipulation%3B%0Acursor%3A%20pointer%3B%0Abackground%2Dimage%3A%20none%3B%0Aborder%3A%201px%20solid%20transparent%3B%0Awhite%2Dspace%3A%20nowrap%3B%0Apadding%3A%206px%2012px%3B%0Afont%2Dsize%3A%2020px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Aborder%2Dradius%3A%200px%3B%0A%2Dwebkit%2Duser%2Dselect%3A%20none%3B%0A%2Dmoz%2Duser%2Dselect%3A%20none%3B%0A%2Dms%2Duser%2Dselect%3A%20none%3B%0Auser%2Dselect%3A%20none%3B%0A%7D%0A%2Ebtn%3Afocus%2C%0A%2Ebtn%3Aactive%3Afocus%2C%0A%2Ebtn%2Eactive%3Afocus%2C%0A%2Ebtn%2Efocus%2C%0A%2Ebtn%3Aactive%2Efocus%2C%0A%2Ebtn%2Eactive%2Efocus%20%7B%0Aoutline%3A%20thin%20dotted%3B%0Aoutline%3A%205px%20auto%20%2Dwebkit%2Dfocus%2Dring%2Dcolor%3B%0Aoutline%2Doffset%3A%20%2D2px%3B%0A%7D%0A%2Ebtn%3Ahover%2C%0A%2Ebtn%3Afocus%2C%0A%2Ebtn%2Efocus%20%7B%0Acolor%3A%20%23333%3B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0A%2Ebtn%3Aactive%2C%0A%2Ebtn%2Eactive%20%7B%0Aoutline%3A%200%3B%0Abackground%2Dimage%3A%20none%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%203px%205px%20rgba%280%2C%200%2C%200%2C%200%2E125%29%3B%0Abox%2Dshadow%3A%20inset%200%203px%205px%20rgba%280%2C%200%2C%200%2C%200%2E125%29%3B%0A%7D%0A%2Ebtn%2Edisabled%2C%0A%2Ebtn%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%20%7B%0Acursor%3A%20not%2Dallowed%3B%0Apointer%2Devents%3A%20none%3B%0Aopacity%3A%200%2E65%3B%0Afilter%3A%20alpha%28opacity%3D65%29%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20none%3B%0Abox%2Dshadow%3A%20none%3B%0A%7D%0A%2Ebtn%2Ddefault%20%7B%0Acolor%3A%20%23333%3B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0Aborder%2Dcolor%3A%20%23f7f7f7%3B%0A%7D%0A%2Ebtn%2Ddefault%3Ahover%2C%0A%2Ebtn%2Ddefault%3Afocus%2C%0A%2Ebtn%2Ddefault%2Efocus%2C%0A%2Ebtn%2Ddefault%3Aactive%2C%0A%2Ebtn%2Ddefault%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Ddefault%20%7B%0Acolor%3A%20%23333%3B%0Abackground%2Dcolor%3A%20%23dedede%3B%0Aborder%2Dcolor%3A%20%23d8d8d8%3B%0A%7D%0A%2Ebtn%2Ddefault%3Aactive%2C%0A%2Ebtn%2Ddefault%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Ddefault%20%7B%0Abackground%2Dimage%3A%20none%3B%0A%7D%0A%2Ebtn%2Ddefault%2Edisabled%2C%0A%2Ebtn%2Ddefault%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%2C%0A%2Ebtn%2Ddefault%2Edisabled%3Ahover%2C%0A%2Ebtn%2Ddefault%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%3Ahover%2C%0A%2Ebtn%2Ddefault%2Edisabled%3Afocus%2C%0A%2Ebtn%2Ddefault%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%3Afocus%2C%0A%2Ebtn%2Ddefault%2Edisabled%2Efocus%2C%0A%2Ebtn%2Ddefault%5Bdisabled%5D%2Efocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%2Efocus%2C%0A%2Ebtn%2Ddefault%2Edisabled%3Aactive%2C%0A%2Ebtn%2Ddefault%5Bdisabled%5D%3Aactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%3Aactive%2C%0A%2Ebtn%2Ddefault%2Edisabled%2Eactive%2C%0A%2Ebtn%2Ddefault%5Bdisabled%5D%2Eactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%2Eactive%20%7B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0Aborder%2Dcolor%3A%20%23f7f7f7%3B%0A%7D%0A%2Ebtn%2Ddefault%20%2Ebadge%20%7B%0Acolor%3A%20%23f7f7f7%3B%0Abackground%2Dcolor%3A%20%23333%3B%0A%7D%0A%2Ebtn%2Dprimary%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0Aborder%2Dcolor%3A%20%232e6da4%3B%0A%7D%0A%2Ebtn%2Dprimary%3Ahover%2C%0A%2Ebtn%2Dprimary%3Afocus%2C%0A%2Ebtn%2Dprimary%2Efocus%2C%0A%2Ebtn%2Dprimary%3Aactive%2C%0A%2Ebtn%2Dprimary%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dprimary%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23286090%3B%0Aborder%2Dcolor%3A%20%23204d74%3B%0A%7D%0A%2Ebtn%2Dprimary%3Aactive%2C%0A%2Ebtn%2Dprimary%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dprimary%20%7B%0Abackground%2Dimage%3A%20none%3B%0A%7D%0A%2Ebtn%2Dprimary%2Edisabled%2C%0A%2Ebtn%2Dprimary%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%2C%0A%2Ebtn%2Dprimary%2Edisabled%3Ahover%2C%0A%2Ebtn%2Dprimary%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%3Ahover%2C%0A%2Ebtn%2Dprimary%2Edisabled%3Afocus%2C%0A%2Ebtn%2Dprimary%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%3Afocus%2C%0A%2Ebtn%2Dprimary%2Edisabled%2Efocus%2C%0A%2Ebtn%2Dprimary%5Bdisabled%5D%2Efocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%2Efocus%2C%0A%2Ebtn%2Dprimary%2Edisabled%3Aactive%2C%0A%2Ebtn%2Dprimary%5Bdisabled%5D%3Aactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%3Aactive%2C%0A%2Ebtn%2Dprimary%2Edisabled%2Eactive%2C%0A%2Ebtn%2Dprimary%5Bdisabled%5D%2Eactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%2Eactive%20%7B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0Aborder%2Dcolor%3A%20%232e6da4%3B%0A%7D%0A%2Ebtn%2Dprimary%20%2Ebadge%20%7B%0Acolor%3A%20%23337ab7%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Ebtn%2Dsuccess%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%235cb85c%3B%0Aborder%2Dcolor%3A%20%234cae4c%3B%0A%7D%0A%2Ebtn%2Dsuccess%3Ahover%2C%0A%2Ebtn%2Dsuccess%3Afocus%2C%0A%2Ebtn%2Dsuccess%2Efocus%2C%0A%2Ebtn%2Dsuccess%3Aactive%2C%0A%2Ebtn%2Dsuccess%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dsuccess%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23449d44%3B%0Aborder%2Dcolor%3A%20%23398439%3B%0A%7D%0A%2Ebtn%2Dsuccess%3Aactive%2C%0A%2Ebtn%2Dsuccess%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dsuccess%20%7B%0Abackground%2Dimage%3A%20none%3B%0A%7D%0A%2Ebtn%2Dsuccess%2Edisabled%2C%0A%2Ebtn%2Dsuccess%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%2C%0A%2Ebtn%2Dsuccess%2Edisabled%3Ahover%2C%0A%2Ebtn%2Dsuccess%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%3Ahover%2C%0A%2Ebtn%2Dsuccess%2Edisabled%3Afocus%2C%0A%2Ebtn%2Dsuccess%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%3Afocus%2C%0A%2Ebtn%2Dsuccess%2Edisabled%2Efocus%2C%0A%2Ebtn%2Dsuccess%5Bdisabled%5D%2Efocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%2Efocus%2C%0A%2Ebtn%2Dsuccess%2Edisabled%3Aactive%2C%0A%2Ebtn%2Dsuccess%5Bdisabled%5D%3Aactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%3Aactive%2C%0A%2Ebtn%2Dsuccess%2Edisabled%2Eactive%2C%0A%2Ebtn%2Dsuccess%5Bdisabled%5D%2Eactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%2Eactive%20%7B%0Abackground%2Dcolor%3A%20%235cb85c%3B%0Aborder%2Dcolor%3A%20%234cae4c%3B%0A%7D%0A%2Ebtn%2Dsuccess%20%2Ebadge%20%7B%0Acolor%3A%20%235cb85c%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Ebtn%2Dinfo%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%235bc0de%3B%0Aborder%2Dcolor%3A%20%2346b8da%3B%0A%7D%0A%2Ebtn%2Dinfo%3Ahover%2C%0A%2Ebtn%2Dinfo%3Afocus%2C%0A%2Ebtn%2Dinfo%2Efocus%2C%0A%2Ebtn%2Dinfo%3Aactive%2C%0A%2Ebtn%2Dinfo%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dinfo%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%2331b0d5%3B%0Aborder%2Dcolor%3A%20%23269abc%3B%0A%7D%0A%2Ebtn%2Dinfo%3Aactive%2C%0A%2Ebtn%2Dinfo%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dinfo%20%7B%0Abackground%2Dimage%3A%20none%3B%0A%7D%0A%2Ebtn%2Dinfo%2Edisabled%2C%0A%2Ebtn%2Dinfo%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%2C%0A%2Ebtn%2Dinfo%2Edisabled%3Ahover%2C%0A%2Ebtn%2Dinfo%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%3Ahover%2C%0A%2Ebtn%2Dinfo%2Edisabled%3Afocus%2C%0A%2Ebtn%2Dinfo%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%3Afocus%2C%0A%2Ebtn%2Dinfo%2Edisabled%2Efocus%2C%0A%2Ebtn%2Dinfo%5Bdisabled%5D%2Efocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%2Efocus%2C%0A%2Ebtn%2Dinfo%2Edisabled%3Aactive%2C%0A%2Ebtn%2Dinfo%5Bdisabled%5D%3Aactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%3Aactive%2C%0A%2Ebtn%2Dinfo%2Edisabled%2Eactive%2C%0A%2Ebtn%2Dinfo%5Bdisabled%5D%2Eactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%2Eactive%20%7B%0Abackground%2Dcolor%3A%20%235bc0de%3B%0Aborder%2Dcolor%3A%20%2346b8da%3B%0A%7D%0A%2Ebtn%2Dinfo%20%2Ebadge%20%7B%0Acolor%3A%20%235bc0de%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Ebtn%2Dwarning%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23f0ad4e%3B%0Aborder%2Dcolor%3A%20%23eea236%3B%0A%7D%0A%2Ebtn%2Dwarning%3Ahover%2C%0A%2Ebtn%2Dwarning%3Afocus%2C%0A%2Ebtn%2Dwarning%2Efocus%2C%0A%2Ebtn%2Dwarning%3Aactive%2C%0A%2Ebtn%2Dwarning%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dwarning%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23ec971f%3B%0Aborder%2Dcolor%3A%20%23d58512%3B%0A%7D%0A%2Ebtn%2Dwarning%3Aactive%2C%0A%2Ebtn%2Dwarning%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Dwarning%20%7B%0Abackground%2Dimage%3A%20none%3B%0A%7D%0A%2Ebtn%2Dwarning%2Edisabled%2C%0A%2Ebtn%2Dwarning%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%2C%0A%2Ebtn%2Dwarning%2Edisabled%3Ahover%2C%0A%2Ebtn%2Dwarning%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%3Ahover%2C%0A%2Ebtn%2Dwarning%2Edisabled%3Afocus%2C%0A%2Ebtn%2Dwarning%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%3Afocus%2C%0A%2Ebtn%2Dwarning%2Edisabled%2Efocus%2C%0A%2Ebtn%2Dwarning%5Bdisabled%5D%2Efocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%2Efocus%2C%0A%2Ebtn%2Dwarning%2Edisabled%3Aactive%2C%0A%2Ebtn%2Dwarning%5Bdisabled%5D%3Aactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%3Aactive%2C%0A%2Ebtn%2Dwarning%2Edisabled%2Eactive%2C%0A%2Ebtn%2Dwarning%5Bdisabled%5D%2Eactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%2Eactive%20%7B%0Abackground%2Dcolor%3A%20%23f0ad4e%3B%0Aborder%2Dcolor%3A%20%23eea236%3B%0A%7D%0A%2Ebtn%2Dwarning%20%2Ebadge%20%7B%0Acolor%3A%20%23f0ad4e%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Ebtn%2Ddanger%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23d9534f%3B%0Aborder%2Dcolor%3A%20%23d43f3a%3B%0A%7D%0A%2Ebtn%2Ddanger%3Ahover%2C%0A%2Ebtn%2Ddanger%3Afocus%2C%0A%2Ebtn%2Ddanger%2Efocus%2C%0A%2Ebtn%2Ddanger%3Aactive%2C%0A%2Ebtn%2Ddanger%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Ddanger%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23c9302c%3B%0Aborder%2Dcolor%3A%20%23ac2925%3B%0A%7D%0A%2Ebtn%2Ddanger%3Aactive%2C%0A%2Ebtn%2Ddanger%2Eactive%2C%0A%2Eopen%20%3E%20%2Edropdown%2Dtoggle%2Ebtn%2Ddanger%20%7B%0Abackground%2Dimage%3A%20none%3B%0A%7D%0A%2Ebtn%2Ddanger%2Edisabled%2C%0A%2Ebtn%2Ddanger%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%2C%0A%2Ebtn%2Ddanger%2Edisabled%3Ahover%2C%0A%2Ebtn%2Ddanger%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%3Ahover%2C%0A%2Ebtn%2Ddanger%2Edisabled%3Afocus%2C%0A%2Ebtn%2Ddanger%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%3Afocus%2C%0A%2Ebtn%2Ddanger%2Edisabled%2Efocus%2C%0A%2Ebtn%2Ddanger%5Bdisabled%5D%2Efocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%2Efocus%2C%0A%2Ebtn%2Ddanger%2Edisabled%3Aactive%2C%0A%2Ebtn%2Ddanger%5Bdisabled%5D%3Aactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%3Aactive%2C%0A%2Ebtn%2Ddanger%2Edisabled%2Eactive%2C%0A%2Ebtn%2Ddanger%5Bdisabled%5D%2Eactive%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%2Eactive%20%7B%0Abackground%2Dcolor%3A%20%23d9534f%3B%0Aborder%2Dcolor%3A%20%23d43f3a%3B%0A%7D%0A%2Ebtn%2Ddanger%20%2Ebadge%20%7B%0Acolor%3A%20%23d9534f%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Ebtn%2Dlink%20%7B%0Acolor%3A%20%23337ab7%3B%0Afont%2Dweight%3A%20normal%3B%0Aborder%2Dradius%3A%200%3B%0A%7D%0A%2Ebtn%2Dlink%2C%0A%2Ebtn%2Dlink%3Aactive%2C%0A%2Ebtn%2Dlink%2Eactive%2C%0A%2Ebtn%2Dlink%5Bdisabled%5D%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dlink%20%7B%0Abackground%2Dcolor%3A%20transparent%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20none%3B%0Abox%2Dshadow%3A%20none%3B%0A%7D%0A%2Ebtn%2Dlink%2C%0A%2Ebtn%2Dlink%3Ahover%2C%0A%2Ebtn%2Dlink%3Afocus%2C%0A%2Ebtn%2Dlink%3Aactive%20%7B%0Aborder%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Ebtn%2Dlink%3Ahover%2C%0A%2Ebtn%2Dlink%3Afocus%20%7B%0Acolor%3A%20%2323527c%3B%0Atext%2Ddecoration%3A%20underline%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Ebtn%2Dlink%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dlink%3Ahover%2C%0A%2Ebtn%2Dlink%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Ebtn%2Dlink%3Afocus%20%7B%0Acolor%3A%20%23777777%3B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0A%2Ebtn%2Dlg%20%7B%0Apadding%3A%2010px%2016px%3B%0Afont%2Dsize%3A%2025px%3B%0Aline%2Dheight%3A%201%2E33%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Ebtn%2Dsm%20%7B%0Apadding%3A%205px%2010px%3B%0Afont%2Dsize%3A%2017px%3B%0Aline%2Dheight%3A%201%2E5%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Ebtn%2Dxs%20%7B%0Apadding%3A%201px%205px%3B%0Afont%2Dsize%3A%2017px%3B%0Aline%2Dheight%3A%201%2E5%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Ebtn%2Dblock%20%7B%0Adisplay%3A%20block%3B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Ebtn%2Dblock%20%2B%20%2Ebtn%2Dblock%20%7B%0Amargin%2Dtop%3A%205px%3B%0A%7D%0Ainput%5Btype%3D%22submit%22%5D%2Ebtn%2Dblock%2C%0Ainput%5Btype%3D%22reset%22%5D%2Ebtn%2Dblock%2C%0Ainput%5Btype%3D%22button%22%5D%2Ebtn%2Dblock%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Efade%20%7B%0Aopacity%3A%200%3B%0A%2Dwebkit%2Dtransition%3A%20opacity%200%2E15s%20linear%3B%0A%2Do%2Dtransition%3A%20opacity%200%2E15s%20linear%3B%0Atransition%3A%20opacity%200%2E15s%20linear%3B%0A%7D%0A%2Efade%2Ein%20%7B%0Aopacity%3A%201%3B%0A%7D%0A%2Ecollapse%20%7B%0Adisplay%3A%20none%3B%0Avisibility%3A%20hidden%3B%0A%7D%0A%2Ecollapse%2Ein%20%7B%0Adisplay%3A%20block%3B%0Avisibility%3A%20visible%3B%0A%7D%0Atr%2Ecollapse%2Ein%20%7B%0Adisplay%3A%20table%2Drow%3B%0A%7D%0Atbody%2Ecollapse%2Ein%20%7B%0Adisplay%3A%20table%2Drow%2Dgroup%3B%0A%7D%0A%2Ecollapsing%20%7B%0Aposition%3A%20relative%3B%0Aheight%3A%200%3B%0Aoverflow%3A%20hidden%3B%0A%2Dwebkit%2Dtransition%2Dproperty%3A%20height%2C%20visibility%3B%0Atransition%2Dproperty%3A%20height%2C%20visibility%3B%0A%2Dwebkit%2Dtransition%2Dduration%3A%200%2E35s%3B%0Atransition%2Dduration%3A%200%2E35s%3B%0A%2Dwebkit%2Dtransition%2Dtiming%2Dfunction%3A%20ease%3B%0Atransition%2Dtiming%2Dfunction%3A%20ease%3B%0A%7D%0A%2Ecaret%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Awidth%3A%200%3B%0Aheight%3A%200%3B%0Amargin%2Dleft%3A%202px%3B%0Avertical%2Dalign%3A%20middle%3B%0Aborder%2Dtop%3A%204px%20solid%3B%0Aborder%2Dright%3A%204px%20solid%20transparent%3B%0Aborder%2Dleft%3A%204px%20solid%20transparent%3B%0A%7D%0A%2Edropdown%20%7B%0Aposition%3A%20relative%3B%0A%7D%0A%2Edropdown%2Dtoggle%3Afocus%20%7B%0Aoutline%3A%200%3B%0A%7D%0A%2Edropdown%2Dmenu%20%7B%0Aposition%3A%20absolute%3B%0Atop%3A%20100%25%3B%0Aleft%3A%200%3B%0Az%2Dindex%3A%201000%3B%0Adisplay%3A%20none%3B%0Afloat%3A%20left%3B%0Amin%2Dwidth%3A%20160px%3B%0Apadding%3A%205px%200%3B%0Amargin%3A%202px%200%200%3B%0Alist%2Dstyle%3A%20none%3B%0Afont%2Dsize%3A%2020px%3B%0Atext%2Dalign%3A%20left%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0Aborder%3A%201px%20solid%20%23ccc%3B%0Aborder%3A%201px%20solid%20rgba%280%2C%200%2C%200%2C%200%2E15%29%3B%0Aborder%2Dradius%3A%200px%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%200%206px%2012px%20rgba%280%2C%200%2C%200%2C%200%2E175%29%3B%0Abox%2Dshadow%3A%200%206px%2012px%20rgba%280%2C%200%2C%200%2C%200%2E175%29%3B%0Abackground%2Dclip%3A%20padding%2Dbox%3B%0A%7D%0A%2Edropdown%2Dmenu%2Epull%2Dright%20%7B%0Aright%3A%200%3B%0Aleft%3A%20auto%3B%0A%7D%0A%2Edropdown%2Dmenu%20%2Edivider%20%7B%0Aheight%3A%201px%3B%0Amargin%3A%2016%2E5px%200%3B%0Aoverflow%3A%20hidden%3B%0Abackground%2Dcolor%3A%20%23e5e5e5%3B%0A%7D%0A%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%20%7B%0Adisplay%3A%20block%3B%0Apadding%3A%203px%2020px%3B%0Aclear%3A%20both%3B%0Afont%2Dweight%3A%20normal%3B%0Aline%2Dheight%3A%201%2E75%3B%0Acolor%3A%20%23333333%3B%0Awhite%2Dspace%3A%20nowrap%3B%0A%7D%0A%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Ahover%2C%0A%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Afocus%20%7B%0Atext%2Ddecoration%3A%20none%3B%0Acolor%3A%20%23262626%3B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0A%7D%0A%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Atext%2Ddecoration%3A%20none%3B%0Aoutline%3A%200%3B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%2C%0A%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Ahover%2C%0A%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23777777%3B%0A%7D%0A%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Ahover%2C%0A%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Afocus%20%7B%0Atext%2Ddecoration%3A%20none%3B%0Abackground%2Dcolor%3A%20transparent%3B%0Abackground%2Dimage%3A%20none%3B%0Afilter%3A%20progid%3ADXImageTransform%2EMicrosoft%2Egradient%28enabled%20%3D%20false%29%3B%0Acursor%3A%20not%2Dallowed%3B%0A%7D%0A%2Eopen%20%3E%20%2Edropdown%2Dmenu%20%7B%0Adisplay%3A%20block%3B%0A%7D%0A%2Eopen%20%3E%20a%20%7B%0Aoutline%3A%200%3B%0A%7D%0A%2Edropdown%2Dmenu%2Dright%20%7B%0Aleft%3A%20auto%3B%0Aright%3A%200%3B%0A%7D%0A%2Edropdown%2Dmenu%2Dleft%20%7B%0Aleft%3A%200%3B%0Aright%3A%20auto%3B%0A%7D%0A%2Edropdown%2Dheader%20%7B%0Adisplay%3A%20block%3B%0Apadding%3A%203px%2020px%3B%0Afont%2Dsize%3A%2017px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Acolor%3A%20%23777777%3B%0Awhite%2Dspace%3A%20nowrap%3B%0A%7D%0A%2Edropdown%2Dbackdrop%20%7B%0Aposition%3A%20fixed%3B%0Aleft%3A%200%3B%0Aright%3A%200%3B%0Abottom%3A%200%3B%0Atop%3A%200%3B%0Az%2Dindex%3A%20990%3B%0A%7D%0A%2Epull%2Dright%20%3E%20%2Edropdown%2Dmenu%20%7B%0Aright%3A%200%3B%0Aleft%3A%20auto%3B%0A%7D%0A%2Edropup%20%2Ecaret%2C%0A%2Enavbar%2Dfixed%2Dbottom%20%2Edropdown%20%2Ecaret%20%7B%0Aborder%2Dtop%3A%200%3B%0Aborder%2Dbottom%3A%204px%20solid%3B%0Acontent%3A%20%22%22%3B%0A%7D%0A%2Edropup%20%2Edropdown%2Dmenu%2C%0A%2Enavbar%2Dfixed%2Dbottom%20%2Edropdown%20%2Edropdown%2Dmenu%20%7B%0Atop%3A%20auto%3B%0Abottom%3A%20100%25%3B%0Amargin%2Dbottom%3A%201px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dright%20%2Edropdown%2Dmenu%20%7B%0Aleft%3A%20auto%3B%0Aright%3A%200%3B%0A%7D%0A%2Enavbar%2Dright%20%2Edropdown%2Dmenu%2Dleft%20%7B%0Aleft%3A%200%3B%0Aright%3A%20auto%3B%0A%7D%0A%7D%0A%2Enav%20%7B%0Amargin%2Dbottom%3A%200%3B%0Apadding%2Dleft%3A%200%3B%0Alist%2Dstyle%3A%20none%3B%0A%7D%0A%2Enav%20%3E%20li%20%7B%0Aposition%3A%20relative%3B%0Adisplay%3A%20block%3B%0A%7D%0A%2Enav%20%3E%20li%20%3E%20a%20%7B%0Aposition%3A%20relative%3B%0Adisplay%3A%20block%3B%0Apadding%3A%2010px%2015px%3B%0A%7D%0A%2Enav%20%3E%20li%20%3E%20a%3Ahover%2C%0A%2Enav%20%3E%20li%20%3E%20a%3Afocus%20%7B%0Atext%2Ddecoration%3A%20none%3B%0Abackground%2Dcolor%3A%20%23eeeeee%3B%0A%7D%0A%2Enav%20%3E%20li%2Edisabled%20%3E%20a%20%7B%0Acolor%3A%20%23777777%3B%0A%7D%0A%2Enav%20%3E%20li%2Edisabled%20%3E%20a%3Ahover%2C%0A%2Enav%20%3E%20li%2Edisabled%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23777777%3B%0Atext%2Ddecoration%3A%20none%3B%0Abackground%2Dcolor%3A%20transparent%3B%0Acursor%3A%20not%2Dallowed%3B%0A%7D%0A%2Enav%20%2Eopen%20%3E%20a%2C%0A%2Enav%20%2Eopen%20%3E%20a%3Ahover%2C%0A%2Enav%20%2Eopen%20%3E%20a%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23eeeeee%3B%0Aborder%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Enav%20%2Enav%2Ddivider%20%7B%0Aheight%3A%201px%3B%0Amargin%3A%2016%2E5px%200%3B%0Aoverflow%3A%20hidden%3B%0Abackground%2Dcolor%3A%20%23e5e5e5%3B%0A%7D%0A%2Enav%20%3E%20li%20%3E%20a%20%3E%20img%20%7B%0Amax%2Dwidth%3A%20none%3B%0A%7D%0A%2Enav%2Dtabs%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Enav%2Dtabs%20%3E%20li%20%7B%0Afloat%3A%20left%3B%0Amargin%2Dbottom%3A%20%2D1px%3B%0A%7D%0A%2Enav%2Dtabs%20%3E%20li%20%3E%20a%20%7B%0Amargin%2Dright%3A%202px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Aborder%3A%201px%20solid%20transparent%3B%0Aborder%2Dradius%3A%200px%200px%200%200%3B%0A%7D%0A%2Enav%2Dtabs%20%3E%20li%20%3E%20a%3Ahover%20%7B%0Aborder%2Dcolor%3A%20%23eeeeee%20%23eeeeee%20%23ddd%3B%0A%7D%0A%2Enav%2Dtabs%20%3E%20li%2Eactive%20%3E%20a%2C%0A%2Enav%2Dtabs%20%3E%20li%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enav%2Dtabs%20%3E%20li%2Eactive%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23555555%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0Aborder%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dbottom%2Dcolor%3A%20transparent%3B%0Acursor%3A%20default%3B%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%7B%0Awidth%3A%20100%25%3B%0Aborder%2Dbottom%3A%200%3B%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20li%20%7B%0Afloat%3A%20none%3B%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Atext%2Dalign%3A%20center%3B%0Amargin%2Dbottom%3A%205px%3B%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20%2Edropdown%20%2Edropdown%2Dmenu%20%7B%0Atop%3A%20auto%3B%0Aleft%3A%20auto%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20li%20%7B%0Adisplay%3A%20table%2Dcell%3B%0Awidth%3A%201%25%3B%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Amargin%2Dright%3A%200%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dradius%3A%200px%200px%200%200%3B%0A%7D%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enav%2Dtabs%2Enav%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23fff%3B%0A%7D%0A%7D%0A%2Enav%2Dpills%20%3E%20li%20%7B%0Afloat%3A%20left%3B%0A%7D%0A%2Enav%2Dpills%20%3E%20li%20%3E%20a%20%7B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Enav%2Dpills%20%3E%20li%20%2B%20li%20%7B%0Amargin%2Dleft%3A%202px%3B%0A%7D%0A%2Enav%2Dpills%20%3E%20li%2Eactive%20%3E%20a%2C%0A%2Enav%2Dpills%20%3E%20li%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enav%2Dpills%20%3E%20li%2Eactive%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Enav%2Dstacked%20%3E%20li%20%7B%0Afloat%3A%20none%3B%0A%7D%0A%2Enav%2Dstacked%20%3E%20li%20%2B%20li%20%7B%0Amargin%2Dtop%3A%202px%3B%0Amargin%2Dleft%3A%200%3B%0A%7D%0A%2Enav%2Djustified%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Enav%2Djustified%20%3E%20li%20%7B%0Afloat%3A%20none%3B%0A%7D%0A%2Enav%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Atext%2Dalign%3A%20center%3B%0Amargin%2Dbottom%3A%205px%3B%0A%7D%0A%2Enav%2Djustified%20%3E%20%2Edropdown%20%2Edropdown%2Dmenu%20%7B%0Atop%3A%20auto%3B%0Aleft%3A%20auto%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enav%2Djustified%20%3E%20li%20%7B%0Adisplay%3A%20table%2Dcell%3B%0Awidth%3A%201%25%3B%0A%7D%0A%2Enav%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%7D%0A%2Enav%2Dtabs%2Djustified%20%7B%0Aborder%2Dbottom%3A%200%3B%0A%7D%0A%2Enav%2Dtabs%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Amargin%2Dright%3A%200%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Enav%2Dtabs%2Djustified%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enav%2Dtabs%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enav%2Dtabs%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enav%2Dtabs%2Djustified%20%3E%20li%20%3E%20a%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dradius%3A%200px%200px%200%200%3B%0A%7D%0A%2Enav%2Dtabs%2Djustified%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enav%2Dtabs%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enav%2Dtabs%2Djustified%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23fff%3B%0A%7D%0A%7D%0A%2Etab%2Dcontent%20%3E%20%2Etab%2Dpane%20%7B%0Adisplay%3A%20none%3B%0Avisibility%3A%20hidden%3B%0A%7D%0A%2Etab%2Dcontent%20%3E%20%2Eactive%20%7B%0Adisplay%3A%20block%3B%0Avisibility%3A%20visible%3B%0A%7D%0A%2Enav%2Dtabs%20%2Edropdown%2Dmenu%20%7B%0Amargin%2Dtop%3A%20%2D1px%3B%0Aborder%2Dtop%2Dright%2Dradius%3A%200%3B%0Aborder%2Dtop%2Dleft%2Dradius%3A%200%3B%0A%7D%0A%2Enavbar%20%7B%0Aposition%3A%20relative%3B%0Amin%2Dheight%3A%2050px%3B%0Amargin%2Dbottom%3A%2035px%3B%0Aborder%3A%201px%20solid%20transparent%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%20%7B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dheader%20%7B%0Afloat%3A%20left%3B%0A%7D%0A%7D%0A%2Enavbar%2Dcollapse%20%7B%0Aoverflow%2Dx%3A%20visible%3B%0Apadding%2Dright%3A%2015px%3B%0Apadding%2Dleft%3A%2015px%3B%0Aborder%2Dtop%3A%201px%20solid%20transparent%3B%0Abox%2Dshadow%3A%20inset%200%201px%200%20rgba%28255%2C%20255%2C%20255%2C%200%2E1%29%3B%0A%2Dwebkit%2Doverflow%2Dscrolling%3A%20touch%3B%0A%7D%0A%2Enavbar%2Dcollapse%2Ein%20%7B%0Aoverflow%2Dy%3A%20auto%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dcollapse%20%7B%0Awidth%3A%20auto%3B%0Aborder%2Dtop%3A%200%3B%0Abox%2Dshadow%3A%20none%3B%0A%7D%0A%2Enavbar%2Dcollapse%2Ecollapse%20%7B%0Adisplay%3A%20block%20%21important%3B%0Avisibility%3A%20visible%20%21important%3B%0Aheight%3A%20auto%20%21important%3B%0Apadding%2Dbottom%3A%200%3B%0Aoverflow%3A%20visible%20%21important%3B%0A%7D%0A%2Enavbar%2Dcollapse%2Ein%20%7B%0Aoverflow%2Dy%3A%20visible%3B%0A%7D%0A%2Enavbar%2Dfixed%2Dtop%20%2Enavbar%2Dcollapse%2C%0A%2Enavbar%2Dstatic%2Dtop%20%2Enavbar%2Dcollapse%2C%0A%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dcollapse%20%7B%0Apadding%2Dleft%3A%200%3B%0Apadding%2Dright%3A%200%3B%0A%7D%0A%7D%0A%2Enavbar%2Dfixed%2Dtop%20%2Enavbar%2Dcollapse%2C%0A%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dcollapse%20%7B%0Amax%2Dheight%3A%20340px%3B%0A%7D%0A%40media%20%28max%2Ddevice%2Dwidth%3A%20480px%29%20and%20%28orientation%3A%20landscape%29%20%7B%0A%2Enavbar%2Dfixed%2Dtop%20%2Enavbar%2Dcollapse%2C%0A%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dcollapse%20%7B%0Amax%2Dheight%3A%20200px%3B%0A%7D%0A%7D%0A%2Econtainer%20%3E%20%2Enavbar%2Dheader%2C%0A%2Econtainer%2Dfluid%20%3E%20%2Enavbar%2Dheader%2C%0A%2Econtainer%20%3E%20%2Enavbar%2Dcollapse%2C%0A%2Econtainer%2Dfluid%20%3E%20%2Enavbar%2Dcollapse%20%7B%0Amargin%2Dright%3A%20%2D15px%3B%0Amargin%2Dleft%3A%20%2D15px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Econtainer%20%3E%20%2Enavbar%2Dheader%2C%0A%2Econtainer%2Dfluid%20%3E%20%2Enavbar%2Dheader%2C%0A%2Econtainer%20%3E%20%2Enavbar%2Dcollapse%2C%0A%2Econtainer%2Dfluid%20%3E%20%2Enavbar%2Dcollapse%20%7B%0Amargin%2Dright%3A%200%3B%0Amargin%2Dleft%3A%200%3B%0A%7D%0A%7D%0A%2Enavbar%2Dstatic%2Dtop%20%7B%0Az%2Dindex%3A%201000%3B%0Aborder%2Dwidth%3A%200%200%201px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dstatic%2Dtop%20%7B%0Aborder%2Dradius%3A%200%3B%0A%7D%0A%7D%0A%2Enavbar%2Dfixed%2Dtop%2C%0A%2Enavbar%2Dfixed%2Dbottom%20%7B%0Aposition%3A%20fixed%3B%0Aright%3A%200%3B%0Aleft%3A%200%3B%0Az%2Dindex%3A%201030%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dfixed%2Dtop%2C%0A%2Enavbar%2Dfixed%2Dbottom%20%7B%0Aborder%2Dradius%3A%200%3B%0A%7D%0A%7D%0A%2Enavbar%2Dfixed%2Dtop%20%7B%0Atop%3A%200%3B%0Aborder%2Dwidth%3A%200%200%201px%3B%0A%7D%0A%2Enavbar%2Dfixed%2Dbottom%20%7B%0Abottom%3A%200%3B%0Amargin%2Dbottom%3A%200%3B%0Aborder%2Dwidth%3A%201px%200%200%3B%0A%7D%0A%2Enavbar%2Dbrand%20%7B%0Afloat%3A%20left%3B%0Apadding%3A%207%2E5px%2015px%3B%0Afont%2Dsize%3A%2025px%3B%0Aline%2Dheight%3A%2035px%3B%0Aheight%3A%2050px%3B%0A%7D%0A%2Enavbar%2Dbrand%3Ahover%2C%0A%2Enavbar%2Dbrand%3Afocus%20%7B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0A%2Enavbar%2Dbrand%20%3E%20img%20%7B%0Adisplay%3A%20block%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%20%3E%20%2Econtainer%20%2Enavbar%2Dbrand%2C%0A%2Enavbar%20%3E%20%2Econtainer%2Dfluid%20%2Enavbar%2Dbrand%20%7B%0Amargin%2Dleft%3A%20%2D15px%3B%0A%7D%0A%7D%0A%2Enavbar%2Dtoggle%20%7B%0Aposition%3A%20relative%3B%0Afloat%3A%20right%3B%0Amargin%2Dright%3A%2015px%3B%0Apadding%3A%209px%2010px%3B%0Amargin%2Dtop%3A%208px%3B%0Amargin%2Dbottom%3A%208px%3B%0Abackground%2Dcolor%3A%20transparent%3B%0Abackground%2Dimage%3A%20none%3B%0Aborder%3A%201px%20solid%20transparent%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Enavbar%2Dtoggle%3Afocus%20%7B%0Aoutline%3A%200%3B%0A%7D%0A%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%20%7B%0Adisplay%3A%20block%3B%0Awidth%3A%2022px%3B%0Aheight%3A%202px%3B%0Aborder%2Dradius%3A%201px%3B%0A%7D%0A%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%20%2B%20%2Eicon%2Dbar%20%7B%0Amargin%2Dtop%3A%204px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dtoggle%20%7B%0Adisplay%3A%20none%3B%0A%7D%0A%7D%0A%2Enavbar%2Dnav%20%7B%0Amargin%3A%203%2E75px%20%2D15px%3B%0A%7D%0A%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%20%7B%0Apadding%2Dtop%3A%2010px%3B%0Apadding%2Dbottom%3A%2010px%3B%0Aline%2Dheight%3A%2035px%3B%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%7B%0Aposition%3A%20static%3B%0Afloat%3A%20none%3B%0Awidth%3A%20auto%3B%0Amargin%2Dtop%3A%200%3B%0Abackground%2Dcolor%3A%20transparent%3B%0Aborder%3A%200%3B%0Abox%2Dshadow%3A%20none%3B%0A%7D%0A%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%2C%0A%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%2Edropdown%2Dheader%20%7B%0Apadding%3A%205px%2015px%205px%2025px%3B%0A%7D%0A%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%20%7B%0Aline%2Dheight%3A%2035px%3B%0A%7D%0A%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Afocus%20%7B%0Abackground%2Dimage%3A%20none%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dnav%20%7B%0Afloat%3A%20left%3B%0Amargin%3A%200%3B%0A%7D%0A%2Enavbar%2Dnav%20%3E%20li%20%7B%0Afloat%3A%20left%3B%0A%7D%0A%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%20%7B%0Apadding%2Dtop%3A%207%2E5px%3B%0Apadding%2Dbottom%3A%207%2E5px%3B%0A%7D%0A%7D%0A%2Enavbar%2Dform%20%7B%0Amargin%2Dleft%3A%20%2D15px%3B%0Amargin%2Dright%3A%20%2D15px%3B%0Apadding%3A%2010px%2015px%3B%0Aborder%2Dtop%3A%201px%20solid%20transparent%3B%0Aborder%2Dbottom%3A%201px%20solid%20transparent%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%200%20rgba%28255%2C%20255%2C%20255%2C%200%2E1%29%2C%200%201px%200%20rgba%28255%2C%20255%2C%20255%2C%200%2E1%29%3B%0Abox%2Dshadow%3A%20inset%200%201px%200%20rgba%28255%2C%20255%2C%20255%2C%200%2E1%29%2C%200%201px%200%20rgba%28255%2C%20255%2C%20255%2C%200%2E1%29%3B%0Amargin%2Dtop%3A%200%2E5px%3B%0Amargin%2Dbottom%3A%200%2E5px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dform%20%2Eform%2Dgroup%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Amargin%2Dbottom%3A%200%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Enavbar%2Dform%20%2Eform%2Dcontrol%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Awidth%3A%20auto%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Enavbar%2Dform%20%2Eform%2Dcontrol%2Dstatic%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0A%7D%0A%2Enavbar%2Dform%20%2Einput%2Dgroup%20%7B%0Adisplay%3A%20inline%2Dtable%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Enavbar%2Dform%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Daddon%2C%0A%2Enavbar%2Dform%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Dbtn%2C%0A%2Enavbar%2Dform%20%2Einput%2Dgroup%20%2Eform%2Dcontrol%20%7B%0Awidth%3A%20auto%3B%0A%7D%0A%2Enavbar%2Dform%20%2Einput%2Dgroup%20%3E%20%2Eform%2Dcontrol%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0A%2Enavbar%2Dform%20%2Econtrol%2Dlabel%20%7B%0Amargin%2Dbottom%3A%200%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Enavbar%2Dform%20%2Eradio%2C%0A%2Enavbar%2Dform%20%2Echeckbox%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dbottom%3A%200%3B%0Avertical%2Dalign%3A%20middle%3B%0A%7D%0A%2Enavbar%2Dform%20%2Eradio%20label%2C%0A%2Enavbar%2Dform%20%2Echeckbox%20label%20%7B%0Apadding%2Dleft%3A%200%3B%0A%7D%0A%2Enavbar%2Dform%20%2Eradio%20input%5Btype%3D%22radio%22%5D%2C%0A%2Enavbar%2Dform%20%2Echeckbox%20input%5Btype%3D%22checkbox%22%5D%20%7B%0Aposition%3A%20relative%3B%0Amargin%2Dleft%3A%200%3B%0A%7D%0A%2Enavbar%2Dform%20%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%2Dfeedback%20%7B%0Atop%3A%200%3B%0A%7D%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Enavbar%2Dform%20%2Eform%2Dgroup%20%7B%0Amargin%2Dbottom%3A%205px%3B%0A%7D%0A%2Enavbar%2Dform%20%2Eform%2Dgroup%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dform%20%7B%0Awidth%3A%20auto%3B%0Aborder%3A%200%3B%0Amargin%2Dleft%3A%200%3B%0Amargin%2Dright%3A%200%3B%0Apadding%2Dtop%3A%200%3B%0Apadding%2Dbottom%3A%200%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20none%3B%0Abox%2Dshadow%3A%20none%3B%0A%7D%0A%7D%0A%2Enavbar%2Dnav%20%3E%20li%20%3E%20%2Edropdown%2Dmenu%20%7B%0Amargin%2Dtop%3A%200%3B%0Aborder%2Dtop%2Dright%2Dradius%3A%200%3B%0Aborder%2Dtop%2Dleft%2Dradius%3A%200%3B%0A%7D%0A%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dnav%20%3E%20li%20%3E%20%2Edropdown%2Dmenu%20%7B%0Aborder%2Dtop%2Dright%2Dradius%3A%200px%3B%0Aborder%2Dtop%2Dleft%2Dradius%3A%200px%3B%0Aborder%2Dbottom%2Dright%2Dradius%3A%200%3B%0Aborder%2Dbottom%2Dleft%2Dradius%3A%200%3B%0A%7D%0A%2Enavbar%2Dbtn%20%7B%0Amargin%2Dtop%3A%200%2E5px%3B%0Amargin%2Dbottom%3A%200%2E5px%3B%0A%7D%0A%2Enavbar%2Dbtn%2Ebtn%2Dsm%20%7B%0Amargin%2Dtop%3A%206%2E5px%3B%0Amargin%2Dbottom%3A%206%2E5px%3B%0A%7D%0A%2Enavbar%2Dbtn%2Ebtn%2Dxs%20%7B%0Amargin%2Dtop%3A%2014px%3B%0Amargin%2Dbottom%3A%2014px%3B%0A%7D%0A%2Enavbar%2Dtext%20%7B%0Amargin%2Dtop%3A%207%2E5px%3B%0Amargin%2Dbottom%3A%207%2E5px%3B%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dtext%20%7B%0Afloat%3A%20left%3B%0Amargin%2Dleft%3A%2015px%3B%0Amargin%2Dright%3A%2015px%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20%7B%0A%2Enavbar%2Dleft%20%7B%0Afloat%3A%20left%20%21important%3B%0A%7D%0A%2Enavbar%2Dright%20%7B%0Afloat%3A%20right%20%21important%3B%0Amargin%2Dright%3A%20%2D15px%3B%0A%7D%0A%2Enavbar%2Dright%20%7E%20%2Enavbar%2Dright%20%7B%0Amargin%2Dright%3A%200%3B%0A%7D%0A%7D%0A%2Enavbar%2Ddefault%20%7B%0Abackground%2Dcolor%3A%20%23f8f8f8%3B%0Aborder%2Dcolor%3A%20%23e7e7e7%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dbrand%20%7B%0Acolor%3A%20%23777%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dbrand%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dbrand%3Afocus%20%7B%0Acolor%3A%20%235e5e5e%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dtext%20%7B%0Acolor%3A%20%23777%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%20%7B%0Acolor%3A%20%23777%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23333%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23555%3B%0Abackground%2Dcolor%3A%20%23e7e7e7%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Edisabled%20%3E%20a%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Edisabled%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Edisabled%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23ccc%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%20%7B%0Aborder%2Dcolor%3A%20%23ddd%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23ddd%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%20%7B%0Abackground%2Dcolor%3A%20%23888%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dcollapse%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dform%20%7B%0Aborder%2Dcolor%3A%20%23e7e7e7%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Eopen%20%3E%20a%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Eopen%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%3E%20%2Eopen%20%3E%20a%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23e7e7e7%3B%0Acolor%3A%20%23555%3B%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%20%7B%0Acolor%3A%20%23777%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23333%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23555%3B%0Abackground%2Dcolor%3A%20%23e7e7e7%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23ccc%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dlink%20%7B%0Acolor%3A%20%23777%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Enavbar%2Dlink%3Ahover%20%7B%0Acolor%3A%20%23333%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%20%7B%0Acolor%3A%20%23777%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Afocus%20%7B%0Acolor%3A%20%23333%3B%0A%7D%0A%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Ahover%2C%0A%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Afocus%20%7B%0Acolor%3A%20%23ccc%3B%0A%7D%0A%2Enavbar%2Dinverse%20%7B%0Abackground%2Dcolor%3A%20%23222%3B%0Aborder%2Dcolor%3A%20%23080808%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dbrand%20%7B%0Acolor%3A%20%239d9d9d%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dbrand%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dbrand%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dtext%20%7B%0Acolor%3A%20%239d9d9d%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%20%7B%0Acolor%3A%20%239d9d9d%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20li%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23080808%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Edisabled%20%3E%20a%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Edisabled%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Edisabled%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23444%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%20%7B%0Aborder%2Dcolor%3A%20%23333%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23333%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dcollapse%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dform%20%7B%0Aborder%2Dcolor%3A%20%23101010%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Eopen%20%3E%20a%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Eopen%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%3E%20%2Eopen%20%3E%20a%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23080808%3B%0Acolor%3A%20%23fff%3B%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Edropdown%2Dheader%20%7B%0Aborder%2Dcolor%3A%20%23080808%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%2Edivider%20%7B%0Abackground%2Dcolor%3A%20%23080808%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%20%7B%0Acolor%3A%20%239d9d9d%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20li%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Eactive%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23080808%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%3E%20%2Edisabled%20%3E%20a%3Afocus%20%7B%0Acolor%3A%20%23444%3B%0Abackground%2Dcolor%3A%20transparent%3B%0A%7D%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dlink%20%7B%0Acolor%3A%20%239d9d9d%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Enavbar%2Dlink%3Ahover%20%7B%0Acolor%3A%20%23fff%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%20%7B%0Acolor%3A%20%239d9d9d%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0A%7D%0A%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%5Bdisabled%5D%3Ahover%2C%0Afieldset%5Bdisabled%5D%20%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Ahover%2C%0A%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%5Bdisabled%5D%3Afocus%2C%0Afieldset%5Bdisabled%5D%20%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Afocus%20%7B%0Acolor%3A%20%23444%3B%0A%7D%0A%2Elabel%20%7B%0Adisplay%3A%20inline%3B%0Apadding%3A%20%2E2em%20%2E6em%20%2E3em%3B%0Afont%2Dsize%3A%2075%25%3B%0Afont%2Dweight%3A%20bold%3B%0Aline%2Dheight%3A%201%3B%0Acolor%3A%20%23fff%3B%0Atext%2Dalign%3A%20center%3B%0Awhite%2Dspace%3A%20nowrap%3B%0Avertical%2Dalign%3A%20baseline%3B%0Aborder%2Dradius%3A%20%2E25em%3B%0A%7D%0Aa%2Elabel%3Ahover%2C%0Aa%2Elabel%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Atext%2Ddecoration%3A%20none%3B%0Acursor%3A%20pointer%3B%0A%7D%0A%2Elabel%3Aempty%20%7B%0Adisplay%3A%20none%3B%0A%7D%0A%2Ebtn%20%2Elabel%20%7B%0Aposition%3A%20relative%3B%0Atop%3A%20%2D1px%3B%0A%7D%0A%2Elabel%2Ddefault%20%7B%0Abackground%2Dcolor%3A%20%23777777%3B%0A%7D%0A%2Elabel%2Ddefault%5Bhref%5D%3Ahover%2C%0A%2Elabel%2Ddefault%5Bhref%5D%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%235e5e5e%3B%0A%7D%0A%2Elabel%2Dprimary%20%7B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Elabel%2Dprimary%5Bhref%5D%3Ahover%2C%0A%2Elabel%2Dprimary%5Bhref%5D%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23286090%3B%0A%7D%0A%2Elabel%2Dsuccess%20%7B%0Abackground%2Dcolor%3A%20%235cb85c%3B%0A%7D%0A%2Elabel%2Dsuccess%5Bhref%5D%3Ahover%2C%0A%2Elabel%2Dsuccess%5Bhref%5D%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23449d44%3B%0A%7D%0A%2Elabel%2Dinfo%20%7B%0Abackground%2Dcolor%3A%20%235bc0de%3B%0A%7D%0A%2Elabel%2Dinfo%5Bhref%5D%3Ahover%2C%0A%2Elabel%2Dinfo%5Bhref%5D%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%2331b0d5%3B%0A%7D%0A%2Elabel%2Dwarning%20%7B%0Abackground%2Dcolor%3A%20%23f0ad4e%3B%0A%7D%0A%2Elabel%2Dwarning%5Bhref%5D%3Ahover%2C%0A%2Elabel%2Dwarning%5Bhref%5D%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23ec971f%3B%0A%7D%0A%2Elabel%2Ddanger%20%7B%0Abackground%2Dcolor%3A%20%23d9534f%3B%0A%7D%0A%2Elabel%2Ddanger%5Bhref%5D%3Ahover%2C%0A%2Elabel%2Ddanger%5Bhref%5D%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23c9302c%3B%0A%7D%0A%2Ebadge%20%7B%0Adisplay%3A%20inline%2Dblock%3B%0Amin%2Dwidth%3A%2010px%3B%0Apadding%3A%203px%207px%3B%0Afont%2Dsize%3A%2017px%3B%0Afont%2Dweight%3A%20bold%3B%0Acolor%3A%20%23fff%3B%0Aline%2Dheight%3A%201%3B%0Avertical%2Dalign%3A%20baseline%3B%0Awhite%2Dspace%3A%20nowrap%3B%0Atext%2Dalign%3A%20center%3B%0Abackground%2Dcolor%3A%20%23777777%3B%0Aborder%2Dradius%3A%2010px%3B%0A%7D%0A%2Ebadge%3Aempty%20%7B%0Adisplay%3A%20none%3B%0A%7D%0A%2Ebtn%20%2Ebadge%20%7B%0Aposition%3A%20relative%3B%0Atop%3A%20%2D1px%3B%0A%7D%0A%2Ebtn%2Dxs%20%2Ebadge%20%7B%0Atop%3A%200%3B%0Apadding%3A%201px%205px%3B%0A%7D%0Aa%2Ebadge%3Ahover%2C%0Aa%2Ebadge%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Atext%2Ddecoration%3A%20none%3B%0Acursor%3A%20pointer%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Eactive%20%3E%20%2Ebadge%2C%0A%2Enav%2Dpills%20%3E%20%2Eactive%20%3E%20a%20%3E%20%2Ebadge%20%7B%0Acolor%3A%20%23337ab7%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%20%3E%20%2Ebadge%20%7B%0Afloat%3A%20right%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%20%3E%20%2Ebadge%20%2B%20%2Ebadge%20%7B%0Amargin%2Dright%3A%205px%3B%0A%7D%0A%2Enav%2Dpills%20%3E%20li%20%3E%20a%20%3E%20%2Ebadge%20%7B%0Amargin%2Dleft%3A%203px%3B%0A%7D%0A%2Ealert%20%7B%0Apadding%3A%2015px%3B%0Amargin%2Dbottom%3A%2035px%3B%0Aborder%3A%201px%20solid%20transparent%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Ealert%20h4%20%7B%0Amargin%2Dtop%3A%200%3B%0Acolor%3A%20inherit%3B%0A%7D%0A%2Ealert%20%2Ealert%2Dlink%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ealert%20%3E%20p%2C%0A%2Ealert%20%3E%20ul%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Ealert%20%3E%20p%20%2B%20p%20%7B%0Amargin%2Dtop%3A%205px%3B%0A%7D%0A%2Ealert%2Ddismissable%2C%0A%2Ealert%2Ddismissible%20%7B%0Apadding%2Dright%3A%2035px%3B%0A%7D%0A%2Ealert%2Ddismissable%20%2Eclose%2C%0A%2Ealert%2Ddismissible%20%2Eclose%20%7B%0Aposition%3A%20relative%3B%0Atop%3A%20%2D2px%3B%0Aright%3A%20%2D21px%3B%0Acolor%3A%20inherit%3B%0A%7D%0A%2Ealert%2Dsuccess%20%7B%0Abackground%2Dcolor%3A%20%23dff0d8%3B%0Aborder%2Dcolor%3A%20%23d6e9c6%3B%0Acolor%3A%20%233c763d%3B%0A%7D%0A%2Ealert%2Dsuccess%20hr%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23c9e2b3%3B%0A%7D%0A%2Ealert%2Dsuccess%20%2Ealert%2Dlink%20%7B%0Acolor%3A%20%232b542c%3B%0A%7D%0A%2Ealert%2Dinfo%20%7B%0Abackground%2Dcolor%3A%20%23d9edf7%3B%0Aborder%2Dcolor%3A%20%23bce8f1%3B%0Acolor%3A%20%2331708f%3B%0A%7D%0A%2Ealert%2Dinfo%20hr%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23a6e1ec%3B%0A%7D%0A%2Ealert%2Dinfo%20%2Ealert%2Dlink%20%7B%0Acolor%3A%20%23245269%3B%0A%7D%0A%2Ealert%2Dwarning%20%7B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0Aborder%2Dcolor%3A%20%23faebcc%3B%0Acolor%3A%20%238a6d3b%3B%0A%7D%0A%2Ealert%2Dwarning%20hr%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23f7e1b5%3B%0A%7D%0A%2Ealert%2Dwarning%20%2Ealert%2Dlink%20%7B%0Acolor%3A%20%2366512c%3B%0A%7D%0A%2Ealert%2Ddanger%20%7B%0Abackground%2Dcolor%3A%20%23f2dede%3B%0Aborder%2Dcolor%3A%20%23ebccd1%3B%0Acolor%3A%20%23a94442%3B%0A%7D%0A%2Ealert%2Ddanger%20hr%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23e4b9c0%3B%0A%7D%0A%2Ealert%2Ddanger%20%2Ealert%2Dlink%20%7B%0Acolor%3A%20%23843534%3B%0A%7D%0A%2Elist%2Dgroup%20%7B%0Amargin%2Dbottom%3A%2020px%3B%0Apadding%2Dleft%3A%200%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%20%7B%0Aposition%3A%20relative%3B%0Adisplay%3A%20block%3B%0Apadding%3A%2010px%2015px%3B%0Amargin%2Dbottom%3A%20%2D1px%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%20%7B%0Aborder%2Dtop%2Dright%2Dradius%3A%200px%3B%0Aborder%2Dtop%2Dleft%2Dradius%3A%200px%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%0Aborder%2Dbottom%2Dright%2Dradius%3A%200px%3B%0Aborder%2Dbottom%2Dleft%2Dradius%3A%200px%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%20%7B%0Acolor%3A%20%23555%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%20%2Elist%2Dgroup%2Ditem%2Dheading%20%7B%0Acolor%3A%20%23333%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%3Afocus%20%7B%0Atext%2Ddecoration%3A%20none%3B%0Acolor%3A%20%23555%3B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Edisabled%2C%0A%2Elist%2Dgroup%2Ditem%2Edisabled%3Ahover%2C%0A%2Elist%2Dgroup%2Ditem%2Edisabled%3Afocus%20%7B%0Abackground%2Dcolor%3A%20%23eeeeee%3B%0Acolor%3A%20%23777777%3B%0Acursor%3A%20not%2Dallowed%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Edisabled%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%0A%2Elist%2Dgroup%2Ditem%2Edisabled%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%0A%2Elist%2Dgroup%2Ditem%2Edisabled%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Edisabled%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%0A%2Elist%2Dgroup%2Ditem%2Edisabled%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%0A%2Elist%2Dgroup%2Ditem%2Edisabled%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dtext%20%7B%0Acolor%3A%20%23777777%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Eactive%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%7B%0Az%2Dindex%3A%202%3B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0Aborder%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dheading%20%3E%20small%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%20%3E%20small%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%20%3E%20small%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dheading%20%3E%20%2Esmall%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%20%3E%20%2Esmall%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%20%3E%20%2Esmall%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%0A%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dtext%20%7B%0Acolor%3A%20%23c7ddef%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Dsuccess%20%7B%0Acolor%3A%20%233c763d%3B%0Abackground%2Dcolor%3A%20%23dff0d8%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dsuccess%20%7B%0Acolor%3A%20%233c763d%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dsuccess%20%2Elist%2Dgroup%2Ditem%2Dheading%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dsuccess%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dsuccess%3Afocus%20%7B%0Acolor%3A%20%233c763d%3B%0Abackground%2Dcolor%3A%20%23d0e9c6%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%233c763d%3B%0Aborder%2Dcolor%3A%20%233c763d%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Dinfo%20%7B%0Acolor%3A%20%2331708f%3B%0Abackground%2Dcolor%3A%20%23d9edf7%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dinfo%20%7B%0Acolor%3A%20%2331708f%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dinfo%20%2Elist%2Dgroup%2Ditem%2Dheading%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dinfo%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dinfo%3Afocus%20%7B%0Acolor%3A%20%2331708f%3B%0Abackground%2Dcolor%3A%20%23c4e3f3%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%2331708f%3B%0Aborder%2Dcolor%3A%20%2331708f%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Dwarning%20%7B%0Acolor%3A%20%238a6d3b%3B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dwarning%20%7B%0Acolor%3A%20%238a6d3b%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dwarning%20%2Elist%2Dgroup%2Ditem%2Dheading%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dwarning%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dwarning%3Afocus%20%7B%0Acolor%3A%20%238a6d3b%3B%0Abackground%2Dcolor%3A%20%23faf2cc%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%238a6d3b%3B%0Aborder%2Dcolor%3A%20%238a6d3b%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Ddanger%20%7B%0Acolor%3A%20%23a94442%3B%0Abackground%2Dcolor%3A%20%23f2dede%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Ddanger%20%7B%0Acolor%3A%20%23a94442%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Ddanger%20%2Elist%2Dgroup%2Ditem%2Dheading%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Ddanger%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Ddanger%3Afocus%20%7B%0Acolor%3A%20%23a94442%3B%0Abackground%2Dcolor%3A%20%23ebcccc%3B%0A%7D%0Aa%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%2C%0Aa%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%3Ahover%2C%0Aa%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%3Afocus%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23a94442%3B%0Aborder%2Dcolor%3A%20%23a94442%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Dheading%20%7B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dbottom%3A%205px%3B%0A%7D%0A%2Elist%2Dgroup%2Ditem%2Dtext%20%7B%0Amargin%2Dbottom%3A%200%3B%0Aline%2Dheight%3A%201%2E3%3B%0A%7D%0A%2Epanel%20%7B%0Amargin%2Dbottom%3A%2035px%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0Aborder%3A%201px%20solid%20transparent%3B%0Aborder%2Dradius%3A%200px%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E05%29%3B%0Abox%2Dshadow%3A%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E05%29%3B%0A%7D%0A%2Epanel%2Dbody%20%7B%0Apadding%3A%2015px%3B%0A%7D%0A%2Epanel%2Dheading%20%7B%0Apadding%3A%2010px%2015px%3B%0Aborder%2Dbottom%3A%201px%20solid%20transparent%3B%0Aborder%2Dtop%2Dright%2Dradius%3A%20%2D1px%3B%0Aborder%2Dtop%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%2Dheading%20%3E%20%2Edropdown%20%2Edropdown%2Dtoggle%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0A%2Epanel%2Dtitle%20%7B%0Amargin%2Dtop%3A%200%3B%0Amargin%2Dbottom%3A%200%3B%0Afont%2Dsize%3A%2023px%3B%0Acolor%3A%20inherit%3B%0A%7D%0A%2Epanel%2Dtitle%20%3E%20a%20%7B%0Acolor%3A%20inherit%3B%0A%7D%0A%2Epanel%2Dfooter%20%7B%0Apadding%3A%2010px%2015px%3B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0Aborder%2Dtop%3A%201px%20solid%20%23ddd%3B%0Aborder%2Dbottom%2Dright%2Dradius%3A%20%2D1px%3B%0Aborder%2Dbottom%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Elist%2Dgroup%2C%0A%2Epanel%20%3E%20%2Epanel%2Dcollapse%20%3E%20%2Elist%2Dgroup%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Elist%2Dgroup%20%2Elist%2Dgroup%2Ditem%2C%0A%2Epanel%20%3E%20%2Epanel%2Dcollapse%20%3E%20%2Elist%2Dgroup%20%2Elist%2Dgroup%2Ditem%20%7B%0Aborder%2Dwidth%3A%201px%200%3B%0Aborder%2Dradius%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Elist%2Dgroup%3Afirst%2Dchild%20%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Epanel%2Dcollapse%20%3E%20%2Elist%2Dgroup%3Afirst%2Dchild%20%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%20%7B%0Aborder%2Dtop%3A%200%3B%0Aborder%2Dtop%2Dright%2Dradius%3A%20%2D1px%3B%0Aborder%2Dtop%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Elist%2Dgroup%3Alast%2Dchild%20%2Elist%2Dgroup%2Ditem%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Epanel%2Dcollapse%20%3E%20%2Elist%2Dgroup%3Alast%2Dchild%20%2Elist%2Dgroup%2Ditem%3Alast%2Dchild%20%7B%0Aborder%2Dbottom%3A%200%3B%0Aborder%2Dbottom%2Dright%2Dradius%3A%20%2D1px%3B%0Aborder%2Dbottom%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%2Dheading%20%2B%20%2Elist%2Dgroup%20%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%20%7B%0Aborder%2Dtop%2Dwidth%3A%200%3B%0A%7D%0A%2Elist%2Dgroup%20%2B%20%2Epanel%2Dfooter%20%7B%0Aborder%2Dtop%2Dwidth%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2C%0A%2Epanel%20%3E%20%2Epanel%2Dcollapse%20%3E%20%2Etable%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%20caption%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%20caption%2C%0A%2Epanel%20%3E%20%2Epanel%2Dcollapse%20%3E%20%2Etable%20caption%20%7B%0Apadding%2Dleft%3A%2015px%3B%0Apadding%2Dright%3A%2015px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%7B%0Aborder%2Dtop%2Dright%2Dradius%3A%20%2D1px%3B%0Aborder%2Dtop%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20%7B%0Aborder%2Dtop%2Dleft%2Dradius%3A%20%2D1px%3B%0Aborder%2Dtop%2Dright%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Afirst%2Dchild%20%7B%0Aborder%2Dtop%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Afirst%2Dchild%20%3E%20%2Etable%3Afirst%2Dchild%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%3Alast%2Dchild%20%7B%0Aborder%2Dtop%2Dright%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%7B%0Aborder%2Dbottom%2Dright%2Dradius%3A%20%2D1px%3B%0Aborder%2Dbottom%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20%7B%0Aborder%2Dbottom%2Dleft%2Dradius%3A%20%2D1px%3B%0Aborder%2Dbottom%2Dright%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Afirst%2Dchild%20%7B%0Aborder%2Dbottom%2Dleft%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tbody%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%3Alast%2Dchild%20%3E%20%2Etable%3Alast%2Dchild%20%3E%20tfoot%3Alast%2Dchild%20%3E%20tr%3Alast%2Dchild%20th%3Alast%2Dchild%20%7B%0Aborder%2Dbottom%2Dright%2Dradius%3A%20%2D1px%3B%0A%7D%0A%2Epanel%20%3E%20%2Epanel%2Dbody%20%2B%20%2Etable%2C%0A%2Epanel%20%3E%20%2Epanel%2Dbody%20%2B%20%2Etable%2Dresponsive%2C%0A%2Epanel%20%3E%20%2Etable%20%2B%20%2Epanel%2Dbody%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%2B%20%2Epanel%2Dbody%20%7B%0Aborder%2Dtop%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20th%2C%0A%2Epanel%20%3E%20%2Etable%20%3E%20tbody%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20td%20%7B%0Aborder%2Dtop%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%2Dbordered%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%7B%0Aborder%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%20%7B%0Aborder%2Dleft%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Alast%2Dchild%20%7B%0Aborder%2Dright%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%20%7B%0Aborder%2Dbottom%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20td%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20th%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20th%2C%0A%2Epanel%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20th%2C%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20th%20%7B%0Aborder%2Dbottom%3A%200%3B%0A%7D%0A%2Epanel%20%3E%20%2Etable%2Dresponsive%20%7B%0Aborder%3A%200%3B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Epanel%2Dgroup%20%7B%0Amargin%2Dbottom%3A%2035px%3B%0A%7D%0A%2Epanel%2Dgroup%20%2Epanel%20%7B%0Amargin%2Dbottom%3A%200%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Epanel%2Dgroup%20%2Epanel%20%2B%20%2Epanel%20%7B%0Amargin%2Dtop%3A%205px%3B%0A%7D%0A%2Epanel%2Dgroup%20%2Epanel%2Dheading%20%7B%0Aborder%2Dbottom%3A%200%3B%0A%7D%0A%2Epanel%2Dgroup%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%2C%0A%2Epanel%2Dgroup%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Elist%2Dgroup%20%7B%0Aborder%2Dtop%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Epanel%2Dgroup%20%2Epanel%2Dfooter%20%7B%0Aborder%2Dtop%3A%200%3B%0A%7D%0A%2Epanel%2Dgroup%20%2Epanel%2Dfooter%20%2B%20%2Epanel%2Dcollapse%20%2Epanel%2Dbody%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23ddd%3B%0A%7D%0A%2Epanel%2Ddefault%20%7B%0Aborder%2Dcolor%3A%20%23ddd%3B%0A%7D%0A%2Epanel%2Ddefault%20%3E%20%2Epanel%2Dheading%20%7B%0Acolor%3A%20%23333333%3B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0Aborder%2Dcolor%3A%20%23ddd%3B%0A%7D%0A%2Epanel%2Ddefault%20%3E%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23ddd%3B%0A%7D%0A%2Epanel%2Ddefault%20%3E%20%2Epanel%2Dheading%20%2Ebadge%20%7B%0Acolor%3A%20%23f5f5f5%3B%0Abackground%2Dcolor%3A%20%23333333%3B%0A%7D%0A%2Epanel%2Ddefault%20%3E%20%2Epanel%2Dfooter%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23ddd%3B%0A%7D%0A%2Epanel%2Dprimary%20%7B%0Aborder%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Epanel%2Dprimary%20%3E%20%2Epanel%2Dheading%20%7B%0Acolor%3A%20%23fff%3B%0Abackground%2Dcolor%3A%20%23337ab7%3B%0Aborder%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Epanel%2Dprimary%20%3E%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Epanel%2Dprimary%20%3E%20%2Epanel%2Dheading%20%2Ebadge%20%7B%0Acolor%3A%20%23337ab7%3B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Epanel%2Dprimary%20%3E%20%2Epanel%2Dfooter%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23337ab7%3B%0A%7D%0A%2Epanel%2Dsuccess%20%7B%0Aborder%2Dcolor%3A%20%23d6e9c6%3B%0A%7D%0A%2Epanel%2Dsuccess%20%3E%20%2Epanel%2Dheading%20%7B%0Acolor%3A%20%233c763d%3B%0Abackground%2Dcolor%3A%20%23dff0d8%3B%0Aborder%2Dcolor%3A%20%23d6e9c6%3B%0A%7D%0A%2Epanel%2Dsuccess%20%3E%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23d6e9c6%3B%0A%7D%0A%2Epanel%2Dsuccess%20%3E%20%2Epanel%2Dheading%20%2Ebadge%20%7B%0Acolor%3A%20%23dff0d8%3B%0Abackground%2Dcolor%3A%20%233c763d%3B%0A%7D%0A%2Epanel%2Dsuccess%20%3E%20%2Epanel%2Dfooter%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23d6e9c6%3B%0A%7D%0A%2Epanel%2Dinfo%20%7B%0Aborder%2Dcolor%3A%20%23bce8f1%3B%0A%7D%0A%2Epanel%2Dinfo%20%3E%20%2Epanel%2Dheading%20%7B%0Acolor%3A%20%2331708f%3B%0Abackground%2Dcolor%3A%20%23d9edf7%3B%0Aborder%2Dcolor%3A%20%23bce8f1%3B%0A%7D%0A%2Epanel%2Dinfo%20%3E%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23bce8f1%3B%0A%7D%0A%2Epanel%2Dinfo%20%3E%20%2Epanel%2Dheading%20%2Ebadge%20%7B%0Acolor%3A%20%23d9edf7%3B%0Abackground%2Dcolor%3A%20%2331708f%3B%0A%7D%0A%2Epanel%2Dinfo%20%3E%20%2Epanel%2Dfooter%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23bce8f1%3B%0A%7D%0A%2Epanel%2Dwarning%20%7B%0Aborder%2Dcolor%3A%20%23faebcc%3B%0A%7D%0A%2Epanel%2Dwarning%20%3E%20%2Epanel%2Dheading%20%7B%0Acolor%3A%20%238a6d3b%3B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0Aborder%2Dcolor%3A%20%23faebcc%3B%0A%7D%0A%2Epanel%2Dwarning%20%3E%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23faebcc%3B%0A%7D%0A%2Epanel%2Dwarning%20%3E%20%2Epanel%2Dheading%20%2Ebadge%20%7B%0Acolor%3A%20%23fcf8e3%3B%0Abackground%2Dcolor%3A%20%238a6d3b%3B%0A%7D%0A%2Epanel%2Dwarning%20%3E%20%2Epanel%2Dfooter%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23faebcc%3B%0A%7D%0A%2Epanel%2Ddanger%20%7B%0Aborder%2Dcolor%3A%20%23ebccd1%3B%0A%7D%0A%2Epanel%2Ddanger%20%3E%20%2Epanel%2Dheading%20%7B%0Acolor%3A%20%23a94442%3B%0Abackground%2Dcolor%3A%20%23f2dede%3B%0Aborder%2Dcolor%3A%20%23ebccd1%3B%0A%7D%0A%2Epanel%2Ddanger%20%3E%20%2Epanel%2Dheading%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dtop%2Dcolor%3A%20%23ebccd1%3B%0A%7D%0A%2Epanel%2Ddanger%20%3E%20%2Epanel%2Dheading%20%2Ebadge%20%7B%0Acolor%3A%20%23f2dede%3B%0Abackground%2Dcolor%3A%20%23a94442%3B%0A%7D%0A%2Epanel%2Ddanger%20%3E%20%2Epanel%2Dfooter%20%2B%20%2Epanel%2Dcollapse%20%3E%20%2Epanel%2Dbody%20%7B%0Aborder%2Dbottom%2Dcolor%3A%20%23ebccd1%3B%0A%7D%0A%2Ewell%20%7B%0Amin%2Dheight%3A%2020px%3B%0Apadding%3A%2019px%3B%0Amargin%2Dbottom%3A%2020px%3B%0Abackground%2Dcolor%3A%20%23f5f5f5%3B%0Aborder%3A%201px%20solid%20%23e3e3e3%3B%0Aborder%2Dradius%3A%200px%3B%0A%2Dwebkit%2Dbox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E05%29%3B%0Abox%2Dshadow%3A%20inset%200%201px%201px%20rgba%280%2C%200%2C%200%2C%200%2E05%29%3B%0A%7D%0A%2Ewell%20blockquote%20%7B%0Aborder%2Dcolor%3A%20%23ddd%3B%0Aborder%2Dcolor%3A%20rgba%280%2C%200%2C%200%2C%200%2E15%29%3B%0A%7D%0A%2Ewell%2Dlg%20%7B%0Apadding%3A%2024px%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Ewell%2Dsm%20%7B%0Apadding%3A%209px%3B%0Aborder%2Dradius%3A%200px%3B%0A%7D%0A%2Eclose%20%7B%0Afloat%3A%20right%3B%0Afont%2Dsize%3A%2030px%3B%0Afont%2Dweight%3A%20bold%3B%0Aline%2Dheight%3A%201%3B%0Acolor%3A%20%23000%3B%0Atext%2Dshadow%3A%200%201px%200%20%23fff%3B%0Aopacity%3A%200%2E2%3B%0Afilter%3A%20alpha%28opacity%3D20%29%3B%0A%7D%0A%2Eclose%3Ahover%2C%0A%2Eclose%3Afocus%20%7B%0Acolor%3A%20%23000%3B%0Atext%2Ddecoration%3A%20none%3B%0Acursor%3A%20pointer%3B%0Aopacity%3A%200%2E5%3B%0Afilter%3A%20alpha%28opacity%3D50%29%3B%0A%7D%0Abutton%2Eclose%20%7B%0Apadding%3A%200%3B%0Acursor%3A%20pointer%3B%0Abackground%3A%20transparent%3B%0Aborder%3A%200%3B%0A%2Dwebkit%2Dappearance%3A%20none%3B%0A%7D%0A%2Eclearfix%3Abefore%2C%0A%2Eclearfix%3Aafter%2C%0A%2Edl%2Dhorizontal%20dd%3Abefore%2C%0A%2Edl%2Dhorizontal%20dd%3Aafter%2C%0A%2Econtainer%3Abefore%2C%0A%2Econtainer%3Aafter%2C%0A%2Econtainer%2Dfluid%3Abefore%2C%0A%2Econtainer%2Dfluid%3Aafter%2C%0A%2Erow%3Abefore%2C%0A%2Erow%3Aafter%2C%0A%2Eform%2Dhorizontal%20%2Eform%2Dgroup%3Abefore%2C%0A%2Eform%2Dhorizontal%20%2Eform%2Dgroup%3Aafter%2C%0A%2Enav%3Abefore%2C%0A%2Enav%3Aafter%2C%0A%2Enavbar%3Abefore%2C%0A%2Enavbar%3Aafter%2C%0A%2Enavbar%2Dheader%3Abefore%2C%0A%2Enavbar%2Dheader%3Aafter%2C%0A%2Enavbar%2Dcollapse%3Abefore%2C%0A%2Enavbar%2Dcollapse%3Aafter%2C%0A%2Epanel%2Dbody%3Abefore%2C%0A%2Epanel%2Dbody%3Aafter%20%7B%0Acontent%3A%20%22%20%22%3B%0Adisplay%3A%20table%3B%0A%7D%0A%2Eclearfix%3Aafter%2C%0A%2Edl%2Dhorizontal%20dd%3Aafter%2C%0A%2Econtainer%3Aafter%2C%0A%2Econtainer%2Dfluid%3Aafter%2C%0A%2Erow%3Aafter%2C%0A%2Eform%2Dhorizontal%20%2Eform%2Dgroup%3Aafter%2C%0A%2Enav%3Aafter%2C%0A%2Enavbar%3Aafter%2C%0A%2Enavbar%2Dheader%3Aafter%2C%0A%2Enavbar%2Dcollapse%3Aafter%2C%0A%2Epanel%2Dbody%3Aafter%20%7B%0Aclear%3A%20both%3B%0A%7D%0A%2Ecenter%2Dblock%20%7B%0Adisplay%3A%20block%3B%0Amargin%2Dleft%3A%20auto%3B%0Amargin%2Dright%3A%20auto%3B%0A%7D%0A%2Epull%2Dright%20%7B%0Afloat%3A%20right%20%21important%3B%0A%7D%0A%2Epull%2Dleft%20%7B%0Afloat%3A%20left%20%21important%3B%0A%7D%0A%2Ehide%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%2Eshow%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0A%2Einvisible%20%7B%0Avisibility%3A%20hidden%3B%0A%7D%0A%2Etext%2Dhide%20%7B%0Afont%3A%200%2F0%20a%3B%0Acolor%3A%20transparent%3B%0Atext%2Dshadow%3A%20none%3B%0Abackground%2Dcolor%3A%20transparent%3B%0Aborder%3A%200%3B%0A%7D%0A%2Ehidden%20%7B%0Adisplay%3A%20none%20%21important%3B%0Avisibility%3A%20hidden%20%21important%3B%0A%7D%0A%2Eaffix%20%7B%0Aposition%3A%20fixed%3B%0A%7D%0A%40%2Dms%2Dviewport%20%7B%0Awidth%3A%20device%2Dwidth%3B%0A%7D%0A%2Evisible%2Dxs%2C%0A%2Evisible%2Dsm%2C%0A%2Evisible%2Dmd%2C%0A%2Evisible%2Dlg%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%2Evisible%2Dxs%2Dblock%2C%0A%2Evisible%2Dxs%2Dinline%2C%0A%2Evisible%2Dxs%2Dinline%2Dblock%2C%0A%2Evisible%2Dsm%2Dblock%2C%0A%2Evisible%2Dsm%2Dinline%2C%0A%2Evisible%2Dsm%2Dinline%2Dblock%2C%0A%2Evisible%2Dmd%2Dblock%2C%0A%2Evisible%2Dmd%2Dinline%2C%0A%2Evisible%2Dmd%2Dinline%2Dblock%2C%0A%2Evisible%2Dlg%2Dblock%2C%0A%2Evisible%2Dlg%2Dinline%2C%0A%2Evisible%2Dlg%2Dinline%2Dblock%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Evisible%2Dxs%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0Atable%2Evisible%2Dxs%20%7B%0Adisplay%3A%20table%3B%0A%7D%0Atr%2Evisible%2Dxs%20%7B%0Adisplay%3A%20table%2Drow%20%21important%3B%0A%7D%0Ath%2Evisible%2Dxs%2C%0Atd%2Evisible%2Dxs%20%7B%0Adisplay%3A%20table%2Dcell%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Evisible%2Dxs%2Dblock%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Evisible%2Dxs%2Dinline%20%7B%0Adisplay%3A%20inline%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Evisible%2Dxs%2Dinline%2Dblock%20%7B%0Adisplay%3A%20inline%2Dblock%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20and%20%28max%2Dwidth%3A%20991px%29%20%7B%0A%2Evisible%2Dsm%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0Atable%2Evisible%2Dsm%20%7B%0Adisplay%3A%20table%3B%0A%7D%0Atr%2Evisible%2Dsm%20%7B%0Adisplay%3A%20table%2Drow%20%21important%3B%0A%7D%0Ath%2Evisible%2Dsm%2C%0Atd%2Evisible%2Dsm%20%7B%0Adisplay%3A%20table%2Dcell%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20and%20%28max%2Dwidth%3A%20991px%29%20%7B%0A%2Evisible%2Dsm%2Dblock%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20and%20%28max%2Dwidth%3A%20991px%29%20%7B%0A%2Evisible%2Dsm%2Dinline%20%7B%0Adisplay%3A%20inline%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20and%20%28max%2Dwidth%3A%20991px%29%20%7B%0A%2Evisible%2Dsm%2Dinline%2Dblock%20%7B%0Adisplay%3A%20inline%2Dblock%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20992px%29%20and%20%28max%2Dwidth%3A%201199px%29%20%7B%0A%2Evisible%2Dmd%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0Atable%2Evisible%2Dmd%20%7B%0Adisplay%3A%20table%3B%0A%7D%0Atr%2Evisible%2Dmd%20%7B%0Adisplay%3A%20table%2Drow%20%21important%3B%0A%7D%0Ath%2Evisible%2Dmd%2C%0Atd%2Evisible%2Dmd%20%7B%0Adisplay%3A%20table%2Dcell%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20992px%29%20and%20%28max%2Dwidth%3A%201199px%29%20%7B%0A%2Evisible%2Dmd%2Dblock%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20992px%29%20and%20%28max%2Dwidth%3A%201199px%29%20%7B%0A%2Evisible%2Dmd%2Dinline%20%7B%0Adisplay%3A%20inline%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20992px%29%20and%20%28max%2Dwidth%3A%201199px%29%20%7B%0A%2Evisible%2Dmd%2Dinline%2Dblock%20%7B%0Adisplay%3A%20inline%2Dblock%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%201200px%29%20%7B%0A%2Evisible%2Dlg%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0Atable%2Evisible%2Dlg%20%7B%0Adisplay%3A%20table%3B%0A%7D%0Atr%2Evisible%2Dlg%20%7B%0Adisplay%3A%20table%2Drow%20%21important%3B%0A%7D%0Ath%2Evisible%2Dlg%2C%0Atd%2Evisible%2Dlg%20%7B%0Adisplay%3A%20table%2Dcell%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%201200px%29%20%7B%0A%2Evisible%2Dlg%2Dblock%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%201200px%29%20%7B%0A%2Evisible%2Dlg%2Dinline%20%7B%0Adisplay%3A%20inline%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%201200px%29%20%7B%0A%2Evisible%2Dlg%2Dinline%2Dblock%20%7B%0Adisplay%3A%20inline%2Dblock%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28max%2Dwidth%3A%20767px%29%20%7B%0A%2Ehidden%2Dxs%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20768px%29%20and%20%28max%2Dwidth%3A%20991px%29%20%7B%0A%2Ehidden%2Dsm%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%20992px%29%20and%20%28max%2Dwidth%3A%201199px%29%20%7B%0A%2Ehidden%2Dmd%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%7D%0A%40media%20%28min%2Dwidth%3A%201200px%29%20%7B%0A%2Ehidden%2Dlg%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%7D%0A%2Evisible%2Dprint%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%40media%20print%20%7B%0A%2Evisible%2Dprint%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0Atable%2Evisible%2Dprint%20%7B%0Adisplay%3A%20table%3B%0A%7D%0Atr%2Evisible%2Dprint%20%7B%0Adisplay%3A%20table%2Drow%20%21important%3B%0A%7D%0Ath%2Evisible%2Dprint%2C%0Atd%2Evisible%2Dprint%20%7B%0Adisplay%3A%20table%2Dcell%20%21important%3B%0A%7D%0A%7D%0A%2Evisible%2Dprint%2Dblock%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%40media%20print%20%7B%0A%2Evisible%2Dprint%2Dblock%20%7B%0Adisplay%3A%20block%20%21important%3B%0A%7D%0A%7D%0A%2Evisible%2Dprint%2Dinline%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%40media%20print%20%7B%0A%2Evisible%2Dprint%2Dinline%20%7B%0Adisplay%3A%20inline%20%21important%3B%0A%7D%0A%7D%0A%2Evisible%2Dprint%2Dinline%2Dblock%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%40media%20print%20%7B%0A%2Evisible%2Dprint%2Dinline%2Dblock%20%7B%0Adisplay%3A%20inline%2Dblock%20%21important%3B%0A%7D%0A%7D%0A%40media%20print%20%7B%0A%2Ehidden%2Dprint%20%7B%0Adisplay%3A%20none%20%21important%3B%0A%7D%0A%7D%0A%2Ehero%20%7B%0Aposition%3A%20relative%3B%0Acolor%3A%20white%3B%0Abackground%3A%20%23042742%3B%0A%7D%0A%2Ehero%20%2Econtainer%20%7B%0Aposition%3A%20relative%3B%0Aheight%3A%2050vh%3B%0Amin%2Dheight%3A%20637%2E5px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%7B%0Aposition%3A%20absolute%3B%0Atop%3A%200%3B%0Aleft%3A%200%3B%0Aright%3A%200%3B%0Abottom%3A%2030px%3B%0Amargin%3A%20auto%3B%0Aheight%3A%20397%2E5px%3B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%2Etitle%20%7B%0Amargin%3A%200%200%2035px%3B%0Aline%2Dheight%3A%2070px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%2Etitle%2Ewith%2Dsubtitle%20%7B%0Amargin%2Dtop%3A%20%2D35px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%2Esubtitle%20%7B%0Adisplay%3A%20block%3B%0Afont%2Dsize%3A%2066%25%3B%0Aline%2Dheight%3A%2042px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%2Eauthor%20%7B%0Amargin%3A%200%200%2035px%3B%0Aline%2Dheight%3A%2052%2E5px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%2Edate%20%7B%0Amargin%3A%200%200%2070px%3B%0Aline%2Dheight%3A%2035px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%2Ebrand%2Dlogo%20%7B%0Adisplay%3A%20block%3B%0Aheight%3A%20100px%3B%0Amargin%3A%200%20auto%3B%0A%7D%0A%2Ehero%2Dleft%2Doverlay%2Dwhite%2C%0A%2Ehero%2Dleft%2Doverlay%2Dblack%2C%0A%2Ehero%2Dright%2Doverlay%2Dwhite%2C%0A%2Ehero%2Dright%2Doverlay%2Dblack%2C%0A%2Ehero%2Darrow%2Doverlay%2Dwhite%20%7B%0Aposition%3A%20absolute%3B%0Atop%3A%200%3B%0Aleft%3A%200%3B%0Aright%3A%200%3B%0Abottom%3A%200%3B%0Az%2Dindex%3A%201%3B%0Abackground%2Dsize%3A%20cover%3B%0Apointer%2Devents%3A%20none%3B%0A%7D%0A%2Ehero%2Dleft%2Doverlay%2Dwhite%20%7B%0Abackground%2Dimage%3A%20url%28%22data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJ5ZXMiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgNjAiPgogIDxwb2x5Z29uIGZpbGw9InJnYmEoMjU1LCAyNTUsIDI1NSwgMC4xKSIgcG9pbnRzPSIwLDAgMzAsMCAwLDE1IiAvPgogIDxwb2x5Z29uIGZpbGw9InJnYmEoMjU1LCAyNTUsIDI1NSwgMC4xKSIgcG9pbnRzPSIwLDAgMTUsMCAwLDEwMCIgLz4KPC9zdmc%2BCg%3D%3D%22%29%3B%0Abackground%2Dposition%3A%20left%20top%3B%0A%7D%0A%2Ehero%2Dright%2Doverlay%2Dwhite%20%7B%0Abackground%2Dimage%3A%20url%28%22data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJ5ZXMiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgNjAiPgogIDxwb2x5Z29uIGZpbGw9InJnYmEoMjU1LCAyNTUsIDI1NSwgMC4xKSIgcG9pbnRzPSI4MCwwIDEwMCwwIDEwMCw2MCIgLz4KICA8cG9seWdvbiBmaWxsPSJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuMSkiIHBvaW50cz0iMTAwLDQwIDEwMCw2MCA4MCw2MCIgLz4KPC9zdmc%2BCg%3D%3D%22%29%3B%0Abackground%2Dposition%3A%20right%20bottom%3B%0A%7D%0A%2Ehero%2Darrow%2Doverlay%2Dwhite%20%7B%0Atop%3A%20auto%3B%0Aheight%3A%2030px%3B%0Az%2Dindex%3A%202%3B%0Abackground%2Dimage%3A%20url%28%22data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJ5ZXMiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAwMCA0MCI%2BCiAgPHBvbHlnb24gZmlsbD0icmdiKDI1NSwgMjU1LCAyNTUpIiBwb2ludHM9IjAsMCA0OTcwLDAgNTAwMCwzMCA1MDMwLDAgMTAwMDAsMCAxMDAwMCw1MCAwLDUwIiAvPgo8L3N2Zz4K%22%29%3B%0Abackground%2Dposition%3A%20center%20bottom%3B%0A%7D%0A%2Ehero%2Doverlay%2Dsoft%20%7B%0Aopacity%3A%20%2E4%3B%0A%7D%0Anav%2Etoc%20%2Econtainer%20%7B%0Awidth%3A%20100%25%3B%0A%7D%0Anav%2Etoc%20h1%20%7B%0Amargin%2Dtop%3A%2035px%3B%0A%7D%0Anav%2Etoc%20%2Etoc%2Dcontents%20%7B%0Adisplay%3A%20none%3B%0Amargin%2Dtop%3A%201em%3B%0A%7D%0Anav%2Etoc%20%2Etoc%2Dcontents%20ul%20%7B%0Apadding%2Dleft%3A%200%3B%0Alist%2Dstyle%3A%20none%3B%0A%7D%0Anav%2Etoc%20%2Etoc%2Dcontents%20ul%20a%20%7B%0Adisplay%3A%20block%3B%0A%7D%0Anav%2Etoc%20%2Etoc%2Dcontents%20ul%20%3E%20li%20%3E%20a%20%7B%0Apadding%2Dtop%3A%2035px%3B%0Afont%2Dsize%3A%2024px%3B%0A%7D%0Anav%2Etoc%20%2Etoc%2Dcontents%20ul%20%3E%20li%20%3E%20ul%20%3E%20li%20%3E%20a%20%7B%0Apadding%2Dtop%3A%208%2E75px%3B%0Apadding%2Dbottom%3A%200px%3B%0Afont%2Dsize%3A%2020px%3B%0A%7D%0Anav%2Etoc%20%2Etoc%2Dtoggle%20%7B%0Amargin%2Dtop%3A%2017%2E5px%3B%0A%7D%0Aol%2Etoc%20%7B%0Apadding%2Dleft%3A%200%3B%0Alist%2Dstyle%3A%20none%3B%0A%7D%0Aol%2Etoc%20a%20%7B%0Adisplay%3A%20block%3B%0A%7D%0Aol%2Etoc%20%3E%20li%20%3E%20a%20%7B%0Apadding%2Dtop%3A%2035px%3B%0Afont%2Dsize%3A%2030px%3B%0A%7D%0Aol%2Etoc%20%3E%20li%20%3E%20ol%20%3E%20li%20%3E%20a%20%7B%0Apadding%2Dtop%3A%2035px%3B%0Apadding%2Dbottom%3A%2017%2E5px%3B%0Afont%2Dsize%3A%2024px%3B%0A%7D%0Aol%2Etoc%20%3E%20li%20%3E%20ol%20%3E%20li%20%3E%20ol%20%3E%20li%20%3E%20a%20%7B%0Apadding%2Dtop%3A%208%2E75px%3B%0Apadding%2Dbottom%3A%200%3B%0Afont%2Dsize%3A%2020px%3B%0A%7D%0A%40media%20screen%20%7B%0A%2Ehighlight%20%7B%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%7D%0A%2Ehighlight%20pre%20%7B%0Abackground%3A%20%23181818%3B%0Acolor%3A%20%23F8F8F8%3B%0Aborder%3A%20none%3B%0A%7D%0A%2Ehighlight%20code%20%2A%20%7B%0Afont%2Dfamily%3A%20Menlo%2C%20Monaco%2C%20Consolas%2C%20%22Lucida%20Console%22%2C%20%22Courier%20New%22%2C%20monospace%3B%0A%7D%0A%2Ehighlight%20code%20%2Ehll%20%7B%0Abackground%3A%20%23ffffcc%3B%0A%7D%0A%2Ehighlight%20code%20%2Ec%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Eerr%20%7B%0Aborder%3A%20%23B22518%3B%0A%7D%0A%2Ehighlight%20code%20%2Ek%20%7B%0Acolor%3A%20%23CDA869%3B%0A%7D%0A%2Ehighlight%20code%20%2Ecm%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Ecp%20%7B%0Acolor%3A%20%235F5A60%3B%0A%7D%0A%2Ehighlight%20code%20%2Ec1%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Ecs%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Egd%20%7B%0Abackground%3A%20%23420E09%3B%0A%7D%0A%2Ehighlight%20code%20%2Ege%20%7B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Egr%20%7B%0Abackground%3A%20%23B22518%3B%0A%7D%0A%2Ehighlight%20code%20%2Egh%20%7B%0Acolor%3A%20%23000080%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Egi%20%7B%0Abackground%3A%20%23253B22%3B%0A%7D%0A%2Ehighlight%20code%20%2Egp%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Egs%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Egu%20%7B%0Acolor%3A%20%23800080%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Ekd%20%7B%0Acolor%3A%20%23e9df8f%3B%0A%7D%0A%2Ehighlight%20code%20%2Ekp%20%7B%0Acolor%3A%20%239B703F%3B%0A%7D%0A%2Ehighlight%20code%20%2Es%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Ena%20%7B%0Acolor%3A%20%23F9EE98%3B%0A%7D%0A%2Ehighlight%20code%20%2Enb%20%7B%0Acolor%3A%20%23CDA869%3B%0A%7D%0A%2Ehighlight%20code%20%2Enc%20%7B%0Acolor%3A%20%239B859D%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Eno%20%7B%0Acolor%3A%20%239B859D%3B%0A%7D%0A%2Ehighlight%20code%20%2End%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Eni%20%7B%0Acolor%3A%20%23CF6A4C%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Enf%20%7B%0Acolor%3A%20%239B703F%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Enn%20%7B%0Acolor%3A%20%239B859D%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Ent%20%7B%0Acolor%3A%20%23CDA869%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Env%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Eow%20%7B%0Acolor%3A%20%23AA22FF%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Ew%20%7B%0Acolor%3A%20%23141414%3B%0A%7D%0A%2Ehighlight%20code%20%2Emf%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Emh%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Emi%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Emo%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Esb%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esc%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esd%20%7B%0Acolor%3A%20%238F9D6A%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Es2%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Ese%20%7B%0Acolor%3A%20%23F9EE98%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Esh%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esi%20%7B%0Acolor%3A%20%23DAEFA3%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Esx%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esr%20%7B%0Acolor%3A%20%23E9C062%3B%0A%7D%0A%2Ehighlight%20code%20%2Es1%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Ess%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Ebp%20%7B%0Acolor%3A%20%2300aaaa%3B%0A%7D%0A%2Ehighlight%20code%20%2Evc%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Evg%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Evi%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Eil%20%7B%0Acolor%3A%20%23009999%3B%0A%7D%0A%7D%0A%40media%20print%20%7B%0A%2Ehighlight%20%7B%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%7D%0A%2Ehighlight%20pre%20%7B%0Abackground%3A%20%23181818%3B%0Acolor%3A%20%23F8F8F8%3B%0Aborder%3A%20none%3B%0A%7D%0A%2Ehighlight%20code%20%2A%20%7B%0Afont%2Dfamily%3A%20Menlo%2C%20Monaco%2C%20Consolas%2C%20%22Lucida%20Console%22%2C%20%22Courier%20New%22%2C%20monospace%3B%0A%7D%0A%2Ehighlight%20code%20%2Ehll%20%7B%0Abackground%3A%20%23ffffcc%3B%0A%7D%0A%2Ehighlight%20code%20%2Ec%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Eerr%20%7B%0Aborder%3A%20%23B22518%3B%0A%7D%0A%2Ehighlight%20code%20%2Ek%20%7B%0Acolor%3A%20%23CDA869%3B%0A%7D%0A%2Ehighlight%20code%20%2Ecm%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Ecp%20%7B%0Acolor%3A%20%235F5A60%3B%0A%7D%0A%2Ehighlight%20code%20%2Ec1%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Ecs%20%7B%0Acolor%3A%20%235F5A60%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Egd%20%7B%0Abackground%3A%20%23420E09%3B%0A%7D%0A%2Ehighlight%20code%20%2Ege%20%7B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Egr%20%7B%0Abackground%3A%20%23B22518%3B%0A%7D%0A%2Ehighlight%20code%20%2Egh%20%7B%0Acolor%3A%20%23000080%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Egi%20%7B%0Abackground%3A%20%23253B22%3B%0A%7D%0A%2Ehighlight%20code%20%2Egp%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Egs%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Egu%20%7B%0Acolor%3A%20%23800080%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Ekd%20%7B%0Acolor%3A%20%23e9df8f%3B%0A%7D%0A%2Ehighlight%20code%20%2Ekp%20%7B%0Acolor%3A%20%239B703F%3B%0A%7D%0A%2Ehighlight%20code%20%2Es%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Ena%20%7B%0Acolor%3A%20%23F9EE98%3B%0A%7D%0A%2Ehighlight%20code%20%2Enb%20%7B%0Acolor%3A%20%23CDA869%3B%0A%7D%0A%2Ehighlight%20code%20%2Enc%20%7B%0Acolor%3A%20%239B859D%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Eno%20%7B%0Acolor%3A%20%239B859D%3B%0A%7D%0A%2Ehighlight%20code%20%2End%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Eni%20%7B%0Acolor%3A%20%23CF6A4C%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Enf%20%7B%0Acolor%3A%20%239B703F%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Enn%20%7B%0Acolor%3A%20%239B859D%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Ent%20%7B%0Acolor%3A%20%23CDA869%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Env%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Eow%20%7B%0Acolor%3A%20%23AA22FF%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Ew%20%7B%0Acolor%3A%20%23141414%3B%0A%7D%0A%2Ehighlight%20code%20%2Emf%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Emh%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Emi%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Emo%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Esb%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esc%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esd%20%7B%0Acolor%3A%20%238F9D6A%3B%0Afont%2Dstyle%3A%20italic%3B%0A%7D%0A%2Ehighlight%20code%20%2Es2%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Ese%20%7B%0Acolor%3A%20%23F9EE98%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Esh%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esi%20%7B%0Acolor%3A%20%23DAEFA3%3B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0A%2Ehighlight%20code%20%2Esx%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Esr%20%7B%0Acolor%3A%20%23E9C062%3B%0A%7D%0A%2Ehighlight%20code%20%2Es1%20%7B%0Acolor%3A%20%238F9D6A%3B%0A%7D%0A%2Ehighlight%20code%20%2Ess%20%7B%0Acolor%3A%20%23CF6A4C%3B%0A%7D%0A%2Ehighlight%20code%20%2Ebp%20%7B%0Acolor%3A%20%2300aaaa%3B%0A%7D%0A%2Ehighlight%20code%20%2Evc%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Evg%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Evi%20%7B%0Acolor%3A%20%237587A6%3B%0A%7D%0A%2Ehighlight%20code%20%2Eil%20%7B%0Acolor%3A%20%23009999%3B%0A%7D%0A%7D%0A%2Ecallout%20%7B%0Amargin%3A%2020px%200%3B%0Apadding%3A%2015px%2030px%2015px%2015px%3B%0Aborder%2Dleft%3A%205px%20solid%20%23eee%3B%0A%7D%0A%2Ecallout%20p%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0A%2Ecallout%20%2Ehighlight%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0A%2Ecallout%2Ecallout%2Dinfo%20%7B%0Abackground%2Dcolor%3A%20%23d9edf7%3B%0Aborder%2Dcolor%3A%20%23bce8f1%3B%0A%7D%0A%2Ecallout%2Ecallout%2Dwarning%20%7B%0Abackground%2Dcolor%3A%20%23fcf8e3%3B%0Aborder%2Dcolor%3A%20%23faebcc%3B%0A%7D%0A%2Ecallout%2Ecallout%2Ddanger%20%7B%0Abackground%2Dcolor%3A%20%23f2dede%3B%0Aborder%2Dcolor%3A%20%23ebccd1%3B%0A%7D%0Aol%20%7B%0Alist%2Dstyle%2Dtype%3A%20decimal%3B%0A%7D%0Aol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Dalpha%3B%0A%7D%0Aol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Droman%3B%0A%7D%0Aol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20decimal%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Dalpha%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Droman%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20decimal%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Dalpha%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Droman%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20decimal%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Dalpha%3B%0A%7D%0Aol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20ol%20%7B%0Alist%2Dstyle%2Dtype%3A%20lower%2Droman%3B%0A%7D%0A%2Ebtn%20%7B%0Aborder%3A%20none%20%21important%3B%0A%7D%0A%2Ebtn%2Ebtn%2Ddefault%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23eaeaea%3B%0A%7D%0A%2Ebtn%2Ebtn%2Ddefault%3Ahover%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23dddddd%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dprimary%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%232e6da4%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dprimary%3Ahover%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23286090%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dsuccess%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%234cae4c%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dsuccess%3Ahover%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23449d44%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dinfo%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%2346b8da%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dinfo%3Ahover%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%2331b0d5%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dwarning%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23eea236%3B%0A%7D%0A%2Ebtn%2Ebtn%2Dwarning%3Ahover%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23ec971f%3B%0A%7D%0A%2Ebtn%2Ebtn%2Ddanger%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23d43f3a%3B%0A%7D%0A%2Ebtn%2Ebtn%2Ddanger%3Ahover%20%7B%0Abox%2Dshadow%3A%200%204px%200%20%23c9302c%3B%0A%7D%0Aarticle%20img%20%7B%0Adisplay%3A%20block%3B%0Amargin%2Dleft%3A%20auto%3B%0Amargin%2Dright%3A%20auto%3B%0Amax%2Dwidth%3A%20100%25%3B%0A%7D%0Aarticle%20%2Efigure%20%2Ecaption%2C%0Aarticle%20%2Esolution%20%2Ecaption%20%7B%0Atext%2Dalign%3A%20center%3B%0Acolor%3A%20%23777777%3B%0A%7D%0Atable%20%7B%0Awidth%3A%20100%25%3B%0Amax%2Dwidth%3A%20100%25%3B%0Amargin%2Dbottom%3A%2035px%3B%0Aborder%3A%201px%20solid%20%23ddd%3B%0Aoverflow%2Dx%3A%20auto%3B%0Amin%2Dheight%3A%200%2E01%25%3B%0A%7D%0Atable%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20thead%20%3E%20tr%20%3E%20td%2C%0Atable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2C%0Atable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%20%7B%0Apadding%3A%208px%3B%0Aline%2Dheight%3A%201%2E75%3B%0Avertical%2Dalign%3A%20top%3B%0Aborder%2Dtop%3A%201px%20solid%20%23ddd%3B%0A%7D%0Atable%20%3E%20thead%20%3E%20tr%20%3E%20th%20%7B%0Avertical%2Dalign%3A%20bottom%3B%0Aborder%2Dbottom%3A%202px%20solid%20%23ddd%3B%0A%7D%0Atable%20%3E%20caption%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0Atable%20%3E%20colgroup%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0Atable%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20%3E%20th%2C%0Atable%20%3E%20caption%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0Atable%20%3E%20colgroup%20%2B%20thead%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%2C%0Atable%20%3E%20thead%3Afirst%2Dchild%20%3E%20tr%3Afirst%2Dchild%20%3E%20td%20%7B%0Aborder%2Dtop%3A%200%3B%0A%7D%0Atable%20%3E%20tbody%20%2B%20tbody%20%7B%0Aborder%2Dtop%3A%202px%20solid%20%23ddd%3B%0A%7D%0Atable%20%2Etable%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0A%7D%0Atable%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20thead%20%3E%20tr%20%3E%20td%2C%0Atable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2C%0Atable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%20%7B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0Atable%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20thead%20%3E%20tr%20%3E%20td%20%7B%0Aborder%2Dbottom%2Dwidth%3A%202px%3B%0A%7D%0Atable%20%3E%20tbody%20%3E%20tr%3Anth%2Dchild%28odd%29%20%7B%0Abackground%2Dcolor%3A%20%23f9f9f9%3B%0A%7D%0A%40media%20screen%20and%20%28max%2Dwidth%3A%20767px%29%20%7B%0Atable%20%7B%0Awidth%3A%20100%25%3B%0Amargin%2Dbottom%3A%2026%2E25px%3B%0Aoverflow%2Dy%3A%20hidden%3B%0A%2Dms%2Doverflow%2Dstyle%3A%20%2Dms%2Dautohiding%2Dscrollbar%3B%0Aborder%3A%201px%20solid%20%23ddd%3B%0A%7D%0Atable%20%3E%20%2Etable%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0Atable%20%3E%20%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20th%2C%0Atable%20%3E%20%2Etable%20%3E%20thead%20%3E%20tr%20%3E%20td%2C%0Atable%20%3E%20%2Etable%20%3E%20tbody%20%3E%20tr%20%3E%20td%2C%0Atable%20%3E%20%2Etable%20%3E%20tfoot%20%3E%20tr%20%3E%20td%20%7B%0Awhite%2Dspace%3A%20nowrap%3B%0A%7D%0Atable%20%3E%20%2Etable%2Dbordered%20%7B%0Aborder%3A%200%3B%0A%7D%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Afirst%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Afirst%2Dchild%20%7B%0Aborder%2Dleft%3A%200%3B%0A%7D%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20th%3Alast%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20thead%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%20%3E%20td%3Alast%2Dchild%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%20%3E%20td%3Alast%2Dchild%20%7B%0Aborder%2Dright%3A%200%3B%0A%7D%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20th%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20th%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tbody%20%3E%20tr%3Alast%2Dchild%20%3E%20td%2C%0Atable%20%3E%20%2Etable%2Dbordered%20%3E%20tfoot%20%3E%20tr%3Alast%2Dchild%20%3E%20td%20%7B%0Aborder%2Dbottom%3A%200%3B%0A%7D%0A%7D%0Aa%20code%20%7B%0Acolor%3A%20%23337ab7%3B%0A%7D%0Afooter%20%7B%0Amargin%2Dtop%3A%2035px%3B%0Apadding%3A%2035px%200%3B%0Abackground%3A%20%235bc0de%3B%0Acolor%3A%20%23fff%3B%0A%7D%0Afooter%20a%20%7B%0Acolor%3A%20%23fff%3B%0A%7D%0Afooter%20h1%2C%0Afooter%20h2%2C%0Afooter%20h3%2C%0Afooter%20h4%2C%0Afooter%20h5%2C%0Afooter%20h6%20%7B%0Acolor%3A%20%23fff%3B%0A%7D%0Afooter%20%2Efooter%2Dbrand%20%7B%0Amargin%3A%200%3B%0A%7D%0Afooter%20%2Esitemap%20%7B%0Amargin%3A%200%200%2035px%3B%0Afont%2Dsize%3A%20%2E9em%3B%0A%7D%0Afooter%20%2Esitemap%20ul%20%7B%0Amargin%3A%200%3B%0A%7D%0Afooter%20%2Esitemap%20li%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0Afooter%20%2Esitemap%20h5%20%7B%0Amargin%2Dtop%3A%2035px%3B%0Atext%2Dalign%3A%20center%3B%0A%7D%0Afooter%20%2Esitemap%20h5%20a%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Afooter%20%2Esitemap%20a%20%7B%0Adisplay%3A%20block%3B%0Aoverflow%3A%20hidden%3B%0Atext%2Doverflow%3A%20ellipsis%3B%0Awhite%2Dspace%3A%20nowrap%3B%0Acolor%3A%20%23fff%3B%0Afont%2Dweight%3A%20200%3B%0A%7D%0Afooter%20%2Ecopyright%20%7B%0Amargin%3A%200%200%2035px%3B%0Afont%2Dsize%3A%20%2E8em%3B%0Afont%2Dweight%3A%20200%3B%0A%7D%0A%2Ehero%20%7B%0Abackground%3A%20%23042742%20url%28%22data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAogAAAFBCAYAAAD0Rl5bAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAQmlJREFUeNrsvWmQJOd53%2FnUfXTPTM9JDEAMcZEiKVEkBVoraSmJpCnTB21RK621sdoNH1I4rI3Y8If9sGF%2Fkr%2FZsWFH7Easw2HZClGyFQrqsGVKJEyCJmgCIAjiBjGY%2B8DcM3133XmU88mqmumjquvKrMrM9%2FcbFufoRnfXm%2B%2Fxf58zlf%2FQ556TGZFKpeTAgXJODCPtve%2BlAwv5pL%2FPRx45UU76e%2Fzs%2F%2FTzjx959HhpFt%2BrXMjLQrEoAEmkZbvyxtW70m63Z%2FY9S%2Fm8FHIF%2BfZvf%2BV0ksf2xo27taTPn9XNSsvEdbO1VbNmtWay3uvnZ%2FnmHNsx7oG66ZQ0W1bi32etVk%2F%2BodaYzZ7kTRlZKBRQEZBYNuu2FHM5qbdmf857e9VHkzy2Jpw3JmqJWZNmCACiRzGfV5M7AwGJFohqzUunZnsM2ZUagw%2BAQIwIM3ShQLhsrW2F%2Fj0y6RSuZUg0lYYtluP6fy7lZ2spbzWaPACAqAnEtqFCCX2YHKqb1dC%2FB%2BIQkk695d7%2Fcy6bnakVEddk%2FHEcl0FImkAEgP1R62Ehl2MgINFsNewdf5%2BlFdFpJTu3AQEMCESIHC0DAqMrG%2BFaEBGHkHTcttx3L%2FdQK2JqRjG3q7eWky0QXaxrSWaWnlgEIsAY1LbCE4hkLoMJNFr9LVzFGV2OWs0WDwEAgQgQH8hcBhNo2v0tXPlsfiZWxK17qzwEAARidHANMPubEDh8J0T3VDGP9RCSj%2BP2d5GpOMxns%2BEeeKmMWAkPhbENiEF027jREykQTY2PMCGTmdiXKcRhLucnqACYfJEs5MJvONVIeB1E14DDxqU0SDIFIkDcuX3%2BRuBfs1TIM7BgBJYz%2BHDXcje5TCa8A8%2B7hNVrFMoGQCDCbC0DthkWxGY92EK7ajnMhngoAsQJjUUMi9YM6pjOG9uizE1iz9gZe%2BkQiLNatK5jwOQ1Y2Nau7sW6NcrEXsIcJ8wS95Y9Ubix8%2BE%2BDwKZSdUILousQOAQNwpEKl9COZQyA23loeVrHLvvVuJH9%2B2AWcsIYgJFYg82eTSatlGvM%2FqVnAxTIVcltI2YBSjTPdCNpxL08a9tcSPr0UnlQQr46QLREOxbUziSWFtdSNAgYj1EMxilGz9dDoTeH9mTX6prK7zABKAqWVu3KTHIGI%2FTDYmtNtTVq7fC0Yghlz3DSBqFLKjHTv5bLCJW5l0WrbWNhI9tqbsv21C1ZIpEF1T6yAijRPF6s2V6Q9K3MtgIOXCaMIvH7Cb2d6ivA1ApAWiqbiGZF21LDPiENcCiGXCvQymUsgNP3qCdjOv3rjL%2FpsATM5gTn6ZGwxpkADW700fy4R7GUxlIT%2Fa3A%2FSzbz83u3Ej6tLNyuIs0A0uR2bCYvXlBiYaXsy%2Bwcf7mUwlIOl0QRiLiA3sykJKvRhhlgLRJMxoh%2BzQdna07Tcy2dxL4O5qIs5lxl%2B%2FGTSmUCKZme8vTfpCSqm7L8m92GetXt9LgLR1IQNE6ynJlmIV25PnqgSdIYmQNw4vDDaJSmI3sw1A%2BofmrL%2FksGccIFoajcVU4SxY0ih1rvXJgt61zpwGXovg%2BEcKuckPUJNxGx6%2BrVy%2B%2BL1xI%2BnKeE9DgIx2QLRVEzJvjKlkv%2Fdm5PFIeYyJKcAqDY8XB5uRcxOeZnS%2BofL15LfYs%2BU8wUPZMIFomtomropoRO2Y4ZAbFnWRHGI%2BRwCEUA5spgfakVMTxmHqKvNiPhDQ8J7XIcklUQLRFMxJfvKFFeHcvvq%2BKUzsmmW3ezXnkit6dx%2FWQ5uqkgcQJ7uO3moMPTzpolD3Ayo6xH7bhTWsbnrdh7CeC6mDGNjEF1TYhDNueFdv3hDPvH5p8c6EIk%2FnA1Ny5X1akuqLdcThHvnpFquDhYycqCUG7m7BwTPYjErB7zXVsPe51KVkZaMXwRaLY83zl5h3%2BUMhbgIRJPbzmmcSCaTbAuSujr0omdCmb%2B11Q1p1ZuSLxVGW3CIw9BR6%2BC9zea%2BgqN3UV2v2%2F5rIZ%2BR4wcLI3X4gOB5aKko1bvVgcaDSS9Vanlcfu9m8oVTmyoZSWcehrX5lLkx%2BBZgiji2LHPczFffvjz6jQyBGCrqPr6yXBsqDndTbXX%2Bu426zSDOAbWsnzpSGhiPmJkwk9larxixF5my35psXJrHe59PkorJhS5dejInjesXRi%2BhkUMghkbFE4XXVutT3bRvrzcQiXNCrbcnDg62xGcmiN29cfoS%2B22CsG1zLYhtUyyIJt8ETClFYFuOMc%2F0%2BtVbvpt5FDKUuAkFjTe8tdEM5GupSFRLJMyeQ6Ws727ux7jW93w2K7cvvMd%2BmySRZLAFcR6GtbkJRGMTVQx525ZllhXm9oXR4pwyafovh4HGHAa5p9zwRCLx8PMVibvdzekxg5rbtabUazUjxsyUyhHGlsibkzBGIM4Yx5AagepKN2kxX3z74tDPob1eOKhLWGMIg96fVistBneOIlFjErf3a86OaX2%2F8tq7xogmE8K2XBJUzBGI0sZUnPhbrUlxiCO4mdMpMmTDYKsWjvVkrWYxuHNEYxIfO172S%2BAo4xTLVvfyjbOXjRinpinWQ5M1g4sF0aCHbUqiilkH7LBs5jTu5cDRkjZBWw%2B371HEIs4XXTIPHy7KI96rkB3dgthcXjcms9eyzbiIm1ziZl4GNZJUmOjhbVwts%2BIQL5%2FeXyCSwRw8zZCD82stBGIU0GLaT5woy7HFggy7Z6ml8dKr7xozNqbssyZnMM9LM8xNIDoG91M05b1btmNUJMGdW8tSXdkcvNhosRc4DSvctdSy6fsaJY4dKMhjxxbkuPd7Ptt%2FPeU9gXj78jUjxkP3V91nzXivJlsQ5%2FNt0%2FN9z2ZaEU0Ktm02zQr0P%2F%2F6%2BYEfowdzHNcqqcxRolcwW%2BMS33%2B4JKeOluTYYt7vhNOzLN47e5X9NXHisG30WjTOgmjy5qvvu21MoopZcYiXT18Z%2FMEUMYgA07B7Ceml62ApJ%2B87VOxYFjOunHnxDWPGw5T91aX7GgLRNJFoAqbFIVaqNXmvT7IK%2BSnxJJfhwUWJYZUA3vz260a1%2BTQm%2FtA1NxZ4nlphvi5mg9PWTZnwGh9jWnHTM6%2Be2fNv9GAOh3I%2B3HHN53hukRLs%2B9QS1TJTNy7fNGYsdF81Jf7Q5JyFeZ6fc7YgkqhiAqbU6eoxLFkFgqMYskAMW4BCcJx%2F5axRIS0m7atGF8me4%2FfOzvehUwvRBFotW0qlglHP9%2FXn3pBP%2F%2FLPxXNuestyq2GLZbvSGFDmpZDLSDaT8suPzNMNq677pVJW1uvBu9q0i4cWa4Z4cG6fBLFECsSmGQLR9ASV9hy1QnbeD95cgdhJVEkZkLjQybRbMOr5Xj53VX6q0ZJsMd9ZaDFwMWvLOu1KMkrh6d7n3N1s%2BkLq8EJODpVzc4m1PFDKhSIQjx7Ix34eaqFv7UDRKwekvcAL2XTn9xiK30Hr6PzLZ%2Fz4X5Mwpv%2By4ZUE5ultzM79zXvqOGNo%2BQ997ybEpukB5diOZAzrRfzD59%2BWT3z%2B6VgIw5WtllgTbkT636lQXK605LAnEo8s5mcqFMuFTOBWRC2bov2A44Z2llmvqsi3pTmkRqR29tH3uVDM%2BmVj4pxIdeX0ZaP2FhWHprSeMzlBZd6lAOeuzFyH6ugmUK03jHu%2BZ984P7Q%2F8zxRAXFluSa31xsTi8PdN%2F0VTyRevFuVSmO22ZXHDxUDs4ipcHrfUjFWc00thddX6nLJG%2FvVamuoOOw9Lw0l0Oevz2zZuyTE0Vhz%2B%2FwNuX1r2ai9pWFQfVmTO6jM23o6f4Eo5mLSxG82LOOerwbMn37hh5H82dRq%2BN5qfSQhMcmmdmOtIfc2Z3eIqfXrpCcS1d09rTg8daQUm%2FI2en7oOF%2FznuU0PannKe6n5a0X3jJubzFpP3XbZDAbKxDbRrfcM8d0rtZSE63FUbQiqjhUq1HYt1O1ZN1Zn53lWC2Ijx0v%2B27TSf97FYdxic3zLcD3av44By3uZ%2FncpkGth3cMsx5quI4p3idN5mxTL9lcgei4Zvc6NancTcOwtntK1KyIPXE4KzQucJZiQy2J7z9akoeWRrcmqtXw6GJeTh0tx0ocqgXYCmn%2F0Oem4QdRP5uNtB4aVN7GdszWB%2FOudhKJ3dClYLYR1CMcjxcmakW0IuC2qzRmKw63iw2Nb5slmmDyxImyPHK46Cew7BZ%2BKh41MUOF5JMnFuTYgXxskjR64jBs64L%2FfVaimxl8%2B8JN46yHpu2jtmNugkoUtFEk0vT8Oj%2BGdprQOMRCzoz32uuqks6YlbWuVsQ3nntDPvOlT89xoxG5tTG%2Fg0Xj27TotGYczxKt06iv5BwYMhNxuF0kqgU4ikk73%2Fva98wTDAZ1T1FM9jBG4b2nozEQ5loQHcNuSCa6mZXXXnpTVu%2Bsz%2B37zyLmcOjP4AlUw0uaTc3NGYrDHmoBjlriiol1D5VawxzrIfGH83%2Fv6ahMBJMxKQ7RVDez8sLXX5zPodJ0%2FHIm80bj5VYrLYHJ0PjRaTKVp%2BFWhMS9Jn398KV3jJwD9ZpJ7mXD4w%2FbCETjBFLfhWBQHKK6RxzbzLiS82cuy6W3Z1%2FQN0qibK1mYUWckJWt%2BT1HtWZEZR5p0peJ1kOTspc7AtHw%2BMMInJORCQYzOdbAtEKgJhbN7vH9b78yW0HutOdmdRokNLZiVmcvCqj10JrzRToK4l7DNM6%2BecHIOWDavml6hRMsiLsODlPROEST%2BlKbWDS7x62bd%2BX177w5s%2B%2BnbdeixloVN3McxywK4v7b%2F%2FE5abXMnD%2BNujnv2%2FT4w6iI4%2BgIxLbhDbkNui3pe200zBUJL3zrZalXZxNLpD15I3dBsFzczGOgVuAwOt5MNJ%2FmKBBPv%2FyuXL1yw0xx2GgZdUZapruXHQTizgGxzZ4QtmHvv9k014qoFpBn%2F%2BhbM7h0SWSExW5qTdzMI49VhEIE5hWuoBeq57%2FxkrFzwLQLtWW4HsCCuOcwM9ukYFpAbr3RFJMf%2BSwSVhqt6M6phmV2fNFYF4oIjZW6medx6fjuV5%2BXSqVm5PPXfdKk8mAabuUa30ElGodjpCoWm5zNrBPCNJFcNzhZRXn2z54L1dXcjHDyk%2BmVC8Z6jla0hP6s69bqReqHb5wx9vmbtk%2FSPaUdmZyEaAlEw7OWTHMzV6tmC0S1iKhlJCkH%2BThoXB3EVLDO8OKhF6jvPvOi0eNt2j5pev3DdoR0UKQEoukFs02Lu9ALQatlGf3M1TIyj9qIAHG4eOgFamVl3dix1thD0wwnplsQ7Qhd7HExR%2Br9m1XuxrcQ1Cl5ErarGSCOmO5a7glEs85As8vbKFFK2E1HboKY7mY2MFnF9IBkdTV%2F7fe%2FjiKAWFDMhX9s6IVJL05GCwVvXzStd71lm13doC3RykVIR3FRmIyJ6f0mNaAfhNZ3C7qA9iwO8ol%2FtnwGpTUiuUwqUj9POhX%2Bz6MXJlOzlu9fHGt1496zTf3DaK31qA2Q6RZEE99%2FzfBklR5aQPvmpdsBCovoCsRMOsUDH5F8LlpiOmxx%2F71nXja2IHYPv7SNYeE3moPgGu5etiP2%2FqMnEI3PYGobd4tSk3q9jhVRC2h%2F80%2B%2BFVg8YiGXlnREhVgZC2Isx8qfUyFOKb0gfe%2B5Hxj%2FzLW0jWllz1oWxfOj1jAkkiYGh2xm495zpVIXED9jM8guKwsRFGIqWgsRdn9HDR2rqFiDF%2FLZ8ESRdzH68z8gFlcxsQSY6e7lqMUfRlYgmh6HaOJCoeTNA7TLirrZAjnQi9nIvb%2BDBayH43IgIs9xaSEX2tf%2BT%2F%2FuPxsfd%2BgL5XrTOCMJ7uVo6p5oWhBxMxspEitVrIg91M0WRH3EQ6Vs5NzMSwt5HnCEhNnIl418JrSEmW%2F84bfk1s27PGgx05uCezl68YfRFYgubbhMdDO3WjZWxG187Y%2BeDSRp5XA5F5n3pCID9%2FL4qDBbKs3XinhkMRxhr9n7ptc7fLAHWkaef6a7l33dE8EzP7I7telWRMu7UZlWNNu%2FPWNF3HZYBJO0ogd7VKyIYYkMEzh%2BqDi353hkIS%2FlEEID9AL07a8%2Fz8M1eP%2FDvRyt%2FsuxEIg2VkQjb1VYEXeiSStf%2BVd%2FPN0i9zTFyUOF%2BYvDkESGKczrOWqCzNEDwQt7FYd%2F%2Brtf5cHe3%2Fssf%2F8z7n3jXo6sQSyyAtG1MTlbho4BVsS9IvGrv%2Fu1qb7GYjE710QHdSuHITJMQ5%2FjkRnGcKrF8pHDxcBL26hVXK3jaiUHs%2Fc9C%2Fey32YXgTiOQGy3jasDtRvbE4gmjgFWxL1oZvO0IvGhpeJc4v9UZJw8VBRqYwfD8YP5mcQj6nM7daQU%2BJxRcahWcb34QG%2FPM9N6qF4y03svdwQiFsTEDNqsRSK3aeiJxGnK36hAO3W0PFORGJbIMJ33eWI%2FTEtimM9Ny9kgDtnvfGGMeznSOifiAhHTc8vQ5uVYEfuj5W%2Bm6dk8S5GIOAwXtST67t%2BATbOaaf7kiYVQnptawSlnsxOte2ii9VCTMmxCySKdb5HJHH38t6I8gfK5rNGTR8cgl81IKmWef07LPZRKBYGdXLnwnhRzBTn52EMT%2Ffc6lQ6Wcn5h1oYdzuak4kKFaD6LOAwTHd%2FDC%2FlAnqUmo5w4VJATBwsSxnaj4lCt4LCT9fWKkRUrNMae8jbeOLQsierTj7RA9H%2FAdHT7yc5MJOrmnTUv%2B1NN71nvfWezZL6GIRI14aHoCbmG5QYW66prVV2fDx8uemuXoMNZ0HuWh8o5SXm%2Fmt66Gedxqpg%2F7onCk0sFfz6EAeKwP2o9rDfMTNSpt1pGCuPt6L5rRdjNHnnznJpfMxmzrRAm37K2tmpSLJL92o9e%2FbhP%2FvzHJ%2F4aKiz0tVa1%2FJc1YTyMCkMtyO3XXEQXzgUtpq1uZ301PdG%2F1bD9S5bltPuIwozkPTFYDrE7CuJwyMW%2FbW4Per%2F2ITkGkSyOHSuB6A%2Bg6W5m17tl2LY3DOaNg7qZ9ZaNqzk8kagcXsj5r4onKqr6arlDxaKKQo1XW%2BiW0EEYRge1ChZy879YIQ4HU63Vje0a1iQ5pXO%2BRVwkR15xqAlaF5G6mk2mZTlGCkSlY0UMJy4qKSJxY21LPvOlT0%2F9tXoWRf%2BW3xZptDo33Kbteuuw7VuclFw2HbrlCeKLlrL52u9%2FXa5eucFg9EGtZ7Vqw8j37ienEHsobWlH%2FoIQC8WhKtt0gagZ3RqvkDZQJen71tv24kKJk2UAr730pmytb8rf%2FLt%2FPbCvqRbBXucTOqDAOOKQOodDLr2VurF1fql92B0HO%2FrW41ioLodUeJ%2BmwWVfNFaHmJX9CaKYNgDiMFy0fFe90TT2%2FTcpXxYbXRMLgUhXlW03L4PHYX2zwq4ygkj88v%2FzH%2FyDGmCWaG%2Flf%2FfPfw9xOAQNmTFWFHmXfBfrYWcsXCyIwYkjrIi%2BWd7k2A0tJtto0Lt1GHpAqxVHD2yAWXD65XflT3%2F3q%2FRWHkKt1vDr%2Fxm7h9skp3SEcjzmQOTrID5QR23JGZ7NrGh5gHwuZ%2Bz715pR5XKRhJUh1OsNOff2RVlcKMvxR44zIBAa2v7xua%2B%2FQOer4UeYrK9vian2M%2FUCcsHvnWNOLLyisRGIOpRZQzuK7N5kspmMscXD1cWuUyCfzwkMv6VeePeyiHdpf%2FSpRxgQCPYSUm3KM3%2FwDXnzlXcYjBHY3Kz65cpMRa2HDnHkPnGJw4yPBVHEF4emF83u3cRMbkGoruZSMe%2BJZObCKFy%2FclNuXrgpj3%2FkccnlscLD9Gj4wld%2F7y%2Fk%2BjXCGEbbsyzZqpgbe6gX%2B3qzJUL4oX9xt2MilGMlEHEzP1hsOg4mW1M1FpPi2aOzsb4lZ147Iyfff1IOHF5kQGBiNN7wa195ViqVKoMx2rEla2tbRicY6n6tblXQmsZ2bOZCrAQibuadY5EzuEexuirUzc6FYYyNqWXJD199F5czTIS6lL%2F9p9%2BRF7%2F9A%2BINx0BruDabZpd20bI%2BFCLpFMdWD1hciJcFUXAz9%2Bgkq5htRdSElZJ2WKHH21jgcoZx6bmUr16%2BzmCMc5G1HVnfMLs8l8ZdYj3soMWx4xSHGTuBiJt5m1j2hJEmrJh7G%2BtsPriax0ddzm%2B99EOynGEomqX8zJ8862fGw3ioa9n0un%2BNpmW0e32HWG7ZsRqL2AlEHVptu5fGatRJVsmabUXE1TzN2HWynJevL8upD57Cmgg7WL2zLv%2Fpd74q7759nsGYgEq1bnxZF92f6ZzS0y7xci8rqfyHPhc7aZ%2F1xEABQeBTKOS8sTC75Iv2pz529JCkCT2YmHw%2BL5%2F74qfloz%2F5EQYDfKvhqy%2B%2BSeHrSYWR7ci9lQ3jx6FabxKv2kWTUzQsCoEY9g%2FtCYIybsXOWKRTcqBcMn4cNGHnqCcSYTo%2B8Ngj8tlf%2Bowced8Sg2EgGmv4zT%2F5Fu3ypkA9iMvL67FopRaqSHZcTyASltCj7onluLUMjl8MYu8H94QRdfDE97mrizVj%2BFj4cT4U0J4ajU08%2FdpZcZoOmc4mHV7dDOX%2F%2BhffJdZwSrYq1di5EkOZU80WsYc9sexdFuLYYjGWFsSOsk1LsZBn5klHIC5iRfQ5fvSQZAwu%2FxMki4tl%2Bfwvfkae%2BNjjDEaCef07b8oL33oZd3IAaMyh6VnLnQu7K5UaF40eTcsW24rfpSG2AlEplwuSEpJVFO0skssSl6mW1GPHlujVHCAnHz4hX%2FjVX4id29ly2t7G7EjDeuDqy2W9i6X3KuTwPlx6%2B7J895kXcScHhBrL7t1bi50bMQzUemhZWFF71OrNWFpTYy0QtQ4g2asdsCI%2BQC3LS0t0CwmaD374cfn8%2F%2FyXpbQQ7fjfjbota9WWJw4Hx4DlMmk5WMrKkcW8mFYQQeMMv%2FPn35VbN%2B8yqQNkdW0T17IQe7h3PBy%2F1E8cibVA1OxVauA9ACviAw4eKEu5XGQggr6U5fPyYz%2FxEfkffuEvRU4o1pqO3N5oijVGIVq9WB3zROLhheTHrmrZmhe%2B%2FqKcP3OZiRwwWtKmUqkzEELm8m407CCuCUuxFoiKWovorPLgsMOK%2BADiEc0Rimo1vL0%2BudViqZSV44eKibQmIgzDRVtYrq5tMRCC9XA3Gm6g2ctxJfYCkZqIO6Eu4gOIR5yNUPzQR5%2BQT3326bnFKE4rDnscKGbl4cPJsTprjOHrL7wpV6%2FcYKKGJQA8QbS8skHcYResh7suDzGsfZgogags4Ep88EDVilgqGt1dZTvEI84OjVF8%2Bud%2BQh5%2B4qGZfU91K19bDc61d3QxL8cOxLs6gmYln3nzHDGGM2DFE4dxLF8SBlgP%2B%2BxPMU1OSZRA1Np3OVyJ98GKuJPFxZIsLuB6nxWa9fzhj39IPvnzHw%2F9e126Wxsr5nAUHjtWjl2Ws9YxfOO7b8rbr7wjlUqNSTgDNjaqUm80GYguWA93C%2Bb4JqckSiCSrLLroWJF3MPSoUUpFqmbOduLW7ju56Bcy7uJk6tZ3cjvvPou8YWzFuSeGNrYrDIQXSzb9sQydTS3E%2BfklEQJRIVklZ1o%2BZ8ShcR3XCKOHjlI0sqc6FkVP%2FypDweW1HJlubZvKZtpeOLEguQy0bxgadLJK99%2BVa5ceA9r4Rygz%2FJeKrV6p5sV%2BMQ9OSVxAjGbyfiuVXiAulXTWBHvQ9JKNNB%2Bz0985PGpxKIWwb50NzwLzkNLRTlUik7ym4rCs6%2Bfk3Nvn6ew9TwPfpJS9qCJGI0m1sPtxLVzSmIFokJnlV2iOZuRchHX%2B3Y0VvXo0UMMRMzFYtDJKbs5spCX4wfna4HXgtbn3rogV89fRRRGANWEq6skpewck7ZU6g1pYz3cQTUhbQYTJRDVrZqn5M0OFkpFXO%2B7KHmi%2BdChBQYiYhw9uiQf%2BOAH5NSTjwzt%2F7y81ZKVSnhWi4V8Rt5%2FdLaJTZpocvmdS3Lx9GW5df0O7uOIsb5ewVK2Cx2PFi31dqBlbZIyJolSU7Z3s0Mg7jp0Wi0%2FYQW2jUmjKZlsmszmiKFWMn299tKbfoLLyYePy9GHjo0kGOOIuo1vX70l1y%2FdlFvXbmMljDCasYw43Im62RGH%2FXVIUkiUBVEpFnKSyZCIsB1a8PXn0MEFst9jhCa6HD1xRI6fPCZHnnxUGpnwXMBBWxDVOnjLE4LvXbwhK7eXZWV5DQthTKjVGrK5xbPaDWVt9pKE0jbbSZxq0GbppRICcTuNluUn8VD2ZpdVYLPqjwnlb%2BKBFn72iz%2B%2F0b34lMty4tGH5Pipk3Lw2GEpLJYlHVCryfSEPfc0brBRrcudG%2Fdka31LVu6uemJw3duXsD7FEc1ERRz2E0Iu4rAPSYtPTZwFUdEDXzNW4QHqei9S9mavEKD8TSI5fOKYHDx8UA6fPO6341QBme3O%2F%2BJCUZzs%2FhUPMtWKpOt7k2A2Vjdlo9t3t9Vo%2BgJQQQQmD3osD4ayNn1Es%2Bv6tQ8RiBFHkzIQQ3tZLBcljXBGJALA%2Foe97ciKdxmgnM1empYlzQS5UYMbl2SUttlxNiZycTuutIWFvZs6i7ovegjoYeBQvgIAcYg43HevJDFlL6o37ASOS2LNSS2Lw36vcHb8lkjQf%2BNTdxJnAgDiEHHYH83kpubhXqyE6o3ECkRV81gR%2ByzwluUXN4U%2Bh4Pr%2BoVwGR4AxCHsOlMdJ1ElXAIdGxuBiKpPAHr7U5EIA%2BaMt9ARiQCG7Yveel%2FfqCAOB45PmzqQA3WGnVijS6IFIredwRNa4zQBkQiA%2BKGF3jCaLYus5X3Oi6SSTvbCb%2FtiCPZSbzYZBEQiAOIQcbgvruuSmLLPOZHkkK20CQ8Q%2Bi36tl%2BuABCJACaiMYf37q1xRgyhhmt5IHbChXPiBSJWxMFoLSu9HcL%2BInF5eZ0SOAAJE4ckpIxwRljeGUE4Uv855DiJnz9GVE0mFpHb4VQbgSeiqZMIgDg0CTUeUBB7MNrWN%2BkYIRB1I6Bv5ICx8W6HuJpHm0OIRADEIcYDMMF6aIxANEXtTwqu5vFEYtL6bQKYQL3eRByOeibgWkZPmCQQsSJyWwxqHmm9ND1sACA%2B4nBjs4o4HGWPw7W8L6ZYD40SiCap%2Fok2Be%2B2SCHU0dHDplKtMxAAEWdzq%2BqvVxiOJnViLEBHGCkQVfVT0mCfiU8B7bGoVOqyscHBAxDZi5y3Pms1rP2j4hfE5gwYiEnWQ%2BMEokLJm%2F3RAtr0ah5jvBpNWVmhViJAlND1qOtS1yeMKn4oiD0M07yQxglE6iLujxbQruNiGO%2FSQa1EgOgIne56xFs03rlYo7vW0H3etBjWtKkPGgajdSMtGxE91qHUrZVIhjPA%2FND155ejoirDWKhRoE2v5f11g4GGJSMFIlbEETbaFqVvxqWX4UzyCsDs0XWn649M5fFQtzLNJIaLQxNDr9LGPnAWxP4i2u1ksxGPOMFBVfEOqvUKcYkAM7nwi7%2FedN3BmJdal%2BoV6AUEYp9NpS1NrIj7bx5a%2BqZFPaxJ0E2XuESAcOnFGyJyJjsDayTxDKVlqPXQaIGo2PrgBTPPvjcnb4yIR5zw8OrGJVJUGyB4ep1RiDeccPw8Ue0Sd7i%2FiBazw9HSpk%2BAVhPxMwziESdH46G0SC8uZ4CADu2uS5nOKFOce8Qdog8QiMOxHYcb6LANmXjE6UU2LmeAqcGlHMCllbjD0eaaN0624e1500wDimePtKkQjxjIhnNvZYMsZ4AJ0HWj64cL%2FRSXfeIO0QUIxDEPbk%2F8OA6WnVEWDJX2AzjoKnVZXdukpRXAiJdTXS9kKU9PrUHc4WiawKHtLALxAaa10JkUdU2wcIKZb8srG1KrNRgMgEGCxlsfuk7Yn4PauzGEoAcQiOPfUimePfqm3WwSHB7QnNvcqmFNBNi9NrpWQ10f7DXTo5Uo8P6MOFbeODHnEIh9FpFD2ZsR8JNWGk2SVgK8rWJNBOheQLEaBiu2XeLHRz7btKwNiYQIxL6TwxM8lL0Z%2FYZfJxMuuPHEmgjsKVgNQzjTqnqZJ%2B5wtMt608bwgUAcDGVvxhgr76ZFuYSAN6iWLXeX18l0BqPQ%2Ba7zHqsh4nBeUNZmL1mGYC%2BWt0llinkGYhRBY3ljlUlLLstUCvTArNSlXmvKoUMLks%2FnGBBI6IXIko2NKpfyEPAbHOCNGH0uNnHD7wYL4oCbBHEIo1P3SyewEYUxD1fXtvyuEWz0kCR0Puu81vmNOAyepmWRdDkGJKb0B7PPPhMmm01LyvsFw1FXxkKxIOk0d47ALQHNlm9pKS8UZaFckhRTEmKKnsHVWl1q1QYHclhnl21LE2vY6HOSxBQE4vgbWSdhpVDAvTfSeHUzmxdKRU%2FAoGCCRg%2FTntt5cbEkpVKBQYFYUa83%2FTmMxTA8tEatenRgdEhMQSBOhAasZt2MZLCKjSZi3PZ9SyIiMaQDwDtcNzar3iHgCcWFEvGJEP0DuGX5SSgkoIS9%2F7p%2BjVoYbz8lMQWBOMXtwsJaM84m1S1%2FUy4yZuEeurastrY8gZiVpYOLks5wiYHo7QXrmxWE4SzGmozlic93QCBOtfA0HjGXY6hGRcvfqEgsFcgEn4VQ1PIgJU%2BQH1gsIRQhEsJwS8MhGlizZoG6R2uIw7EhMQWBGMwhrKVcshlJ4zYda%2FEpiMTZoIexvhCKgDA0Sxyq5ZAqB2POVc0xIMsbgRiYSGxaUqQ24tgiUeM381hfEYqAMITAqWmJMcThROc5IBADo1cbMZfNMBhjoCVa1PBKIe35CcXFhaJvAQcI9JBtWVKvtxCG81rj3t7qkGAxNmq4IJMegRjKxKI24iRipSVSRCTOUyhqMgtZzxDIpc9bz7V6g%2BSTOYtDCmGPDzUPEYjhTa522y9AWiSuDpEYM3pZz%2Bryp44ijL%2F3qTCkjiHiMN7o%2BU3NQwRiaGghUlzNiMTYzt9uHcWtrZrfmUXLERGnCIPQ%2BLZKrS6NeouMT8RhrNFz2yFeE4EY%2BkTD1YxIjPvB3%2B3Moi%2B1iGsCFklYcH%2Bd1juhCbiREYdJwHctM3YIxJlMNlzNiMQEoYlE%2BspspaVULmBVNPXSgLUQcZhQcC0jEGcKrmZEYuLmtOvetypqUotmQBf9tomMTXIvu2otbPgWQ4L3EYdJBNcyAnE%2BEw9XMyIxoahrUV8ar6hCsVDIJd4F%2FYX2lvzYzauyVa3KK4%2F%2FiLyWW0qsKNSEE7WqqOUYEIdJpdcJDSYjlf%2FQ57C7ToFmhRK7NR0lb%2FwQidFHOwkVCvlEisXfbNyRE7UtuX532a8tl0qn5Pb7H5WvH3gUUQiIw5iiJZnIukcgzhXtFEKvZkSiiWJRXdFxd0P%2Fn%2FXbcqRekXqrJXdX1na%2Bz4feJ79z9KlYvi%2BNKWy2LEQh4tBIdPxop4dAjIbAKRXo1YxINPeSpEJRrYv5XKy6tvzj6k3JN2v%2Bn5fXN6Rab%2BwVwzESidrdRMWg1bKJKUQcGotaDdV6CNPBaRwQTW8yUnx4yo1R%2B4oW2lLI0e0jbvRiFhW%2F%2F7YnFFU0qmCMaka0Wg574lCpNfu3jHNv35G%2FUSzJXyw8Er2D0BOBaiXsjL9F9nGM0SzbhvcMEYcB7Ef0WkYgRgndmJvewi7gap5OaHsL23XbUqKEUKxv770Wf1EVjP%2B7veq7lXtU6nVpu4PF1Yn3rsrTTy3Kq7lDCEIIRRxWvfXikm0bzBnCukAgRg1bs5rTKclkKH0zDb0bNCIxmYJRQzFUMGZzmW78bm6mMYw%2FmWrKE5urO%2F6tVm%2Fuf4B74vHpy2fk9Ac%2FJfXUbNa3igWNobIdxxeDFK1GHMKQvcZbK7peAIEYzduLt4mXSpS%2BCUIkqiWxXMx74oGxTBJ6u%2FeTJrZpMrUyaqJXTzRmvUtWGJbGsrTli6s3ZfcR0rCGxyupWPv7196R%2F%2F%2FUjwd%2FsNmO%2F%2FVVTKsYtC0HK4gJa8F73jUVhy7Pemqh7f1qcolCIEb9NthsWJS%2BCeg2qDfrBT9LFpGY6GftHZTOLtGoqFs6nUr7wtEXjenUVBbH32jcFae9Ux5q7GF7xAO6urUln7dW5Nnc0fHFgOP61g3b7og%2FFYKO7VKGw2BxqPtbG3EYCHru0i0FgRiLw06tAXniEaffRL1DVTNL%2FfZvadq%2FmcZ9t2ofD7B2MdJ6hZl0RjLZztzYvubUjb2dj3lf5HBta8%2FXGbcEzFNXLsmzHzy67VKoFm%2Bre%2Bi377u4OlZAFxEIe7Bs209IQRwGtE90re8QLJS5CREt%2B5Ghp20wE9UTAuVCgfGEyeZPSuRf5T1x6O7NbuwVxx7rQDpyXP5l%2BhgDCxOJwzolWAJD2%2BhR5zMcOG1DRLMNNS4Cpkdv2mpJ1M0VYFw%2BW2hL3t07dyzHGVscKsdrFQYVxkZrHCIOAzwX%2FLhDStqEBT7QMCcv8YjBb7DaOinn%2BtZZgFH5lUxKnrYXpJpypSKuNL3XZsqRTXv%2Fw0XjHnNp7%2BX9XsikZSldkKVUTrLtlPyjoiP%2Fb4OKBTDaWVDTvYsM20Ah7jBccDHPQoXnstRHDHpMsxm%2FDA7JKzCMH82n5T%2B4jb4fW2m2pGJPZoGwvTX9y%2BkDDDDsi5%2Bp7M0zytgELA61BBRFxUMFF%2FMM0EnMzTHgMbU7Gc4ugckwhC%2FlBt%2BBW%2B7k6zLrrevP0TwJ9kHj46hxGMa4OohDBGKCbjstm7pmQd%2FMu5svhVFhEEvplHxhgIXQaatAnO7g%2FjW7xiBD%2F8uHJ2A0bppM5YD3%2FTb1DhGICaMTj0hwcuDj6m2%2B2gWjaRGoDHv52UJKDg6w3ljt6a06x%2Busadi712syCpm14aDnKHGHCMRE3nzYNELaNJqW35GAjQO28z%2BmB4vApj295Vnn26%2BXcB%2FCgz1evRoW7s9Q0PMTT9zsIHNixjgORbTDwo9LdCmqDQ%2F4q%2FtcyOzuQWMfLMrqB07Kjfc%2Fdf9jB7dW5eSlS1K%2BuTb0e3zC1u9RZLBN338cx7cc4lIOB78YNrGcCMSko7fLjHaAyFAiI%2FAbvNu5wRfzOcllmd4m85MF75Kwj5Fw%2FaGD8p2f%2Bivyrx%2F%2Fhf6f8NMiv3LvDfnsq1%2BVE29fHvh1PqBu5iwC0WTUstXCahgampSCVRaBaAwaZFsspiVNmZbA0Ru81ku0tV5iPkcpHEP58Wx7oEB846c%2FKf%2FsY78qy4UF%2BcVjTXlyyZIj5QcHUMtJyZW1nLy98DH54%2BOfkL%2FzsRflr%2F75v5fs5t5yOW3v8PqRUkrOWliOjNtrqG8Y%2FqWfpJS5kckcffy3GIZ53YpcyeFqDm9jcV2xvVc2k0YkGshv5EUe7XNwqzj8B5%2F8%2B%2FLxoyn51acqcuqQJaXcTteVdnQ8Wnbko0db8kTJkT%2BRJ2XlyR%2BRHz%2F%2FA0k39x5Wa%2BWCvG0zx0xCXco1Sm2FTp2klLlBoNacb58NMpvDFYmeCK%2FUGrh%2FDORn%2BsQfnvmJD%2Fvi8DOHLfn8Y1XJZ4YfPI8tWfIbnpD83pGn5Jkv%2Fm99P%2BdjDln0JqEuZa2eQLxhyOOMOEQgmozj3T6biJfZbOhkORvDo9m91rzGwaL800%2F9Pfmpg7YvDsdB3c9%2F%2B1RVvvzIz8i1T310z8cfp8ySGRdOb7%2Bu1LlwzgI9Fx2sswhE09GK8Gw4Mxhn2%2FE3dwprJ5%2BTmb0C8fVPfFIuZsvymfdPVtxaLYmfXHDkv%2FzEl%2FZ8rGQxp5KOX%2FiarigzwaKNHgIRdi4IAp3Dp1dYWy2KWBOTi5%2BgsotnH%2FsZ33q4WJj8gH%2F6REP%2By6GnpPbw4Z3zirWb3D1Daxv29gxcyqGj5yAGEwQi7KLRtDCpz9IaUG9QV8sgvrr4mHxgcTpX8MMHOgfXrSee2POxfm5tiDfqbaj4%2BwQXgFnQaSZBuAYCEfqiHUGoFD%2BjzUhrJnqbP9bE5PGU7Hyet554yP%2F9WHm6C0EvqWXzwJE9H%2FvJLJeNpNApX9MkEWXW4pCkTQQi7L8xsUhmC9bE5HFw98WrFFwh6w8XsSYlmZ7V0LZ5zrOEHssIREAkRvP2ijUx0Sytrgf2tc40%2BndAOoyHOfb7LlbD%2BaDnHZ4zBCKMiMYiIhJnD9bEhArEW%2BvypF2T61vTFaavNDtb5rF7N%2FZ87GEXi1Oc1z1WwzmJQ%2B9STuw9AhEmEInUSJw9PWsidRPjy%2Fv7iLXPr7wjZzemE4iX13P%2B7yfPXdrzsXKbQy52a50M5bni1zrkMo5AhMnQWlCIxDmNfbduIiUX4sepPnUJ%2F%2FKZ%2F%2Ba7h29t5Sb6mtqf%2Bb8tF%2BUfXv5m357MEB%2F04te0LKlU62Qoz1EcUusQgQgBiEREypwOErftWxcquJ1jz2PvXJFfW3tH%2FvS9si%2F2xuXlGyW51UrJT7%2F4DIMZ5%2F3UE4TqIWhSTmVuWN7lG3GIQISgFhSFtOeKdk%2FQQ6VOEksseLGQ7%2Fvvf%2Be5P5RyrS5fObc4lkg8t5yXZ1by8k9f%2FR0p31xjgOO4hrvuZE1CcXEnzw2%2FEHYLcY5AhEDxC2kjEucu1HE7xxdNVvnn3%2FgX0qo05LfPHBzqbtaklD%2B%2FuCi%2Fd63su5Y%2F%2Bl%2BfH%2Fi5tRTbaRTBnRwtcUgh7PiQyRx9%2FLcYhvhgO65k0ilJpzmM5nfidNxUlm17zyLjPQvqm0SNv5EXeXSAGMisbMgnLz0v9RPvky83T8nN9Zyk3JS47bRUWhn%2FdWsrK6%2FfLcq%2F94Rh3hMW%2F%2Ff3f1uefuYb%2B37P50tledtmLkTqQuet0VqzRXYy4hAmIMsQxA9dZMWCqvsMgzFHetnO%2BhxKxbykU4iDeBxUbd9N%2FKu%2F%2B%2F%2FJpz79tLx76pPy5cbP7Pm8L2xckH9y7QfysRe%2BO1JSSgOvZYSesSv1VssPDYEI7JVqxW3hdUEgwsxEYqmURpRE5Gas7qtcLivFfE5SPJO5szni5z35%2FKvypLwqX5R%2FK%2BtPnpRWudNx5cTblxnEmAqReqOFKzliz6RBlxQEIsxYJHqLrojlKjJofKK6nvOeUMxnswjFOXJBxh%2F7pYu3pvqeFx2e9zxFSLNl%2BWsQEIeAQDSeXks%2BRGKEnonb9stnaBILQtEs3iC8ai57oApDksYQh4BABERirISiWjQK%2BZzksiy1WXIJa17i972W3akPSwcUxCEgEAGRGL%2BN0u3ERDXTFkJxhlT2OZdymbRIwNY%2BO8dzRRgC4hCBCIhEQChGmuo%2BZ1MY68Ol1BHCEBCHCERAJEIQQjFHjGJovNNyZ7q7bWpdUiqqhCI4tOuG5TgIQ8QhIBBhWpFYrzelWMhRJzHiQpFkluRwTy3CLcYhSLFBVjLiEOYL7TgSCm35YiLou0Kx0u3z7LLBBsbb%2BdndfysMdyA4fs%2Fzpl9XFHGIOIT5ggUx4SKRjivxEYqWa%2FuHYjabkUJOLcDc36Zha4a9kd9N5xjwKdCWeE1v7tP5JG6CnvZ5CERAJMLM0L6x%2Bkp7ArGQy5LQMiE3BhTLzoUgHOsYT8ZGLU8WiSeIQ0AgwnxFYj7X9pMiIEYHqPaTdVrS0IQWT%2BDn8zmSj8bgzoB%2Fz4QwhF9r8lxGFxaun5GMCxlxCAhEiAB6S1fnTQGRGDvUutJyO5YWdT9rUksWizDEaQ771kLHm8OWn6AF8cV%2Fji3EIQIREoXdvbEjEmP8DHvu53TKF4lYFQfzlj14XLKptNjtYOLdWgXiDwfOV8fxBQXWwmSgcaI2zxKBCMkViW3XlWIhz2DEGHebVVHjS%2FO5jC8YKZUz4sbnCWybJP9w5ma3dqGKQ6yFiENAIEKM0BigXkFtSMLzdKTeLWmU85NaMrigPa47nlDJpiRvhytSrqZcEcN10H0Xsk0mchLR88Jxea6mQR0NU0WFt9i1oDZ195KFuvJq3nPdqtU7dRUN3dQPeDvbP1hKyUah%2FxaXSwe39WU31%2BWUgVWy290s5FrDm2%2FVujR0viEOEYeAQIT40ytwikhM4OGtdRU9sVipNbxX9%2FA2aJP%2F24cy8nimLasDhGBGgnPF11xLfmX9ihyX5LvfdotCbRtp46tP7Pmgl03EIQIRTBUS3dZ8dF1J8Eav8YrbxKJaFu0EP%2B%2F%2FdSkjP5fvHGpbA2IyMwHWuml4Y5n3RNIvVq%2FLYgIbMvsxhRai0CRUFNIdBYhBhM4hR61EY8Si2%2B3YkkqnJJNO349ZTEKCy88tZOQLhQcibZAnORtgseyW2xFLx%2Bp1%2BaX0Dfn90qMJmCeuWN0MZNzGholDahwCAhH2HHTUSjQKdUPbrnPfGqSdW1QsalHudDp%2BzoUfK6bl1xd3ipnCoI0vIDG84e6MPXykWpFfzNyRP8u%2FL15zod32rcq2Jwb1dzqbmHsGUJIIEIjQF78MjndIkOFsHmopaupLrB3WRS2jE%2FVai0%2Fk0%2FJ%2FHNwrauxMyALR2Zuc8pHNVVk5XJTnM4ciPWZazUDjCW3XxUoI0mxaiQ49AQQiBHFwdDOcC55IpAizmeyxLqpgzKgrOh05wagZy7%2B5JLLQ90ca%2FHNmUmlxpiyWrQkq%2Ffj02k1pHknLD9IHIiUIO8%2FUJeYYHqx171ezYZGMAghEGI1ehnMhn%2FMEAblMxs%2BH%2B7GLcl8wqhtaYxfV0jjPOfJ%2FeULsRGqwS3RQLcSc9x6m1Un2Pq7Yn928JXeWCvKe5OeyfjWO0O%2B8g4UQhuzzJKMAAhHGu1nq5tFs%2Bb1%2FSV6BvYLR2ZHNmvHFYsoXiyoaZxHH%2BOuHtZzN%2FuKnGWKx7P3a9Wlms5a%2F%2BTdLT0klxIIRbV8Mdiy%2BaiVUYUgHExgGySiAQISp8ZNXvAOnQM9ZGHLg%2BBa5bWdOTzSqWAza0vhLBx%2BUs5kXdWf%2FgH4Vif9L9T35w4VTgYhEX%2Fx5gtDxrYOuJw4RgzA%2BtM0DBCIEhp%2FZ2GhL3hOJxCXC2KJxG%2BqeTqXSks2mxftT19qYGqvMjpaz%2BVJpNHFY8b7PgTnWJ9TyN389e1u%2BUnh4jHFz%2FdgwFYK%2BVVCthLiJIQDojAIIRAj%2BsO8WTyUuEaahY%2FFy%2BiZKZLo9pFU8%2Br%2BnM9tE5QMB%2BfHCaN%2BrnkvJ2YW83F7aa%2F3ebGXEcicPQqzalqytluXw3drQz31ia0MWCw%2FdtyKqJVDDvnRNqRDsuOy9V9ulxAyEs%2B6INwQEIoRJLy5RYxLzxCVC0JeQrmjs%2Fd6UnTFSPevjDzZz8qmjmaFf704hK3%2F3y38Q2s%2F7tz7zs%2FLXZLhAPF86ILfr9CqG%2BaAFz1st4g0BgQiz2HD8uERXigXqJcLs6Fkfv7%2Flym8eLQ%2F9%2FPc1bflHX%2FxlKRdT8gs%2FusvsWNQdsI9buzpc8F1aScl%2FfKspf8m9O9LPfdX7ZohDmAfEGwICEWaOxkZpM3dNXsmkcTnD7Nhw2vJmoy0fL%2B4ft1iy2vJntxr%2B5%2F%2FWr9dHE6F3lod%2Bzss3TsqLG658UFJybISv%2Ba6vRgFmeJnSHtpN6hvC5HCqw1S0u3EttGeCWfNabfjBd6HV9sWh8v2L5cC%2B95nljjC9lioN%2Fdw7%2BYLcarPVwiwv7w7JKIBAhGigpXA0NhFgVrxaGR5T9W7jQUD%2B8%2BcygX3vC2udGMkrqeEhFm9nDvKwYGY0%2Fb3YIhkFEIgQpVtrx%2BXsEGsFM%2BCG5fgWwv04U3%2BQpXzuTjDt5dZqeXlnvWMxv%2BRmpZnZX3jiXoZZ0MtSJt4QEIgQSXpZzi02KZgB363sfxl5p%2F7Aynj%2BXjBZnK%2FcWNzx9yu5wW7mjVwO9zKEjmYp1%2FVyjksZEIgQ%2BQ1L3RzebdbFzQEhcqY2WPRtjz9UTq8GEwLx0rWd2dD7xSGeyy7ykCBU%2FAs5JWwAgQhxoldY27IdBgNC4VzTkdsD%2Bixvjz%2Fs8cxbC1N%2Fz%2FMrO%2F%2B%2BXxzim6kyDwnC2V8J6QEEIsQZdTnr7ZYEFgiLH9T6C8TXK3vDHL53Yfo2kefXd154BsUhqntZPwYQNL2kQBJRAIEI3HYBBvD8Zv%2FLx%2Bv1vW638%2Femi429sLwoV6t7LeL94hBxL0Pg%2B6jr%2BrGGlBUDBCIkil4CS7NJvAwERz8385uN9gCBN93ce%2BNW%2F3jDfnGI70mBhwOBQVw3IBAh8diOgzURAuWdxs6%2FnxkgEN%2Br2LJSyU38fd69199lvDsOUV3Or7YRiDA9vfI1VIYABCIYAdZECJLXqjsPz7O1wYfpsz%2BcXLi9fqu%2F8Nwdh3g2j3sZpkethpSvAQQiGAnWRAiCFyst2V4SsV%2F8YY%2FTNyf%2FPmfWBwvP7XGI56XEQ4GJ6VWAwGoICEQwGqyJEATf72YzD4o%2FvC8er082z165tiTr1uCvvT0O8ZzkeSAwEa1urCFWQ0AgAnTpWROpmwiTcLbbVu%2FMEIF4bmWykktv3dnfNd1rqXe2uChb7RQPBMaCDGVAIALsw%2Fa6iWTrwTi8XO0Iv%2F3iD5X1livnbo8fh%2Fju8v49l7WlntY%2BvJBe4GHAWKj3hAxlQCACjHKbdrhNw3hoW72Xau194w97PHdmfBfwxZXhLr%2Br2bK8RfYyjIh6S9Rrot4TgKhBmX%2BINBqPY3ubaD6fk0yG%2Bwzsz7%2B%2BWx%2Fp887eGt9S89K94cLzL%2BQQ7mUYiloKW02LOENAIAJMu5mqyzmbyUi%2BkJWUcABDf9SKOArn742XqPLN80dG%2BjzEIYxy6cUzAghEgABRN4xdcySfy0oux9SFyXn5llbWHl3Mnb6rbmP6icPkON7%2B1WzZ9E%2BG2IDPDmJ5A69TOxGm5PsXyyN%2F7pllLIMwoTDs1jRsNC3EISAQAcKm53Ym2xkm5flzmZE%2F98IaSQQwHm3vVy87mVhDiCP46SDet%2FNutnM2l5UCbmcYg3N3RhN9a7W8vLNOzBiMjsYY0gUFEIgAEcD2NmPHdiSXzRCfCCMxaqLKKzfoqwyjXliJMwQEIkDk8Its3y%2BLk5VMJsOgwEBOr2rSyfDYwpeukaACw4Sh6xf4J9wFkgQxiJA4OvGJFoksMJRn3hre9eT8CuMEA4ShJqAQCw0IRIA4CsXO5k2QOPTjexeGWxDPr5OgAjvRBBR%2Fb9EEFC6hkFBwMUPyb%2FneBu44Lb8Ti8YnZtLci6Ar%2Fu7tn0hwYXlRrlYRiPBAGLYsx495BkAgAiRQKBYKOTqygCcA909UeeNWyft%2FLEQIQ4QhmAemFDBSKNZqTWl6m71u%2FGAu71VsWankBn783XvcoU0XhrpP6H6BOAQEIoAh2N2NXw8AAszN5dkfFgZ%2B7PVbzAuEIcIQzITrMSAUtTSO9yJG0UxO3xz8sTMUyDZOGOJKBkAgAuyAZBYzef16%2FzjEV64tybqFBdGIte%2B6fvcTMpIBEIgAw4ViWoVihoLbCefcSv8i2G%2FdUdczlqSkr3XLRhgC9AMTCcCgw8MvgtsruE2pk6Sy3nLl3O29cYjvLnMxSK4wdPx17ddIRRwCIBABJqHXmaXmHSgWmc%2BJ5Lkz%2BT3%2FdnEF4ZAkdN3q%2Bq35wpC2eADDwMUMMOoB0%2B31rK9sLivZTJo4xYRwtk%2B28kv3LAYmIRc8yybxBACBCDADOpnPQpxiQji%2FSwx%2B8%2FwRBiXmqBvZshzabAIgEAHmcAh5h4%2FTdCWVsiWbzfhikQ4t8ePlWw3v%2Fx88t9N3NSaxxcDEjI4b2RHbdnyLPwBMDv4xgCAOpnY3vkkLbzctAt9jyPcvlu%2F%2F%2BcwyIj9WFzVvvem60%2FXnxwkjDgEQiABRw3YcPztSsyRbJLXEhufPPQgTuLBG1nrkL2XSiQmudbORbSoNAAQKLmaAkNDgeNc7wKxel5YssYpR5tydjsBYq%2BXlHTqoRBY%2FttB2sNIDIBABknCouf5LYxUznlAkAzp69BJVXrmxyGBEcP3YGu9LbCEAAhEgiejh1suATqdSvlgksSUanF5tyVY9Ky9dywkJKvNHLfCabKKikJqFAAhEAKMOwPsu6HS6Y1nMphGL8xSJN%2FJyfgX38twuUKIXqE4WMqIQAIEIYDx%2BuZyWK62WIBbnyJtX03J%2BnWSHmYtCu%2BM%2BpmYhAAIRABCLkePZM7ZcrSIQw0atg0430QRRCBBNUvkPfQ47PkAM8MVipiMYNX4RIHYXH8clphAgJmBBBIjTAavWFsv2BWJaLYtd0QgQyTnrOGK7bbKPARCIADALegkuvXSKbCYjaU8o4oqGec%2FLTkkn6hQCIBABYO74XSS8l8Yt9srnZLAuQshogonr1yjESgiAQASASHO%2FfE737z2hmKY4NwRAL7GEWEIABCIAxPlAvx%2B72BWMXaGIYIRh9CyEjtv7HbcxAAIRAJIpGLtt%2F%2B4LxvtiMeX%2FTgyjufRiCH0rNBZCAAQiABgsGLsWxp5LOqUxjCoau4IRK2My6VgH2%2F6zd7slaAAAEIgA0F84aA9cP%2BlF7lsZ%2FbI620Sj%2Fo6lMT6oJbDtC8GeIGyTUAIACEQAmF5guLtEY8oXjR3h2Psz1sY5i3u1CnbjBdUe2CZuEAAQiAAwUzHix6u197gmdwhH7%2B9%2BXKP%2BG91fAsMXfW3xXcO%2BNVDauIgBAIEIADESjtaDj6lITG0Xj2pxTAku634CUMQXf9JuIwIBAIEIAMnFz4p1BgudnvVRuuIx1fnH%2B%2F8Wd0vkfXdv1%2FrXE4H6S%2F%2BHOxgAEIgAALvoWR99MTWCtcy3SG4TjP6f03sFZLorNAMVuv1%2B%2Fq7rd%2FvnkQwCAAhEAIAZ4gu13QLMYVwAAKaFlEMAAAAAQCACAAAAAAIRAAAAABCIAAAAAIBABAAAAAAEIgAAAAAgEAEAAAAAgQgAAAAACEQAAAAAQCACAAAAAAIRAAAAABCIAAAAAIBABAAAAAAEIgAAAAAgEAEAAAAAgQgAAAAACEQAAAAAQCACAAAAAAIRAAAAABCIAAAAAAAIRAAAAABAIAIAAAAAAhEAAAAAEIgAAAAAgEAEAAAAAAQiAAAAACAQAQAAAACBCAAAAACz478LMAA53Eh%2FTCXfIgAAAABJRU5ErkJggg%3D%3D%22%29%20center%20top%20no%2Drepeat%3B%0A%7D%0A%2Ehero%20%2Econtainer%20%7B%0Aheight%3A%20600px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20%7B%0Atop%3A%20auto%3B%0Aheight%3A%20auto%3B%0Abottom%3A%200%3B%0Apadding%2Dbottom%3A%2060px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20h1%2Etitle%20%7B%0Amargin%2Dbottom%3A%200%3B%0Afont%2Dsize%3A%2036px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20h3%2Eauthor%20%7B%0Amargin%2Dbottom%3A%2010px%3B%0Afont%2Dsize%3A%2030px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20p%2Edate%20%7B%0Amargin%2Dbottom%3A%2030px%3B%0A%7D%0A%2Ehero%20%2Ehero%2Dtext%20img%2Ebrand%2Dlogo%20%7B%0Aheight%3A%2080px%3B%0A%7D%0Afooter%20%7B%0Abackground%3A%20%23042742%3B%0A%7D%0A" rel="stylesheet">
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; background-color: #f8f8f8; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
pre, code { background-color: #f8f8f8; }
code > span.kw { color: #204a87; font-weight: bold; } /* Keyword */
code > span.dt { color: #204a87; } /* DataType */
code > span.dv { color: #0000cf; } /* DecVal */
code > span.bn { color: #0000cf; } /* BaseN */
code > span.fl { color: #0000cf; } /* Float */
code > span.ch { color: #4e9a06; } /* Char */
code > span.st { color: #4e9a06; } /* String */
code > span.co { color: #8f5902; font-style: italic; } /* Comment */
code > span.ot { color: #8f5902; } /* Other */
code > span.al { color: #ef2929; } /* Alert */
code > span.fu { color: #000000; } /* Function */
code > span.er { color: #a40000; font-weight: bold; } /* Error */
code > span.wa { color: #8f5902; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #000000; } /* Constant */
code > span.sc { color: #000000; } /* SpecialChar */
code > span.vs { color: #4e9a06; } /* VerbatimString */
code > span.ss { color: #4e9a06; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #000000; } /* Variable */
code > span.cf { color: #204a87; font-weight: bold; } /* ControlFlow */
code > span.op { color: #ce5c00; font-weight: bold; } /* Operator */
code > span.pp { color: #8f5902; font-style: italic; } /* Preprocessor */
code > span.ex { } /* Extension */
code > span.at { color: #c4a000; } /* Attribute */
code > span.do { color: #8f5902; font-weight: bold; font-style: italic; } /* Documentation */
code > span.an { color: #8f5902; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #8f5902; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #8f5902; font-weight: bold; font-style: italic; } /* Information */
</style>
<script src="data:application/x-javascript;base64,KGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT0iZnVuY3Rpb24iJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKCJDYW5ub3QgZmluZCBtb2R1bGUgJyIrbysiJyIpO3Rocm93IGYuY29kZT0iTU9EVUxFX05PVF9GT1VORCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT0iZnVuY3Rpb24iJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSh7MTpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7Ci8qIQogKiBqUXVlcnkgSmF2YVNjcmlwdCBMaWJyYXJ5IHYyLjEuMQogKiBodHRwOi8vanF1ZXJ5LmNvbS8KICoKICogSW5jbHVkZXMgU2l6emxlLmpzCiAqIGh0dHA6Ly9zaXp6bGVqcy5jb20vCiAqCiAqIENvcHlyaWdodCAyMDA1LCAyMDE0IGpRdWVyeSBGb3VuZGF0aW9uLCBJbmMuIGFuZCBvdGhlciBjb250cmlidXRvcnMKICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlCiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2UKICoKICogRGF0ZTogMjAxNC0wNS0wMVQxNzoxMVoKICovCgooZnVuY3Rpb24oIGdsb2JhbCwgZmFjdG9yeSApIHsKCglpZiAoIHR5cGVvZiBtb2R1bGUgPT09ICJvYmplY3QiICYmIHR5cGVvZiBtb2R1bGUuZXhwb3J0cyA9PT0gIm9iamVjdCIgKSB7CgkJLy8gRm9yIENvbW1vbkpTIGFuZCBDb21tb25KUy1saWtlIGVudmlyb25tZW50cyB3aGVyZSBhIHByb3BlciB3aW5kb3cgaXMgcHJlc2VudCwKCQkvLyBleGVjdXRlIHRoZSBmYWN0b3J5IGFuZCBnZXQgalF1ZXJ5CgkJLy8gRm9yIGVudmlyb25tZW50cyB0aGF0IGRvIG5vdCBpbmhlcmVudGx5IHBvc3NlcyBhIHdpbmRvdyB3aXRoIGEgZG9jdW1lbnQKCQkvLyAoc3VjaCBhcyBOb2RlLmpzKSwgZXhwb3NlIGEgalF1ZXJ5LW1ha2luZyBmYWN0b3J5IGFzIG1vZHVsZS5leHBvcnRzCgkJLy8gVGhpcyBhY2NlbnR1YXRlcyB0aGUgbmVlZCBmb3IgdGhlIGNyZWF0aW9uIG9mIGEgcmVhbCB3aW5kb3cKCQkvLyBlLmcuIHZhciBqUXVlcnkgPSByZXF1aXJlKCJqcXVlcnkiKSh3aW5kb3cpOwoJCS8vIFNlZSB0aWNrZXQgIzE0NTQ5IGZvciBtb3JlIGluZm8KCQltb2R1bGUuZXhwb3J0cyA9IGdsb2JhbC5kb2N1bWVudCA/CgkJCWZhY3RvcnkoIGdsb2JhbCwgdHJ1ZSApIDoKCQkJZnVuY3Rpb24oIHcgKSB7CgkJCQlpZiAoICF3LmRvY3VtZW50ICkgewoJCQkJCXRocm93IG5ldyBFcnJvciggImpRdWVyeSByZXF1aXJlcyBhIHdpbmRvdyB3aXRoIGEgZG9jdW1lbnQiICk7CgkJCQl9CgkJCQlyZXR1cm4gZmFjdG9yeSggdyApOwoJCQl9OwoJfSBlbHNlIHsKCQlmYWN0b3J5KCBnbG9iYWwgKTsKCX0KCi8vIFBhc3MgdGhpcyBpZiB3aW5kb3cgaXMgbm90IGRlZmluZWQgeWV0Cn0odHlwZW9mIHdpbmRvdyAhPT0gInVuZGVmaW5lZCIgPyB3aW5kb3cgOiB0aGlzLCBmdW5jdGlvbiggd2luZG93LCBub0dsb2JhbCApIHsKCi8vIENhbid0IGRvIHRoaXMgYmVjYXVzZSBzZXZlcmFsIGFwcHMgaW5jbHVkaW5nIEFTUC5ORVQgdHJhY2UKLy8gdGhlIHN0YWNrIHZpYSBhcmd1bWVudHMuY2FsbGVyLmNhbGxlZSBhbmQgRmlyZWZveCBkaWVzIGlmCi8vIHlvdSB0cnkgdG8gdHJhY2UgdGhyb3VnaCAidXNlIHN0cmljdCIgY2FsbCBjaGFpbnMuICgjMTMzMzUpCi8vIFN1cHBvcnQ6IEZpcmVmb3ggMTgrCi8vCgp2YXIgYXJyID0gW107Cgp2YXIgc2xpY2UgPSBhcnIuc2xpY2U7Cgp2YXIgY29uY2F0ID0gYXJyLmNvbmNhdDsKCnZhciBwdXNoID0gYXJyLnB1c2g7Cgp2YXIgaW5kZXhPZiA9IGFyci5pbmRleE9mOwoKdmFyIGNsYXNzMnR5cGUgPSB7fTsKCnZhciB0b1N0cmluZyA9IGNsYXNzMnR5cGUudG9TdHJpbmc7Cgp2YXIgaGFzT3duID0gY2xhc3MydHlwZS5oYXNPd25Qcm9wZXJ0eTsKCnZhciBzdXBwb3J0ID0ge307CgoKCnZhcgoJLy8gVXNlIHRoZSBjb3JyZWN0IGRvY3VtZW50IGFjY29yZGluZ2x5IHdpdGggd2luZG93IGFyZ3VtZW50IChzYW5kYm94KQoJZG9jdW1lbnQgPSB3aW5kb3cuZG9jdW1lbnQsCgoJdmVyc2lvbiA9ICIyLjEuMSIsCgoJLy8gRGVmaW5lIGEgbG9jYWwgY29weSBvZiBqUXVlcnkKCWpRdWVyeSA9IGZ1bmN0aW9uKCBzZWxlY3RvciwgY29udGV4dCApIHsKCQkvLyBUaGUgalF1ZXJ5IG9iamVjdCBpcyBhY3R1YWxseSBqdXN0IHRoZSBpbml0IGNvbnN0cnVjdG9yICdlbmhhbmNlZCcKCQkvLyBOZWVkIGluaXQgaWYgalF1ZXJ5IGlzIGNhbGxlZCAoanVzdCBhbGxvdyBlcnJvciB0byBiZSB0aHJvd24gaWYgbm90IGluY2x1ZGVkKQoJCXJldHVybiBuZXcgalF1ZXJ5LmZuLmluaXQoIHNlbGVjdG9yLCBjb250ZXh0ICk7Cgl9LAoKCS8vIFN1cHBvcnQ6IEFuZHJvaWQ8NC4xCgkvLyBNYWtlIHN1cmUgd2UgdHJpbSBCT00gYW5kIE5CU1AKCXJ0cmltID0gL15bXHNcdUZFRkZceEEwXSt8W1xzXHVGRUZGXHhBMF0rJC9nLAoKCS8vIE1hdGNoZXMgZGFzaGVkIHN0cmluZyBmb3IgY2FtZWxpemluZwoJcm1zUHJlZml4ID0gL14tbXMtLywKCXJkYXNoQWxwaGEgPSAvLShbXGRhLXpdKS9naSwKCgkvLyBVc2VkIGJ5IGpRdWVyeS5jYW1lbENhc2UgYXMgY2FsbGJhY2sgdG8gcmVwbGFjZSgpCglmY2FtZWxDYXNlID0gZnVuY3Rpb24oIGFsbCwgbGV0dGVyICkgewoJCXJldHVybiBsZXR0ZXIudG9VcHBlckNhc2UoKTsKCX07CgpqUXVlcnkuZm4gPSBqUXVlcnkucHJvdG90eXBlID0gewoJLy8gVGhlIGN1cnJlbnQgdmVyc2lvbiBvZiBqUXVlcnkgYmVpbmcgdXNlZAoJanF1ZXJ5OiB2ZXJzaW9uLAoKCWNvbnN0cnVjdG9yOiBqUXVlcnksCgoJLy8gU3RhcnQgd2l0aCBhbiBlbXB0eSBzZWxlY3RvcgoJc2VsZWN0b3I6ICIiLAoKCS8vIFRoZSBkZWZhdWx0IGxlbmd0aCBvZiBhIGpRdWVyeSBvYmplY3QgaXMgMAoJbGVuZ3RoOiAwLAoKCXRvQXJyYXk6IGZ1bmN0aW9uKCkgewoJCXJldHVybiBzbGljZS5jYWxsKCB0aGlzICk7Cgl9LAoKCS8vIEdldCB0aGUgTnRoIGVsZW1lbnQgaW4gdGhlIG1hdGNoZWQgZWxlbWVudCBzZXQgT1IKCS8vIEdldCB0aGUgd2hvbGUgbWF0Y2hlZCBlbGVtZW50IHNldCBhcyBhIGNsZWFuIGFycmF5CglnZXQ6IGZ1bmN0aW9uKCBudW0gKSB7CgkJcmV0dXJuIG51bSAhPSBudWxsID8KCgkJCS8vIFJldHVybiBqdXN0IHRoZSBvbmUgZWxlbWVudCBmcm9tIHRoZSBzZXQKCQkJKCBudW0gPCAwID8gdGhpc1sgbnVtICsgdGhpcy5sZW5ndGggXSA6IHRoaXNbIG51bSBdICkgOgoKCQkJLy8gUmV0dXJuIGFsbCB0aGUgZWxlbWVudHMgaW4gYSBjbGVhbiBhcnJheQoJCQlzbGljZS5jYWxsKCB0aGlzICk7Cgl9LAoKCS8vIFRha2UgYW4gYXJyYXkgb2YgZWxlbWVudHMgYW5kIHB1c2ggaXQgb250byB0aGUgc3RhY2sKCS8vIChyZXR1cm5pbmcgdGhlIG5ldyBtYXRjaGVkIGVsZW1lbnQgc2V0KQoJcHVzaFN0YWNrOiBmdW5jdGlvbiggZWxlbXMgKSB7CgoJCS8vIEJ1aWxkIGEgbmV3IGpRdWVyeSBtYXRjaGVkIGVsZW1lbnQgc2V0CgkJdmFyIHJldCA9IGpRdWVyeS5tZXJnZSggdGhpcy5jb25zdHJ1Y3RvcigpLCBlbGVtcyApOwoKCQkvLyBBZGQgdGhlIG9sZCBvYmplY3Qgb250byB0aGUgc3RhY2sgKGFzIGEgcmVmZXJlbmNlKQoJCXJldC5wcmV2T2JqZWN0ID0gdGhpczsKCQlyZXQuY29udGV4dCA9IHRoaXMuY29udGV4dDsKCgkJLy8gUmV0dXJuIHRoZSBuZXdseS1mb3JtZWQgZWxlbWVudCBzZXQKCQlyZXR1cm4gcmV0OwoJfSwKCgkvLyBFeGVjdXRlIGEgY2FsbGJhY2sgZm9yIGV2ZXJ5IGVsZW1lbnQgaW4gdGhlIG1hdGNoZWQgc2V0LgoJLy8gKFlvdSBjYW4gc2VlZCB0aGUgYXJndW1lbnRzIHdpdGggYW4gYXJyYXkgb2YgYXJncywgYnV0IHRoaXMgaXMKCS8vIG9ubHkgdXNlZCBpbnRlcm5hbGx5LikKCWVhY2g6IGZ1bmN0aW9uKCBjYWxsYmFjaywgYXJncyApIHsKCQlyZXR1cm4galF1ZXJ5LmVhY2goIHRoaXMsIGNhbGxiYWNrLCBhcmdzICk7Cgl9LAoKCW1hcDogZnVuY3Rpb24oIGNhbGxiYWNrICkgewoJCXJldHVybiB0aGlzLnB1c2hTdGFjayggalF1ZXJ5Lm1hcCh0aGlzLCBmdW5jdGlvbiggZWxlbSwgaSApIHsKCQkJcmV0dXJuIGNhbGxiYWNrLmNhbGwoIGVsZW0sIGksIGVsZW0gKTsKCQl9KSk7Cgl9LAoKCXNsaWNlOiBmdW5jdGlvbigpIHsKCQlyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHNsaWNlLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSApOwoJfSwKCglmaXJzdDogZnVuY3Rpb24oKSB7CgkJcmV0dXJuIHRoaXMuZXEoIDAgKTsKCX0sCgoJbGFzdDogZnVuY3Rpb24oKSB7CgkJcmV0dXJuIHRoaXMuZXEoIC0xICk7Cgl9LAoKCWVxOiBmdW5jdGlvbiggaSApIHsKCQl2YXIgbGVuID0gdGhpcy5sZW5ndGgsCgkJCWogPSAraSArICggaSA8IDAgPyBsZW4gOiAwICk7CgkJcmV0dXJuIHRoaXMucHVzaFN0YWNrKCBqID49IDAgJiYgaiA8IGxlbiA/IFsgdGhpc1tqXSBdIDogW10gKTsKCX0sCgoJZW5kOiBmdW5jdGlvbigpIHsKCQlyZXR1cm4gdGhpcy5wcmV2T2JqZWN0IHx8IHRoaXMuY29uc3RydWN0b3IobnVsbCk7Cgl9LAoKCS8vIEZvciBpbnRlcm5hbCB1c2Ugb25seS4KCS8vIEJlaGF2ZXMgbGlrZSBhbiBBcnJheSdzIG1ldGhvZCwgbm90IGxpa2UgYSBqUXVlcnkgbWV0aG9kLgoJcHVzaDogcHVzaCwKCXNvcnQ6IGFyci5zb3J0LAoJc3BsaWNlOiBhcnIuc3BsaWNlCn07CgpqUXVlcnkuZXh0ZW5kID0galF1ZXJ5LmZuLmV4dGVuZCA9IGZ1bmN0aW9uKCkgewoJdmFyIG9wdGlvbnMsIG5hbWUsIHNyYywgY29weSwgY29weUlzQXJyYXksIGNsb25lLAoJCXRhcmdldCA9IGFyZ3VtZW50c1swXSB8fCB7fSwKCQlpID0gMSwKCQlsZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoLAoJCWRlZXAgPSBmYWxzZTsKCgkvLyBIYW5kbGUgYSBkZWVwIGNvcHkgc2l0dWF0aW9uCglpZiAoIHR5cGVvZiB0YXJnZXQgPT09ICJib29sZWFuIiApIHsKCQlkZWVwID0gdGFyZ2V0OwoKCQkvLyBza2lwIHRoZSBib29sZWFuIGFuZCB0aGUgdGFyZ2V0CgkJdGFyZ2V0ID0gYXJndW1lbnRzWyBpIF0gfHwge307CgkJaSsrOwoJfQoKCS8vIEhhbmRsZSBjYXNlIHdoZW4gdGFyZ2V0IGlzIGEgc3RyaW5nIG9yIHNvbWV0aGluZyAocG9zc2libGUgaW4gZGVlcCBjb3B5KQoJaWYgKCB0eXBlb2YgdGFyZ2V0ICE9PSAib2JqZWN0IiAmJiAhalF1ZXJ5LmlzRnVuY3Rpb24odGFyZ2V0KSApIHsKCQl0YXJnZXQgPSB7fTsKCX0KCgkvLyBleHRlbmQgalF1ZXJ5IGl0c2VsZiBpZiBvbmx5IG9uZSBhcmd1bWVudCBpcyBwYXNzZWQKCWlmICggaSA9PT0gbGVuZ3RoICkgewoJCXRhcmdldCA9IHRoaXM7CgkJaS0tOwoJfQoKCWZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkgewoJCS8vIE9ubHkgZGVhbCB3aXRoIG5vbi1udWxsL3VuZGVmaW5lZCB2YWx1ZXMKCQlpZiAoIChvcHRpb25zID0gYXJndW1lbnRzWyBpIF0pICE9IG51bGwgKSB7CgkJCS8vIEV4dGVuZCB0aGUgYmFzZSBvYmplY3QKCQkJZm9yICggbmFtZSBpbiBvcHRpb25zICkgewoJCQkJc3JjID0gdGFyZ2V0WyBuYW1lIF07CgkJCQljb3B5ID0gb3B0aW9uc1sgbmFtZSBdOwoKCQkJCS8vIFByZXZlbnQgbmV2ZXItZW5kaW5nIGxvb3AKCQkJCWlmICggdGFyZ2V0ID09PSBjb3B5ICkgewoJCQkJCWNvbnRpbnVlOwoJCQkJfQoKCQkJCS8vIFJlY3Vyc2UgaWYgd2UncmUgbWVyZ2luZyBwbGFpbiBvYmplY3RzIG9yIGFycmF5cwoJCQkJaWYgKCBkZWVwICYmIGNvcHkgJiYgKCBqUXVlcnkuaXNQbGFpbk9iamVjdChjb3B5KSB8fCAoY29weUlzQXJyYXkgPSBqUXVlcnkuaXNBcnJheShjb3B5KSkgKSApIHsKCQkJCQlpZiAoIGNvcHlJc0FycmF5ICkgewoJCQkJCQljb3B5SXNBcnJheSA9IGZhbHNlOwoJCQkJCQljbG9uZSA9IHNyYyAmJiBqUXVlcnkuaXNBcnJheShzcmMpID8gc3JjIDogW107CgoJCQkJCX0gZWxzZSB7CgkJCQkJCWNsb25lID0gc3JjICYmIGpRdWVyeS5pc1BsYWluT2JqZWN0KHNyYykgPyBzcmMgOiB7fTsKCQkJCQl9CgoJCQkJCS8vIE5ldmVyIG1vdmUgb3JpZ2luYWwgb2JqZWN0cywgY2xvbmUgdGhlbQoJCQkJCXRhcmdldFsgbmFtZSBdID0galF1ZXJ5LmV4dGVuZCggZGVlcCwgY2xvbmUsIGNvcHkgKTsKCgkJCQkvLyBEb24ndCBicmluZyBpbiB1bmRlZmluZWQgdmFsdWVzCgkJCQl9IGVsc2UgaWYgKCBjb3B5ICE9PSB1bmRlZmluZWQgKSB7CgkJCQkJdGFyZ2V0WyBuYW1lIF0gPSBjb3B5OwoJCQkJfQoJCQl9CgkJfQoJfQoKCS8vIFJldHVybiB0aGUgbW9kaWZpZWQgb2JqZWN0CglyZXR1cm4gdGFyZ2V0Owp9OwoKalF1ZXJ5LmV4dGVuZCh7CgkvLyBVbmlxdWUgZm9yIGVhY2ggY29weSBvZiBqUXVlcnkgb24gdGhlIHBhZ2UKCWV4cGFuZG86ICJqUXVlcnkiICsgKCB2ZXJzaW9uICsgTWF0aC5yYW5kb20oKSApLnJlcGxhY2UoIC9cRC9nLCAiIiApLAoKCS8vIEFzc3VtZSBqUXVlcnkgaXMgcmVhZHkgd2l0aG91dCB0aGUgcmVhZHkgbW9kdWxlCglpc1JlYWR5OiB0cnVlLAoKCWVycm9yOiBmdW5jdGlvbiggbXNnICkgewoJCXRocm93IG5ldyBFcnJvciggbXNnICk7Cgl9LAoKCW5vb3A6IGZ1bmN0aW9uKCkge30sCgoJLy8gU2VlIHRlc3QvdW5pdC9jb3JlLmpzIGZvciBkZXRhaWxzIGNvbmNlcm5pbmcgaXNGdW5jdGlvbi4KCS8vIFNpbmNlIHZlcnNpb24gMS4zLCBET00gbWV0aG9kcyBhbmQgZnVuY3Rpb25zIGxpa2UgYWxlcnQKCS8vIGFyZW4ndCBzdXBwb3J0ZWQuIFRoZXkgcmV0dXJuIGZhbHNlIG9uIElFICgjMjk2OCkuCglpc0Z1bmN0aW9uOiBmdW5jdGlvbiggb2JqICkgewoJCXJldHVybiBqUXVlcnkudHlwZShvYmopID09PSAiZnVuY3Rpb24iOwoJfSwKCglpc0FycmF5OiBBcnJheS5pc0FycmF5LAoKCWlzV2luZG93OiBmdW5jdGlvbiggb2JqICkgewoJCXJldHVybiBvYmogIT0gbnVsbCAmJiBvYmogPT09IG9iai53aW5kb3c7Cgl9LAoKCWlzTnVtZXJpYzogZnVuY3Rpb24oIG9iaiApIHsKCQkvLyBwYXJzZUZsb2F0IE5hTnMgbnVtZXJpYy1jYXN0IGZhbHNlIHBvc2l0aXZlcyAobnVsbHx0cnVlfGZhbHNlfCIiKQoJCS8vIC4uLmJ1dCBtaXNpbnRlcnByZXRzIGxlYWRpbmctbnVtYmVyIHN0cmluZ3MsIHBhcnRpY3VsYXJseSBoZXggbGl0ZXJhbHMgKCIweC4uLiIpCgkJLy8gc3VidHJhY3Rpb24gZm9yY2VzIGluZmluaXRpZXMgdG8gTmFOCgkJcmV0dXJuICFqUXVlcnkuaXNBcnJheSggb2JqICkgJiYgb2JqIC0gcGFyc2VGbG9hdCggb2JqICkgPj0gMDsKCX0sCgoJaXNQbGFpbk9iamVjdDogZnVuY3Rpb24oIG9iaiApIHsKCQkvLyBOb3QgcGxhaW4gb2JqZWN0czoKCQkvLyAtIEFueSBvYmplY3Qgb3IgdmFsdWUgd2hvc2UgaW50ZXJuYWwgW1tDbGFzc11dIHByb3BlcnR5IGlzIG5vdCAiW29iamVjdCBPYmplY3RdIgoJCS8vIC0gRE9NIG5vZGVzCgkJLy8gLSB3aW5kb3cKCQlpZiAoIGpRdWVyeS50eXBlKCBvYmogKSAhPT0gIm9iamVjdCIgfHwgb2JqLm5vZGVUeXBlIHx8IGpRdWVyeS5pc1dpbmRvdyggb2JqICkgKSB7CgkJCXJldHVybiBmYWxzZTsKCQl9CgoJCWlmICggb2JqLmNvbnN0cnVjdG9yICYmCgkJCQkhaGFzT3duLmNhbGwoIG9iai5jb25zdHJ1Y3Rvci5wcm90b3R5cGUsICJpc1Byb3RvdHlwZU9mIiApICkgewoJCQlyZXR1cm4gZmFsc2U7CgkJfQoKCQkvLyBJZiB0aGUgZnVuY3Rpb24gaGFzbid0IHJldHVybmVkIGFscmVhZHksIHdlJ3JlIGNvbmZpZGVudCB0aGF0CgkJLy8gfG9ianwgaXMgYSBwbGFpbiBvYmplY3QsIGNyZWF0ZWQgYnkge30gb3IgY29uc3RydWN0ZWQgd2l0aCBuZXcgT2JqZWN0CgkJcmV0dXJuIHRydWU7Cgl9LAoKCWlzRW1wdHlPYmplY3Q6IGZ1bmN0aW9uKCBvYmogKSB7CgkJdmFyIG5hbWU7CgkJZm9yICggbmFtZSBpbiBvYmogKSB7CgkJCXJldHVybiBmYWxzZTsKCQl9CgkJcmV0dXJuIHRydWU7Cgl9LAoKCXR5cGU6IGZ1bmN0aW9uKCBvYmogKSB7CgkJaWYgKCBvYmogPT0gbnVsbCApIHsKCQkJcmV0dXJuIG9iaiArICIiOwoJCX0KCQkvLyBTdXBwb3J0OiBBbmRyb2lkIDwgNC4wLCBpT1MgPCA2IChmdW5jdGlvbmlzaCBSZWdFeHApCgkJcmV0dXJuIHR5cGVvZiBvYmogPT09ICJvYmplY3QiIHx8IHR5cGVvZiBvYmogPT09ICJmdW5jdGlvbiIgPwoJCQljbGFzczJ0eXBlWyB0b1N0cmluZy5jYWxsKG9iaikgXSB8fCAib2JqZWN0IiA6CgkJCXR5cGVvZiBvYmo7Cgl9LAoKCS8vIEV2YWx1YXRlcyBhIHNjcmlwdCBpbiBhIGdsb2JhbCBjb250ZXh0CglnbG9iYWxFdmFsOiBmdW5jdGlvbiggY29kZSApIHsKCQl2YXIgc2NyaXB0LAoJCQlpbmRpcmVjdCA9IGV2YWw7CgoJCWNvZGUgPSBqUXVlcnkudHJpbSggY29kZSApOwoKCQlpZiAoIGNvZGUgKSB7CgkJCS8vIElmIHRoZSBjb2RlIGluY2x1ZGVzIGEgdmFsaWQsIHByb2xvZ3VlIHBvc2l0aW9uCgkJCS8vIHN0cmljdCBtb2RlIHByYWdtYSwgZXhlY3V0ZSBjb2RlIGJ5IGluamVjdGluZyBhCgkJCS8vIHNjcmlwdCB0YWcgaW50byB0aGUgZG9jdW1lbnQuCgkJCWlmICggY29kZS5pbmRleE9mKCJ1c2Ugc3RyaWN0IikgPT09IDEgKSB7CgkJCQlzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKTsKCQkJCXNjcmlwdC50ZXh0ID0gY29kZTsKCQkJCWRvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQoIHNjcmlwdCApLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIHNjcmlwdCApOwoJCQl9IGVsc2UgewoJCQkvLyBPdGhlcndpc2UsIGF2b2lkIHRoZSBET00gbm9kZSBjcmVhdGlvbiwgaW5zZXJ0aW9uCgkJCS8vIGFuZCByZW1vdmFsIGJ5IHVzaW5nIGFuIGluZGlyZWN0IGdsb2JhbCBldmFsCgkJCQlpbmRpcmVjdCggY29kZSApOwoJCQl9CgkJfQoJfSwKCgkvLyBDb252ZXJ0IGRhc2hlZCB0byBjYW1lbENhc2U7IHVzZWQgYnkgdGhlIGNzcyBhbmQgZGF0YSBtb2R1bGVzCgkvLyBNaWNyb3NvZnQgZm9yZ290IHRvIGh1bXAgdGhlaXIgdmVuZG9yIHByZWZpeCAoIzk1NzIpCgljYW1lbENhc2U6IGZ1bmN0aW9uKCBzdHJpbmcgKSB7CgkJcmV0dXJuIHN0cmluZy5yZXBsYWNlKCBybXNQcmVmaXgsICJtcy0iICkucmVwbGFjZSggcmRhc2hBbHBoYSwgZmNhbWVsQ2FzZSApOwoJfSwKCglub2RlTmFtZTogZnVuY3Rpb24oIGVsZW0sIG5hbWUgKSB7CgkJcmV0dXJuIGVsZW0ubm9kZU5hbWUgJiYgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBuYW1lLnRvTG93ZXJDYXNlKCk7Cgl9LAoKCS8vIGFyZ3MgaXMgZm9yIGludGVybmFsIHVzYWdlIG9ubHkKCWVhY2g6IGZ1bmN0aW9uKCBvYmosIGNhbGxiYWNrLCBhcmdzICkgewoJCXZhciB2YWx1ZSwKCQkJaSA9IDAsCgkJCWxlbmd0aCA9IG9iai5sZW5ndGgsCgkJCWlzQXJyYXkgPSBpc0FycmF5bGlrZSggb2JqICk7CgoJCWlmICggYXJncyApIHsKCQkJaWYgKCBpc0FycmF5ICkgewoJCQkJZm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7CgkJCQkJdmFsdWUgPSBjYWxsYmFjay5hcHBseSggb2JqWyBpIF0sIGFyZ3MgKTsKCgkJCQkJaWYgKCB2YWx1ZSA9PT0gZmFsc2UgKSB7CgkJCQkJCWJyZWFrOwoJCQkJCX0KCQkJCX0KCQkJfSBlbHNlIHsKCQkJCWZvciAoIGkgaW4gb2JqICkgewoJCQkJCXZhbHVlID0gY2FsbGJhY2suYXBwbHkoIG9ialsgaSBdLCBhcmdzICk7CgoJCQkJCWlmICggdmFsdWUgPT09IGZhbHNlICkgewoJCQkJCQlicmVhazsKCQkJCQl9CgkJCQl9CgkJCX0KCgkJLy8gQSBzcGVjaWFsLCBmYXN0LCBjYXNlIGZvciB0aGUgbW9zdCBjb21tb24gdXNlIG9mIGVhY2gKCQl9IGVsc2UgewoJCQlpZiAoIGlzQXJyYXkgKSB7CgkJCQlmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHsKCQkJCQl2YWx1ZSA9IGNhbGxiYWNrLmNhbGwoIG9ialsgaSBdLCBpLCBvYmpbIGkgXSApOwoKCQkJCQlpZiAoIHZhbHVlID09PSBmYWxzZSApIHsKCQkJCQkJYnJlYWs7CgkJCQkJfQoJCQkJfQoJCQl9IGVsc2UgewoJCQkJZm9yICggaSBpbiBvYmogKSB7CgkJCQkJdmFsdWUgPSBjYWxsYmFjay5jYWxsKCBvYmpbIGkgXSwgaSwgb2JqWyBpIF0gKTsKCgkJCQkJaWYgKCB2YWx1ZSA9PT0gZmFsc2UgKSB7CgkJCQkJCWJyZWFrOwoJCQkJCX0KCQkJCX0KCQkJfQoJCX0KCgkJcmV0dXJuIG9iajsKCX0sCgoJLy8gU3VwcG9ydDogQW5kcm9pZDw0LjEKCXRyaW06IGZ1bmN0aW9uKCB0ZXh0ICkgewoJCXJldHVybiB0ZXh0ID09IG51bGwgPwoJCQkiIiA6CgkJCSggdGV4dCArICIiICkucmVwbGFjZSggcnRyaW0sICIiICk7Cgl9LAoKCS8vIHJlc3VsdHMgaXMgZm9yIGludGVybmFsIHVzYWdlIG9ubHkKCW1ha2VBcnJheTogZnVuY3Rpb24oIGFyciwgcmVzdWx0cyApIHsKCQl2YXIgcmV0ID0gcmVzdWx0cyB8fCBbXTsKCgkJaWYgKCBhcnIgIT0gbnVsbCApIHsKCQkJaWYgKCBpc0FycmF5bGlrZSggT2JqZWN0KGFycikgKSApIHsKCQkJCWpRdWVyeS5tZXJnZSggcmV0LAoJCQkJCXR5cGVvZiBhcnIgPT09ICJzdHJpbmciID8KCQkJCQlbIGFyciBdIDogYXJyCgkJCQkpOwoJCQl9IGVsc2UgewoJCQkJcHVzaC5jYWxsKCByZXQsIGFyciApOwoJCQl9CgkJfQoKCQlyZXR1cm4gcmV0OwoJfSwKCglpbkFycmF5OiBmdW5jdGlvbiggZWxlbSwgYXJyLCBpICkgewoJCXJldHVybiBhcnIgPT0gbnVsbCA/IC0xIDogaW5kZXhPZi5jYWxsKCBhcnIsIGVsZW0sIGkgKTsKCX0sCgoJbWVyZ2U6IGZ1bmN0aW9uKCBmaXJzdCwgc2Vjb25kICkgewoJCXZhciBsZW4gPSArc2Vjb25kLmxlbmd0aCwKCQkJaiA9IDAsCgkJCWkgPSBmaXJzdC5sZW5ndGg7CgoJCWZvciAoIDsgaiA8IGxlbjsgaisrICkgewoJCQlmaXJzdFsgaSsrIF0gPSBzZWNvbmRbIGogXTsKCQl9CgoJCWZpcnN0Lmxlbmd0aCA9IGk7CgoJCXJldHVybiBmaXJzdDsKCX0sCgoJZ3JlcDogZnVuY3Rpb24oIGVsZW1zLCBjYWxsYmFjaywgaW52ZXJ0ICkgewoJCXZhciBjYWxsYmFja0ludmVyc2UsCgkJCW1hdGNoZXMgPSBbXSwKCQkJaSA9IDAsCgkJCWxlbmd0aCA9IGVsZW1zLmxlbmd0aCwKCQkJY2FsbGJhY2tFeHBlY3QgPSAhaW52ZXJ0OwoKCQkvLyBHbyB0aHJvdWdoIHRoZSBhcnJheSwgb25seSBzYXZpbmcgdGhlIGl0ZW1zCgkJLy8gdGhhdCBwYXNzIHRoZSB2YWxpZGF0b3IgZnVuY3Rpb24KCQlmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHsKCQkJY2FsbGJhY2tJbnZlcnNlID0gIWNhbGxiYWNrKCBlbGVtc1sgaSBdLCBpICk7CgkJCWlmICggY2FsbGJhY2tJbnZlcnNlICE9PSBjYWxsYmFja0V4cGVjdCApIHsKCQkJCW1hdGNoZXMucHVzaCggZWxlbXNbIGkgXSApOwoJCQl9CgkJfQoKCQlyZXR1cm4gbWF0Y2hlczsKCX0sCgoJLy8gYXJnIGlzIGZvciBpbnRlcm5hbCB1c2FnZSBvbmx5CgltYXA6IGZ1bmN0aW9uKCBlbGVtcywgY2FsbGJhY2ssIGFyZyApIHsKCQl2YXIgdmFsdWUsCgkJCWkgPSAwLAoJCQlsZW5ndGggPSBlbGVtcy5sZW5ndGgsCgkJCWlzQXJyYXkgPSBpc0FycmF5bGlrZSggZWxlbXMgKSwKCQkJcmV0ID0gW107CgoJCS8vIEdvIHRocm91Z2ggdGhlIGFycmF5LCB0cmFuc2xhdGluZyBlYWNoIG9mIHRoZSBpdGVtcyB0byB0aGVpciBuZXcgdmFsdWVzCgkJaWYgKCBpc0FycmF5ICkgewoJCQlmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHsKCQkJCXZhbHVlID0gY2FsbGJhY2soIGVsZW1zWyBpIF0sIGksIGFyZyApOwoKCQkJCWlmICggdmFsdWUgIT0gbnVsbCApIHsKCQkJCQlyZXQucHVzaCggdmFsdWUgKTsKCQkJCX0KCQkJfQoKCQkvLyBHbyB0aHJvdWdoIGV2ZXJ5IGtleSBvbiB0aGUgb2JqZWN0LAoJCX0gZWxzZSB7CgkJCWZvciAoIGkgaW4gZWxlbXMgKSB7CgkJCQl2YWx1ZSA9IGNhbGxiYWNrKCBlbGVtc1sgaSBdLCBpLCBhcmcgKTsKCgkJCQlpZiAoIHZhbHVlICE9IG51bGwgKSB7CgkJCQkJcmV0LnB1c2goIHZhbHVlICk7CgkJCQl9CgkJCX0KCQl9CgoJCS8vIEZsYXR0ZW4gYW55IG5lc3RlZCBhcnJheXMKCQlyZXR1cm4gY29uY2F0LmFwcGx5KCBbXSwgcmV0ICk7Cgl9LAoKCS8vIEEgZ2xvYmFsIEdVSUQgY291bnRlciBmb3Igb2JqZWN0cwoJZ3VpZDogMSwKCgkvLyBCaW5kIGEgZnVuY3Rpb24gdG8gYSBjb250ZXh0LCBvcHRpb25hbGx5IHBhcnRpYWxseSBhcHBseWluZyBhbnkKCS8vIGFyZ3VtZW50cy4KCXByb3h5OiBmdW5jdGlvbiggZm4sIGNvbnRleHQgKSB7CgkJdmFyIHRtcCwgYXJncywgcHJveHk7CgoJCWlmICggdHlwZW9mIGNvbnRleHQgPT09ICJzdHJpbmciICkgewoJCQl0bXAgPSBmblsgY29udGV4dCBdOwoJCQljb250ZXh0ID0gZm47CgkJCWZuID0gdG1wOwoJCX0KCgkJLy8gUXVpY2sgY2hlY2sgdG8gZGV0ZXJtaW5lIGlmIHRhcmdldCBpcyBjYWxsYWJsZSwgaW4gdGhlIHNwZWMKCQkvLyB0aGlzIHRocm93cyBhIFR5cGVFcnJvciwgYnV0IHdlIHdpbGwganVzdCByZXR1cm4gdW5kZWZpbmVkLgoJCWlmICggIWpRdWVyeS5pc0Z1bmN0aW9uKCBmbiApICkgewoJCQlyZXR1cm4gdW5kZWZpbmVkOwoJCX0KCgkJLy8gU2ltdWxhdGVkIGJpbmQKCQlhcmdzID0gc2xpY2UuY2FsbCggYXJndW1lbnRzLCAyICk7CgkJcHJveHkgPSBmdW5jdGlvbigpIHsKCQkJcmV0dXJuIGZuLmFwcGx5KCBjb250ZXh0IHx8IHRoaXMsIGFyZ3MuY29uY2F0KCBzbGljZS5jYWxsKCBhcmd1bWVudHMgKSApICk7CgkJfTsKCgkJLy8gU2V0IHRoZSBndWlkIG9mIHVuaXF1ZSBoYW5kbGVyIHRvIHRoZSBzYW1lIG9mIG9yaWdpbmFsIGhhbmRsZXIsIHNvIGl0IGNhbiBiZSByZW1vdmVkCgkJcHJveHkuZ3VpZCA9IGZuLmd1aWQgPSBmbi5ndWlkIHx8IGpRdWVyeS5ndWlkKys7CgoJCXJldHVybiBwcm94eTsKCX0sCgoJbm93OiBEYXRlLm5vdywKCgkvLyBqUXVlcnkuc3VwcG9ydCBpcyBub3QgdXNlZCBpbiBDb3JlIGJ1dCBvdGhlciBwcm9qZWN0cyBhdHRhY2ggdGhlaXIKCS8vIHByb3BlcnRpZXMgdG8gaXQgc28gaXQgbmVlZHMgdG8gZXhpc3QuCglzdXBwb3J0OiBzdXBwb3J0Cn0pOwoKLy8gUG9wdWxhdGUgdGhlIGNsYXNzMnR5cGUgbWFwCmpRdWVyeS5lYWNoKCJCb29sZWFuIE51bWJlciBTdHJpbmcgRnVuY3Rpb24gQXJyYXkgRGF0ZSBSZWdFeHAgT2JqZWN0IEVycm9yIi5zcGxpdCgiICIpLCBmdW5jdGlvbihpLCBuYW1lKSB7CgljbGFzczJ0eXBlWyAiW29iamVjdCAiICsgbmFtZSArICJdIiBdID0gbmFtZS50b0xvd2VyQ2FzZSgpOwp9KTsKCmZ1bmN0aW9uIGlzQXJyYXlsaWtlKCBvYmogKSB7Cgl2YXIgbGVuZ3RoID0gb2JqLmxlbmd0aCwKCQl0eXBlID0galF1ZXJ5LnR5cGUoIG9iaiApOwoKCWlmICggdHlwZSA9PT0gImZ1bmN0aW9uIiB8fCBqUXVlcnkuaXNXaW5kb3coIG9iaiApICkgewoJCXJldHVybiBmYWxzZTsKCX0KCglpZiAoIG9iai5ub2RlVHlwZSA9PT0gMSAmJiBsZW5ndGggKSB7CgkJcmV0dXJuIHRydWU7Cgl9CgoJcmV0dXJuIHR5cGUgPT09ICJhcnJheSIgfHwgbGVuZ3RoID09PSAwIHx8CgkJdHlwZW9mIGxlbmd0aCA9PT0gIm51bWJlciIgJiYgbGVuZ3RoID4gMCAmJiAoIGxlbmd0aCAtIDEgKSBpbiBvYmo7Cn0KdmFyIFNpenpsZSA9Ci8qIQogKiBTaXp6bGUgQ1NTIFNlbGVjdG9yIEVuZ2luZSB2MS4xMC4xOQogKiBodHRwOi8vc2l6emxlanMuY29tLwogKgogKiBDb3B5cmlnaHQgMjAxMyBqUXVlcnkgRm91bmRhdGlvbiwgSW5jLiBhbmQgb3RoZXIgY29udHJpYnV0b3JzCiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZQogKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlCiAqCiAqIERhdGU6IDIwMTQtMDQtMTgKICovCihmdW5jdGlvbiggd2luZG93ICkgewoKdmFyIGksCglzdXBwb3J0LAoJRXhwciwKCWdldFRleHQsCglpc1hNTCwKCXRva2VuaXplLAoJY29tcGlsZSwKCXNlbGVjdCwKCW91dGVybW9zdENvbnRleHQsCglzb3J0SW5wdXQsCgloYXNEdXBsaWNhdGUsCgoJLy8gTG9jYWwgZG9jdW1lbnQgdmFycwoJc2V0RG9jdW1lbnQsCglkb2N1bWVudCwKCWRvY0VsZW0sCglkb2N1bWVudElzSFRNTCwKCXJidWdneVFTQSwKCXJidWdneU1hdGNoZXMsCgltYXRjaGVzLAoJY29udGFpbnMsCgoJLy8gSW5zdGFuY2Utc3BlY2lmaWMgZGF0YQoJZXhwYW5kbyA9ICJzaXp6bGUiICsgLShuZXcgRGF0ZSgpKSwKCXByZWZlcnJlZERvYyA9IHdpbmRvdy5kb2N1bWVudCwKCWRpcnJ1bnMgPSAwLAoJZG9uZSA9IDAsCgljbGFzc0NhY2hlID0gY3JlYXRlQ2FjaGUoKSwKCXRva2VuQ2FjaGUgPSBjcmVhdGVDYWNoZSgpLAoJY29tcGlsZXJDYWNoZSA9IGNyZWF0ZUNhY2hlKCksCglzb3J0T3JkZXIgPSBmdW5jdGlvbiggYSwgYiApIHsKCQlpZiAoIGEgPT09IGIgKSB7CgkJCWhhc0R1cGxpY2F0ZSA9IHRydWU7CgkJfQoJCXJldHVybiAwOwoJfSwKCgkvLyBHZW5lcmFsLXB1cnBvc2UgY29uc3RhbnRzCglzdHJ1bmRlZmluZWQgPSB0eXBlb2YgdW5kZWZpbmVkLAoJTUFYX05FR0FUSVZFID0gMSA8PCAzMSwKCgkvLyBJbnN0YW5jZSBtZXRob2RzCgloYXNPd24gPSAoe30pLmhhc093blByb3BlcnR5LAoJYXJyID0gW10sCglwb3AgPSBhcnIucG9wLAoJcHVzaF9uYXRpdmUgPSBhcnIucHVzaCwKCXB1c2ggPSBhcnIucHVzaCwKCXNsaWNlID0gYXJyLnNsaWNlLAoJLy8gVXNlIGEgc3RyaXBwZWQtZG93biBpbmRleE9mIGlmIHdlIGNhbid0IHVzZSBhIG5hdGl2ZSBvbmUKCWluZGV4T2YgPSBhcnIuaW5kZXhPZiB8fCBmdW5jdGlvbiggZWxlbSApIHsKCQl2YXIgaSA9IDAsCgkJCWxlbiA9IHRoaXMubGVuZ3RoOwoJCWZvciAoIDsgaSA8IGxlbjsgaSsrICkgewoJCQlpZiAoIHRoaXNbaV0gPT09IGVsZW0gKSB7CgkJCQlyZXR1cm4gaTsKCQkJfQoJCX0KCQlyZXR1cm4gLTE7Cgl9LAoKCWJvb2xlYW5zID0gImNoZWNrZWR8c2VsZWN0ZWR8YXN5bmN8YXV0b2ZvY3VzfGF1dG9wbGF5fGNvbnRyb2xzfGRlZmVyfGRpc2FibGVkfGhpZGRlbnxpc21hcHxsb29wfG11bHRpcGxlfG9wZW58cmVhZG9ubHl8cmVxdWlyZWR8c2NvcGVkIiwKCgkvLyBSZWd1bGFyIGV4cHJlc3Npb25zCgoJLy8gV2hpdGVzcGFjZSBjaGFyYWN0ZXJzIGh0dHA6Ly93d3cudzMub3JnL1RSL2NzczMtc2VsZWN0b3JzLyN3aGl0ZXNwYWNlCgl3aGl0ZXNwYWNlID0gIltcXHgyMFxcdFxcclxcblxcZl0iLAoJLy8gaHR0cDovL3d3dy53My5vcmcvVFIvY3NzMy1zeW50YXgvI2NoYXJhY3RlcnMKCWNoYXJhY3RlckVuY29kaW5nID0gIig/OlxcXFwufFtcXHctXXxbXlxceDAwLVxceGEwXSkrIiwKCgkvLyBMb29zZWx5IG1vZGVsZWQgb24gQ1NTIGlkZW50aWZpZXIgY2hhcmFjdGVycwoJLy8gQW4gdW5xdW90ZWQgdmFsdWUgc2hvdWxkIGJlIGEgQ1NTIGlkZW50aWZpZXIgaHR0cDovL3d3dy53My5vcmcvVFIvY3NzMy1zZWxlY3RvcnMvI2F0dHJpYnV0ZS1zZWxlY3RvcnMKCS8vIFByb3BlciBzeW50YXg6IGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIxL3N5bmRhdGEuaHRtbCN2YWx1ZS1kZWYtaWRlbnRpZmllcgoJaWRlbnRpZmllciA9IGNoYXJhY3RlckVuY29kaW5nLnJlcGxhY2UoICJ3IiwgIncjIiApLAoKCS8vIEF0dHJpYnV0ZSBzZWxlY3RvcnM6IGh0dHA6Ly93d3cudzMub3JnL1RSL3NlbGVjdG9ycy8jYXR0cmlidXRlLXNlbGVjdG9ycwoJYXR0cmlidXRlcyA9ICJcXFsiICsgd2hpdGVzcGFjZSArICIqKCIgKyBjaGFyYWN0ZXJFbmNvZGluZyArICIpKD86IiArIHdoaXRlc3BhY2UgKwoJCS8vIE9wZXJhdG9yIChjYXB0dXJlIDIpCgkJIiooWypeJHwhfl0/PSkiICsgd2hpdGVzcGFjZSArCgkJLy8gIkF0dHJpYnV0ZSB2YWx1ZXMgbXVzdCBiZSBDU1MgaWRlbnRpZmllcnMgW2NhcHR1cmUgNV0gb3Igc3RyaW5ncyBbY2FwdHVyZSAzIG9yIGNhcHR1cmUgNF0iCgkJIiooPzonKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcInwoIiArIGlkZW50aWZpZXIgKyAiKSl8KSIgKyB3aGl0ZXNwYWNlICsKCQkiKlxcXSIsCgoJcHNldWRvcyA9ICI6KCIgKyBjaGFyYWN0ZXJFbmNvZGluZyArICIpKD86XFwoKCIgKwoJCS8vIFRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIHNlbGVjdG9ycyBuZWVkaW5nIHRva2VuaXplIGluIHRoZSBwcmVGaWx0ZXIsIHByZWZlciBhcmd1bWVudHM6CgkJLy8gMS4gcXVvdGVkIChjYXB0dXJlIDM7IGNhcHR1cmUgNCBvciBjYXB0dXJlIDUpCgkJIignKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcIil8IiArCgkJLy8gMi4gc2ltcGxlIChjYXB0dXJlIDYpCgkJIigoPzpcXFxcLnxbXlxcXFwoKVtcXF1dfCIgKyBhdHRyaWJ1dGVzICsgIikqKXwiICsKCQkvLyAzLiBhbnl0aGluZyBlbHNlIChjYXB0dXJlIDIpCgkJIi4qIiArCgkJIilcXCl8KSIsCgoJLy8gTGVhZGluZyBhbmQgbm9uLWVzY2FwZWQgdHJhaWxpbmcgd2hpdGVzcGFjZSwgY2FwdHVyaW5nIHNvbWUgbm9uLXdoaXRlc3BhY2UgY2hhcmFjdGVycyBwcmVjZWRpbmcgdGhlIGxhdHRlcgoJcnRyaW0gPSBuZXcgUmVnRXhwKCAiXiIgKyB3aGl0ZXNwYWNlICsgIit8KCg/Ol58W15cXFxcXSkoPzpcXFxcLikqKSIgKyB3aGl0ZXNwYWNlICsgIiskIiwgImciICksCgoJcmNvbW1hID0gbmV3IFJlZ0V4cCggIl4iICsgd2hpdGVzcGFjZSArICIqLCIgKyB3aGl0ZXNwYWNlICsgIioiICksCglyY29tYmluYXRvcnMgPSBuZXcgUmVnRXhwKCAiXiIgKyB3aGl0ZXNwYWNlICsgIiooWz4rfl18IiArIHdoaXRlc3BhY2UgKyAiKSIgKyB3aGl0ZXNwYWNlICsgIioiICksCgoJcmF0dHJpYnV0ZVF1b3RlcyA9IG5ldyBSZWdFeHAoICI9IiArIHdoaXRlc3BhY2UgKyAiKihbXlxcXSdcIl0qPykiICsgd2hpdGVzcGFjZSArICIqXFxdIiwgImciICksCgoJcnBzZXVkbyA9IG5ldyBSZWdFeHAoIHBzZXVkb3MgKSwKCXJpZGVudGlmaWVyID0gbmV3IFJlZ0V4cCggIl4iICsgaWRlbnRpZmllciArICIkIiApLAoKCW1hdGNoRXhwciA9IHsKCQkiSUQiOiBuZXcgUmVnRXhwKCAiXiMoIiArIGNoYXJhY3RlckVuY29kaW5nICsgIikiICksCgkJIkNMQVNTIjogbmV3IFJlZ0V4cCggIl5cXC4oIiArIGNoYXJhY3RlckVuY29kaW5nICsgIikiICksCgkJIlRBRyI6IG5ldyBSZWdFeHAoICJeKCIgKyBjaGFyYWN0ZXJFbmNvZGluZy5yZXBsYWNlKCAidyIsICJ3KiIgKSArICIpIiApLAoJCSJBVFRSIjogbmV3IFJlZ0V4cCggIl4iICsgYXR0cmlidXRlcyApLAoJCSJQU0VVRE8iOiBuZXcgUmVnRXhwKCAiXiIgKyBwc2V1ZG9zICksCgkJIkNISUxEIjogbmV3IFJlZ0V4cCggIl46KG9ubHl8Zmlyc3R8bGFzdHxudGh8bnRoLWxhc3QpLShjaGlsZHxvZi10eXBlKSg/OlxcKCIgKyB3aGl0ZXNwYWNlICsKCQkJIiooZXZlbnxvZGR8KChbKy1dfCkoXFxkKilufCkiICsgd2hpdGVzcGFjZSArICIqKD86KFsrLV18KSIgKyB3aGl0ZXNwYWNlICsKCQkJIiooXFxkKyl8KSkiICsgd2hpdGVzcGFjZSArICIqXFwpfCkiLCAiaSIgKSwKCQkiYm9vbCI6IG5ldyBSZWdFeHAoICJeKD86IiArIGJvb2xlYW5zICsgIikkIiwgImkiICksCgkJLy8gRm9yIHVzZSBpbiBsaWJyYXJpZXMgaW1wbGVtZW50aW5nIC5pcygpCgkJLy8gV2UgdXNlIHRoaXMgZm9yIFBPUyBtYXRjaGluZyBpbiBgc2VsZWN0YAoJCSJuZWVkc0NvbnRleHQiOiBuZXcgUmVnRXhwKCAiXiIgKyB3aGl0ZXNwYWNlICsgIipbPit+XXw6KGV2ZW58b2RkfGVxfGd0fGx0fG50aHxmaXJzdHxsYXN0KSg/OlxcKCIgKwoJCQl3aGl0ZXNwYWNlICsgIiooKD86LVxcZCk/XFxkKikiICsgd2hpdGVzcGFjZSArICIqXFwpfCkoPz1bXi1dfCQpIiwgImkiICkKCX0sCgoJcmlucHV0cyA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbikkL2ksCglyaGVhZGVyID0gL15oXGQkL2ksCgoJcm5hdGl2ZSA9IC9eW157XStce1xzKlxbbmF0aXZlIFx3LywKCgkvLyBFYXNpbHktcGFyc2VhYmxlL3JldHJpZXZhYmxlIElEIG9yIFRBRyBvciBDTEFTUyBzZWxlY3RvcnMKCXJxdWlja0V4cHIgPSAvXig/OiMoW1x3LV0rKXwoXHcrKXxcLihbXHctXSspKSQvLAoKCXJzaWJsaW5nID0gL1srfl0vLAoJcmVzY2FwZSA9IC8nfFxcL2csCgoJLy8gQ1NTIGVzY2FwZXMgaHR0cDovL3d3dy53My5vcmcvVFIvQ1NTMjEvc3luZGF0YS5odG1sI2VzY2FwZWQtY2hhcmFjdGVycwoJcnVuZXNjYXBlID0gbmV3IFJlZ0V4cCggIlxcXFwoW1xcZGEtZl17MSw2fSIgKyB3aGl0ZXNwYWNlICsgIj98KCIgKyB3aGl0ZXNwYWNlICsgIil8LikiLCAiaWciICksCglmdW5lc2NhcGUgPSBmdW5jdGlvbiggXywgZXNjYXBlZCwgZXNjYXBlZFdoaXRlc3BhY2UgKSB7CgkJdmFyIGhpZ2ggPSAiMHgiICsgZXNjYXBlZCAtIDB4MTAwMDA7CgkJLy8gTmFOIG1lYW5zIG5vbi1jb2RlcG9pbnQKCQkvLyBTdXBwb3J0OiBGaXJlZm94PDI0CgkJLy8gV29ya2Fyb3VuZCBlcnJvbmVvdXMgbnVtZXJpYyBpbnRlcnByZXRhdGlvbiBvZiArIjB4IgoJCXJldHVybiBoaWdoICE9PSBoaWdoIHx8IGVzY2FwZWRXaGl0ZXNwYWNlID8KCQkJZXNjYXBlZCA6CgkJCWhpZ2ggPCAwID8KCQkJCS8vIEJNUCBjb2RlcG9pbnQKCQkJCVN0cmluZy5mcm9tQ2hhckNvZGUoIGhpZ2ggKyAweDEwMDAwICkgOgoJCQkJLy8gU3VwcGxlbWVudGFsIFBsYW5lIGNvZGVwb2ludCAoc3Vycm9nYXRlIHBhaXIpCgkJCQlTdHJpbmcuZnJvbUNoYXJDb2RlKCBoaWdoID4+IDEwIHwgMHhEODAwLCBoaWdoICYgMHgzRkYgfCAweERDMDAgKTsKCX07CgovLyBPcHRpbWl6ZSBmb3IgcHVzaC5hcHBseSggXywgTm9kZUxpc3QgKQp0cnkgewoJcHVzaC5hcHBseSgKCQkoYXJyID0gc2xpY2UuY2FsbCggcHJlZmVycmVkRG9jLmNoaWxkTm9kZXMgKSksCgkJcHJlZmVycmVkRG9jLmNoaWxkTm9kZXMKCSk7CgkvLyBTdXBwb3J0OiBBbmRyb2lkPDQuMAoJLy8gRGV0ZWN0IHNpbGVudGx5IGZhaWxpbmcgcHVzaC5hcHBseQoJYXJyWyBwcmVmZXJyZWREb2MuY2hpbGROb2Rlcy5sZW5ndGggXS5ub2RlVHlwZTsKfSBjYXRjaCAoIGUgKSB7CglwdXNoID0geyBhcHBseTogYXJyLmxlbmd0aCA/CgoJCS8vIExldmVyYWdlIHNsaWNlIGlmIHBvc3NpYmxlCgkJZnVuY3Rpb24oIHRhcmdldCwgZWxzICkgewoJCQlwdXNoX25hdGl2ZS5hcHBseSggdGFyZ2V0LCBzbGljZS5jYWxsKGVscykgKTsKCQl9IDoKCgkJLy8gU3VwcG9ydDogSUU8OQoJCS8vIE90aGVyd2lzZSBhcHBlbmQgZGlyZWN0bHkKCQlmdW5jdGlvbiggdGFyZ2V0LCBlbHMgKSB7CgkJCXZhciBqID0gdGFyZ2V0Lmxlbmd0aCwKCQkJCWkgPSAwOwoJCQkvLyBDYW4ndCB0cnVzdCBOb2RlTGlzdC5sZW5ndGgKCQkJd2hpbGUgKCAodGFyZ2V0W2orK10gPSBlbHNbaSsrXSkgKSB7fQoJCQl0YXJnZXQubGVuZ3RoID0gaiAtIDE7CgkJfQoJfTsKfQoKZnVuY3Rpb24gU2l6emxlKCBzZWxlY3RvciwgY29udGV4dCwgcmVzdWx0cywgc2VlZCApIHsKCXZhciBtYXRjaCwgZWxlbSwgbSwgbm9kZVR5cGUsCgkJLy8gUVNBIHZhcnMKCQlpLCBncm91cHMsIG9sZCwgbmlkLCBuZXdDb250ZXh0LCBuZXdTZWxlY3RvcjsKCglpZiAoICggY29udGV4dCA/IGNvbnRleHQub3duZXJEb2N1bWVudCB8fCBjb250ZXh0IDogcHJlZmVycmVkRG9jICkgIT09IGRvY3VtZW50ICkgewoJCXNldERvY3VtZW50KCBjb250ZXh0ICk7Cgl9CgoJY29udGV4dCA9IGNvbnRleHQgfHwgZG9jdW1lbnQ7CglyZXN1bHRzID0gcmVzdWx0cyB8fCBbXTsKCglpZiAoICFzZWxlY3RvciB8fCB0eXBlb2Ygc2VsZWN0b3IgIT09ICJzdHJpbmciICkgewoJCXJldHVybiByZXN1bHRzOwoJfQoKCWlmICggKG5vZGVUeXBlID0gY29udGV4dC5ub2RlVHlwZSkgIT09IDEgJiYgbm9kZVR5cGUgIT09IDkgKSB7CgkJcmV0dXJuIFtdOwoJfQoKCWlmICggZG9jdW1lbnRJc0hUTUwgJiYgIXNlZWQgKSB7CgoJCS8vIFNob3J0Y3V0cwoJCWlmICggKG1hdGNoID0gcnF1aWNrRXhwci5leGVjKCBzZWxlY3RvciApKSApIHsKCQkJLy8gU3BlZWQtdXA6IFNpenpsZSgiI0lEIikKCQkJaWYgKCAobSA9IG1hdGNoWzFdKSApIHsKCQkJCWlmICggbm9kZVR5cGUgPT09IDkgKSB7CgkJCQkJZWxlbSA9IGNvbnRleHQuZ2V0RWxlbWVudEJ5SWQoIG0gKTsKCQkJCQkvLyBDaGVjayBwYXJlbnROb2RlIHRvIGNhdGNoIHdoZW4gQmxhY2tiZXJyeSA0LjYgcmV0dXJucwoJCQkJCS8vIG5vZGVzIHRoYXQgYXJlIG5vIGxvbmdlciBpbiB0aGUgZG9jdW1lbnQgKGpRdWVyeSAjNjk2MykKCQkJCQlpZiAoIGVsZW0gJiYgZWxlbS5wYXJlbnROb2RlICkgewoJCQkJCQkvLyBIYW5kbGUgdGhlIGNhc2Ugd2hlcmUgSUUsIE9wZXJhLCBhbmQgV2Via2l0IHJldHVybiBpdGVtcwoJCQkJCQkvLyBieSBuYW1lIGluc3RlYWQgb2YgSUQKCQkJCQkJaWYgKCBlbGVtLmlkID09PSBtICkgewoJCQkJCQkJcmVzdWx0cy5wdXNoKCBlbGVtICk7CgkJCQkJCQlyZXR1cm4gcmVzdWx0czsKCQkJCQkJfQoJCQkJCX0gZWxzZSB7CgkJCQkJCXJldHVybiByZXN1bHRzOwoJCQkJCX0KCQkJCX0gZWxzZSB7CgkJCQkJLy8gQ29udGV4dCBpcyBub3QgYSBkb2N1bWVudAoJCQkJCWlmICggY29udGV4dC5vd25lckRvY3VtZW50ICYmIChlbGVtID0gY29udGV4dC5vd25lckRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCBtICkpICYmCgkJCQkJCWNvbnRhaW5zKCBjb250ZXh0LCBlbGVtICkgJiYgZWxlbS5pZCA9PT0gbSApIHsKCQkJCQkJcmVzdWx0cy5wdXNoKCBlbGVtICk7CgkJCQkJCXJldHVybiByZXN1bHRzOwoJCQkJCX0KCQkJCX0KCgkJCS8vIFNwZWVkLXVwOiBTaXp6bGUoIlRBRyIpCgkJCX0gZWxzZSBpZiAoIG1hdGNoWzJdICkgewoJCQkJcHVzaC5hcHBseSggcmVzdWx0cywgY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSggc2VsZWN0b3IgKSApOwoJCQkJcmV0dXJuIHJlc3VsdHM7CgoJCQkvLyBTcGVlZC11cDogU2l6emxlKCIuQ0xBU1MiKQoJCQl9IGVsc2UgaWYgKCAobSA9IG1hdGNoWzNdKSAmJiBzdXBwb3J0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgY29udGV4dC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lICkgewoJCQkJcHVzaC5hcHBseSggcmVzdWx0cywgY29udGV4dC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCBtICkgKTsKCQkJCXJldHVybiByZXN1bHRzOwoJCQl9CgkJfQoKCQkvLyBRU0EgcGF0aAoJCWlmICggc3VwcG9ydC5xc2EgJiYgKCFyYnVnZ3lRU0EgfHwgIXJidWdneVFTQS50ZXN0KCBzZWxlY3RvciApKSApIHsKCQkJbmlkID0gb2xkID0gZXhwYW5kbzsKCQkJbmV3Q29udGV4dCA9IGNvbnRleHQ7CgkJCW5ld1NlbGVjdG9yID0gbm9kZVR5cGUgPT09IDkgJiYgc2VsZWN0b3I7CgoJCQkvLyBxU0Egd29ya3Mgc3RyYW5nZWx5IG9uIEVsZW1lbnQtcm9vdGVkIHF1ZXJpZXMKCQkJLy8gV2UgY2FuIHdvcmsgYXJvdW5kIHRoaXMgYnkgc3BlY2lmeWluZyBhbiBleHRyYSBJRCBvbiB0aGUgcm9vdAoJCQkvLyBhbmQgd29ya2luZyB1cCBmcm9tIHRoZXJlIChUaGFua3MgdG8gQW5kcmV3IER1cG9udCBmb3IgdGhlIHRlY2huaXF1ZSkKCQkJLy8gSUUgOCBkb2Vzbid0IHdvcmsgb24gb2JqZWN0IGVsZW1lbnRzCgkJCWlmICggbm9kZVR5cGUgPT09IDEgJiYgY29udGV4dC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpICE9PSAib2JqZWN0IiApIHsKCQkJCWdyb3VwcyA9IHRva2VuaXplKCBzZWxlY3RvciApOwoKCQkJCWlmICggKG9sZCA9IGNvbnRleHQuZ2V0QXR0cmlidXRlKCJpZCIpKSApIHsKCQkJCQluaWQgPSBvbGQucmVwbGFjZSggcmVzY2FwZSwgIlxcJCYiICk7CgkJCQl9IGVsc2UgewoJCQkJCWNvbnRleHQuc2V0QXR0cmlidXRlKCAiaWQiLCBuaWQgKTsKCQkJCX0KCQkJCW5pZCA9ICJbaWQ9JyIgKyBuaWQgKyAiJ10gIjsKCgkJCQlpID0gZ3JvdXBzLmxlbmd0aDsKCQkJCXdoaWxlICggaS0tICkgewoJCQkJCWdyb3Vwc1tpXSA9IG5pZCArIHRvU2VsZWN0b3IoIGdyb3Vwc1tpXSApOwoJCQkJfQoJCQkJbmV3Q29udGV4dCA9IHJzaWJsaW5nLnRlc3QoIHNlbGVjdG9yICkgJiYgdGVzdENvbnRleHQoIGNvbnRleHQucGFyZW50Tm9kZSApIHx8IGNvbnRleHQ7CgkJCQluZXdTZWxlY3RvciA9IGdyb3Vwcy5qb2luKCIsIik7CgkJCX0KCgkJCWlmICggbmV3U2VsZWN0b3IgKSB7CgkJCQl0cnkgewoJCQkJCXB1c2guYXBwbHkoIHJlc3VsdHMsCgkJCQkJCW5ld0NvbnRleHQucXVlcnlTZWxlY3RvckFsbCggbmV3U2VsZWN0b3IgKQoJCQkJCSk7CgkJCQkJcmV0dXJuIHJlc3VsdHM7CgkJCQl9IGNhdGNoKHFzYUVycm9yKSB7CgkJCQl9IGZpbmFsbHkgewoJCQkJCWlmICggIW9sZCApIHsKCQkJCQkJY29udGV4dC5yZW1vdmVBdHRyaWJ1dGUoImlkIik7CgkJCQkJfQoJCQkJfQoJCQl9CgkJfQoJfQoKCS8vIEFsbCBvdGhlcnMKCXJldHVybiBzZWxlY3QoIHNlbGVjdG9yLnJlcGxhY2UoIHJ0cmltLCAiJDEiICksIGNvbnRleHQsIHJlc3VsdHMsIHNlZWQgKTsKfQoKLyoqCiAqIENyZWF0ZSBrZXktdmFsdWUgY2FjaGVzIG9mIGxpbWl0ZWQgc2l6ZQogKiBAcmV0dXJucyB7RnVuY3Rpb24oc3RyaW5nLCBPYmplY3QpfSBSZXR1cm5zIHRoZSBPYmplY3QgZGF0YSBhZnRlciBzdG9yaW5nIGl0IG9uIGl0c2VsZiB3aXRoCiAqCXByb3BlcnR5IG5hbWUgdGhlIChzcGFjZS1zdWZmaXhlZCkgc3RyaW5nIGFuZCAoaWYgdGhlIGNhY2hlIGlzIGxhcmdlciB0aGFuIEV4cHIuY2FjaGVMZW5ndGgpCiAqCWRlbGV0aW5nIHRoZSBvbGRlc3QgZW50cnkKICovCmZ1bmN0aW9uIGNyZWF0ZUNhY2hlKCkgewoJdmFyIGtleXMgPSBbXTsKCglmdW5jdGlvbiBjYWNoZSgga2V5LCB2YWx1ZSApIHsKCQkvLyBVc2UgKGtleSArICIgIikgdG8gYXZvaWQgY29sbGlzaW9uIHdpdGggbmF0aXZlIHByb3RvdHlwZSBwcm9wZXJ0aWVzIChzZWUgSXNzdWUgIzE1NykKCQlpZiAoIGtleXMucHVzaCgga2V5ICsgIiAiICkgPiBFeHByLmNhY2hlTGVuZ3RoICkgewoJCQkvLyBPbmx5IGtlZXAgdGhlIG1vc3QgcmVjZW50IGVudHJpZXMKCQkJZGVsZXRlIGNhY2hlWyBrZXlzLnNoaWZ0KCkgXTsKCQl9CgkJcmV0dXJuIChjYWNoZVsga2V5ICsgIiAiIF0gPSB2YWx1ZSk7Cgl9CglyZXR1cm4gY2FjaGU7Cn0KCi8qKgogKiBNYXJrIGEgZnVuY3Rpb24gZm9yIHNwZWNpYWwgdXNlIGJ5IFNpenpsZQogKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgZnVuY3Rpb24gdG8gbWFyawogKi8KZnVuY3Rpb24gbWFya0Z1bmN0aW9uKCBmbiApIHsKCWZuWyBleHBhbmRvIF0gPSB0cnVlOwoJcmV0dXJuIGZuOwp9CgovKioKICogU3VwcG9ydCB0ZXN0aW5nIHVzaW5nIGFuIGVsZW1lbnQKICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gUGFzc2VkIHRoZSBjcmVhdGVkIGRpdiBhbmQgZXhwZWN0cyBhIGJvb2xlYW4gcmVzdWx0CiAqLwpmdW5jdGlvbiBhc3NlcnQoIGZuICkgewoJdmFyIGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpOwoKCXRyeSB7CgkJcmV0dXJuICEhZm4oIGRpdiApOwoJfSBjYXRjaCAoZSkgewoJCXJldHVybiBmYWxzZTsKCX0gZmluYWxseSB7CgkJLy8gUmVtb3ZlIGZyb20gaXRzIHBhcmVudCBieSBkZWZhdWx0CgkJaWYgKCBkaXYucGFyZW50Tm9kZSApIHsKCQkJZGl2LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIGRpdiApOwoJCX0KCQkvLyByZWxlYXNlIG1lbW9yeSBpbiBJRQoJCWRpdiA9IG51bGw7Cgl9Cn0KCi8qKgogKiBBZGRzIHRoZSBzYW1lIGhhbmRsZXIgZm9yIGFsbCBvZiB0aGUgc3BlY2lmaWVkIGF0dHJzCiAqIEBwYXJhbSB7U3RyaW5nfSBhdHRycyBQaXBlLXNlcGFyYXRlZCBsaXN0IG9mIGF0dHJpYnV0ZXMKICogQHBhcmFtIHtGdW5jdGlvbn0gaGFuZGxlciBUaGUgbWV0aG9kIHRoYXQgd2lsbCBiZSBhcHBsaWVkCiAqLwpmdW5jdGlvbiBhZGRIYW5kbGUoIGF0dHJzLCBoYW5kbGVyICkgewoJdmFyIGFyciA9IGF0dHJzLnNwbGl0KCJ8IiksCgkJaSA9IGF0dHJzLmxlbmd0aDsKCgl3aGlsZSAoIGktLSApIHsKCQlFeHByLmF0dHJIYW5kbGVbIGFycltpXSBdID0gaGFuZGxlcjsKCX0KfQoKLyoqCiAqIENoZWNrcyBkb2N1bWVudCBvcmRlciBvZiB0d28gc2libGluZ3MKICogQHBhcmFtIHtFbGVtZW50fSBhCiAqIEBwYXJhbSB7RWxlbWVudH0gYgogKiBAcmV0dXJucyB7TnVtYmVyfSBSZXR1cm5zIGxlc3MgdGhhbiAwIGlmIGEgcHJlY2VkZXMgYiwgZ3JlYXRlciB0aGFuIDAgaWYgYSBmb2xsb3dzIGIKICovCmZ1bmN0aW9uIHNpYmxpbmdDaGVjayggYSwgYiApIHsKCXZhciBjdXIgPSBiICYmIGEsCgkJZGlmZiA9IGN1ciAmJiBhLm5vZGVUeXBlID09PSAxICYmIGIubm9kZVR5cGUgPT09IDEgJiYKCQkJKCB+Yi5zb3VyY2VJbmRleCB8fCBNQVhfTkVHQVRJVkUgKSAtCgkJCSggfmEuc291cmNlSW5kZXggfHwgTUFYX05FR0FUSVZFICk7CgoJLy8gVXNlIElFIHNvdXJjZUluZGV4IGlmIGF2YWlsYWJsZSBvbiBib3RoIG5vZGVzCglpZiAoIGRpZmYgKSB7CgkJcmV0dXJuIGRpZmY7Cgl9CgoJLy8gQ2hlY2sgaWYgYiBmb2xsb3dzIGEKCWlmICggY3VyICkgewoJCXdoaWxlICggKGN1ciA9IGN1ci5uZXh0U2libGluZykgKSB7CgkJCWlmICggY3VyID09PSBiICkgewoJCQkJcmV0dXJuIC0xOwoJCQl9CgkJfQoJfQoKCXJldHVybiBhID8gMSA6IC0xOwp9CgovKioKICogUmV0dXJucyBhIGZ1bmN0aW9uIHRvIHVzZSBpbiBwc2V1ZG9zIGZvciBpbnB1dCB0eXBlcwogKiBAcGFyYW0ge1N0cmluZ30gdHlwZQogKi8KZnVuY3Rpb24gY3JlYXRlSW5wdXRQc2V1ZG8oIHR5cGUgKSB7CglyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7CgkJdmFyIG5hbWUgPSBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7CgkJcmV0dXJuIG5hbWUgPT09ICJpbnB1dCIgJiYgZWxlbS50eXBlID09PSB0eXBlOwoJfTsKfQoKLyoqCiAqIFJldHVybnMgYSBmdW5jdGlvbiB0byB1c2UgaW4gcHNldWRvcyBmb3IgYnV0dG9ucwogKiBAcGFyYW0ge1N0cmluZ30gdHlwZQogKi8KZnVuY3Rpb24gY3JlYXRlQnV0dG9uUHNldWRvKCB0eXBlICkgewoJcmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkgewoJCXZhciBuYW1lID0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOwoJCXJldHVybiAobmFtZSA9PT0gImlucHV0IiB8fCBuYW1lID09PSAiYnV0dG9uIikgJiYgZWxlbS50eXBlID09PSB0eXBlOwoJfTsKfQoKLyoqCiAqIFJldHVybnMgYSBmdW5jdGlvbiB0byB1c2UgaW4gcHNldWRvcyBmb3IgcG9zaXRpb25hbHMKICogQHBhcmFtIHtGdW5jdGlvbn0gZm4KICovCmZ1bmN0aW9uIGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oIGZuICkgewoJcmV0dXJuIG1hcmtGdW5jdGlvbihmdW5jdGlvbiggYXJndW1lbnQgKSB7CgkJYXJndW1lbnQgPSArYXJndW1lbnQ7CgkJcmV0dXJuIG1hcmtGdW5jdGlvbihmdW5jdGlvbiggc2VlZCwgbWF0Y2hlcyApIHsKCQkJdmFyIGosCgkJCQltYXRjaEluZGV4ZXMgPSBmbiggW10sIHNlZWQubGVuZ3RoLCBhcmd1bWVudCApLAoJCQkJaSA9IG1hdGNoSW5kZXhlcy5sZW5ndGg7CgoJCQkvLyBNYXRjaCBlbGVtZW50cyBmb3VuZCBhdCB0aGUgc3BlY2lmaWVkIGluZGV4ZXMKCQkJd2hpbGUgKCBpLS0gKSB7CgkJCQlpZiAoIHNlZWRbIChqID0gbWF0Y2hJbmRleGVzW2ldKSBdICkgewoJCQkJCXNlZWRbal0gPSAhKG1hdGNoZXNbal0gPSBzZWVkW2pdKTsKCQkJCX0KCQkJfQoJCX0pOwoJfSk7Cn0KCi8qKgogKiBDaGVja3MgYSBub2RlIGZvciB2YWxpZGl0eSBhcyBhIFNpenpsZSBjb250ZXh0CiAqIEBwYXJhbSB7RWxlbWVudHxPYmplY3Q9fSBjb250ZXh0CiAqIEByZXR1cm5zIHtFbGVtZW50fE9iamVjdHxCb29sZWFufSBUaGUgaW5wdXQgbm9kZSBpZiBhY2NlcHRhYmxlLCBvdGhlcndpc2UgYSBmYWxzeSB2YWx1ZQogKi8KZnVuY3Rpb24gdGVzdENvbnRleHQoIGNvbnRleHQgKSB7CglyZXR1cm4gY29udGV4dCAmJiB0eXBlb2YgY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSAhPT0gc3RydW5kZWZpbmVkICYmIGNvbnRleHQ7Cn0KCi8vIEV4cG9zZSBzdXBwb3J0IHZhcnMgZm9yIGNvbnZlbmllbmNlCnN1cHBvcnQgPSBTaXp6bGUuc3VwcG9ydCA9IHt9OwoKLyoqCiAqIERldGVjdHMgWE1MIG5vZGVzCiAqIEBwYXJhbSB7RWxlbWVudHxPYmplY3R9IGVsZW0gQW4gZWxlbWVudCBvciBhIGRvY3VtZW50CiAqIEByZXR1cm5zIHtCb29sZWFufSBUcnVlIGlmZiBlbGVtIGlzIGEgbm9uLUhUTUwgWE1MIG5vZGUKICovCmlzWE1MID0gU2l6emxlLmlzWE1MID0gZnVuY3Rpb24oIGVsZW0gKSB7CgkvLyBkb2N1bWVudEVsZW1lbnQgaXMgdmVyaWZpZWQgZm9yIGNhc2VzIHdoZXJlIGl0IGRvZXNuJ3QgeWV0IGV4aXN0CgkvLyAoc3VjaCBhcyBsb2FkaW5nIGlmcmFtZXMgaW4gSUUgLSAjNDgzMykKCXZhciBkb2N1bWVudEVsZW1lbnQgPSBlbGVtICYmIChlbGVtLm93bmVyRG9jdW1lbnQgfHwgZWxlbSkuZG9jdW1lbnRFbGVtZW50OwoJcmV0dXJuIGRvY3VtZW50RWxlbWVudCA/IGRvY3VtZW50RWxlbWVudC5ub2RlTmFtZSAhPT0gIkhUTUwiIDogZmFsc2U7Cn07CgovKioKICogU2V0cyBkb2N1bWVudC1yZWxhdGVkIHZhcmlhYmxlcyBvbmNlIGJhc2VkIG9uIHRoZSBjdXJyZW50IGRvY3VtZW50CiAqIEBwYXJhbSB7RWxlbWVudHxPYmplY3R9IFtkb2NdIEFuIGVsZW1lbnQgb3IgZG9jdW1lbnQgb2JqZWN0IHRvIHVzZSB0byBzZXQgdGhlIGRvY3VtZW50CiAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgdGhlIGN1cnJlbnQgZG9jdW1lbnQKICovCnNldERvY3VtZW50ID0gU2l6emxlLnNldERvY3VtZW50ID0gZnVuY3Rpb24oIG5vZGUgKSB7Cgl2YXIgaGFzQ29tcGFyZSwKCQlkb2MgPSBub2RlID8gbm9kZS5vd25lckRvY3VtZW50IHx8IG5vZGUgOiBwcmVmZXJyZWREb2MsCgkJcGFyZW50ID0gZG9jLmRlZmF1bHRWaWV3OwoKCS8vIElmIG5vIGRvY3VtZW50IGFuZCBkb2N1bWVudEVsZW1lbnQgaXMgYXZhaWxhYmxlLCByZXR1cm4KCWlmICggZG9jID09PSBkb2N1bWVudCB8fCBkb2Mubm9kZVR5cGUgIT09IDkgfHwgIWRvYy5kb2N1bWVudEVsZW1lbnQgKSB7CgkJcmV0dXJuIGRvY3VtZW50OwoJfQoKCS8vIFNldCBvdXIgZG9jdW1lbnQKCWRvY3VtZW50ID0gZG9jOwoJZG9jRWxlbSA9IGRvYy5kb2N1bWVudEVsZW1lbnQ7CgoJLy8gU3VwcG9ydCB0ZXN0cwoJZG9jdW1lbnRJc0hUTUwgPSAhaXNYTUwoIGRvYyApOwoKCS8vIFN1cHBvcnQ6IElFPjgKCS8vIElmIGlmcmFtZSBkb2N1bWVudCBpcyBhc3NpZ25lZCB0byAiZG9jdW1lbnQiIHZhcmlhYmxlIGFuZCBpZiBpZnJhbWUgaGFzIGJlZW4gcmVsb2FkZWQsCgkvLyBJRSB3aWxsIHRocm93ICJwZXJtaXNzaW9uIGRlbmllZCIgZXJyb3Igd2hlbiBhY2Nlc3NpbmcgImRvY3VtZW50IiB2YXJpYWJsZSwgc2VlIGpRdWVyeSAjMTM5MzYKCS8vIElFNi04IGRvIG5vdCBzdXBwb3J0IHRoZSBkZWZhdWx0VmlldyBwcm9wZXJ0eSBzbyBwYXJlbnQgd2lsbCBiZSB1bmRlZmluZWQKCWlmICggcGFyZW50ICYmIHBhcmVudCAhPT0gcGFyZW50LnRvcCApIHsKCQkvLyBJRTExIGRvZXMgbm90IGhhdmUgYXR0YWNoRXZlbnQsIHNvIGFsbCBtdXN0IHN1ZmZlcgoJCWlmICggcGFyZW50LmFkZEV2ZW50TGlzdGVuZXIgKSB7CgkJCXBhcmVudC5hZGRFdmVudExpc3RlbmVyKCAidW5sb2FkIiwgZnVuY3Rpb24oKSB7CgkJCQlzZXREb2N1bWVudCgpOwoJCQl9LCBmYWxzZSApOwoJCX0gZWxzZSBpZiAoIHBhcmVudC5hdHRhY2hFdmVudCApIHsKCQkJcGFyZW50LmF0dGFjaEV2ZW50KCAib251bmxvYWQiLCBmdW5jdGlvbigpIHsKCQkJCXNldERvY3VtZW50KCk7CgkJCX0pOwoJCX0KCX0KCgkvKiBBdHRyaWJ1dGVzCgktLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCgoJLy8gU3VwcG9ydDogSUU8OAoJLy8gVmVyaWZ5IHRoYXQgZ2V0QXR0cmlidXRlIHJlYWxseSByZXR1cm5zIGF0dHJpYnV0ZXMgYW5kIG5vdCBwcm9wZXJ0aWVzIChleGNlcHRpbmcgSUU4IGJvb2xlYW5zKQoJc3VwcG9ydC5hdHRyaWJ1dGVzID0gYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7CgkJZGl2LmNsYXNzTmFtZSA9ICJpIjsKCQlyZXR1cm4gIWRpdi5nZXRBdHRyaWJ1dGUoImNsYXNzTmFtZSIpOwoJfSk7CgoJLyogZ2V0RWxlbWVudChzKUJ5KgoJLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwoKCS8vIENoZWNrIGlmIGdldEVsZW1lbnRzQnlUYWdOYW1lKCIqIikgcmV0dXJucyBvbmx5IGVsZW1lbnRzCglzdXBwb3J0LmdldEVsZW1lbnRzQnlUYWdOYW1lID0gYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7CgkJZGl2LmFwcGVuZENoaWxkKCBkb2MuY3JlYXRlQ29tbWVudCgiIikgKTsKCQlyZXR1cm4gIWRpdi5nZXRFbGVtZW50c0J5VGFnTmFtZSgiKiIpLmxlbmd0aDsKCX0pOwoKCS8vIENoZWNrIGlmIGdldEVsZW1lbnRzQnlDbGFzc05hbWUgY2FuIGJlIHRydXN0ZWQKCXN1cHBvcnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSA9IHJuYXRpdmUudGVzdCggZG9jLmdldEVsZW1lbnRzQnlDbGFzc05hbWUgKSAmJiBhc3NlcnQoZnVuY3Rpb24oIGRpdiApIHsKCQlkaXYuaW5uZXJIVE1MID0gIjxkaXYgY2xhc3M9J2EnPjwvZGl2PjxkaXYgY2xhc3M9J2EgaSc+PC9kaXY+IjsKCgkJLy8gU3VwcG9ydDogU2FmYXJpPDQKCQkvLyBDYXRjaCBjbGFzcyBvdmVyLWNhY2hpbmcKCQlkaXYuZmlyc3RDaGlsZC5jbGFzc05hbWUgPSAiaSI7CgkJLy8gU3VwcG9ydDogT3BlcmE8MTAKCQkvLyBDYXRjaCBnRUJDTiBmYWlsdXJlIHRvIGZpbmQgbm9uLWxlYWRpbmcgY2xhc3NlcwoJCXJldHVybiBkaXYuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgiaSIpLmxlbmd0aCA9PT0gMjsKCX0pOwoKCS8vIFN1cHBvcnQ6IElFPDEwCgkvLyBDaGVjayBpZiBnZXRFbGVtZW50QnlJZCByZXR1cm5zIGVsZW1lbnRzIGJ5IG5hbWUKCS8vIFRoZSBicm9rZW4gZ2V0RWxlbWVudEJ5SWQgbWV0aG9kcyBkb24ndCBwaWNrIHVwIHByb2dyYW1hdGljYWxseS1zZXQgbmFtZXMsCgkvLyBzbyB1c2UgYSByb3VuZGFib3V0IGdldEVsZW1lbnRzQnlOYW1lIHRlc3QKCXN1cHBvcnQuZ2V0QnlJZCA9IGFzc2VydChmdW5jdGlvbiggZGl2ICkgewoJCWRvY0VsZW0uYXBwZW5kQ2hpbGQoIGRpdiApLmlkID0gZXhwYW5kbzsKCQlyZXR1cm4gIWRvYy5nZXRFbGVtZW50c0J5TmFtZSB8fCAhZG9jLmdldEVsZW1lbnRzQnlOYW1lKCBleHBhbmRvICkubGVuZ3RoOwoJfSk7CgoJLy8gSUQgZmluZCBhbmQgZmlsdGVyCglpZiAoIHN1cHBvcnQuZ2V0QnlJZCApIHsKCQlFeHByLmZpbmRbIklEIl0gPSBmdW5jdGlvbiggaWQsIGNvbnRleHQgKSB7CgkJCWlmICggdHlwZW9mIGNvbnRleHQuZ2V0RWxlbWVudEJ5SWQgIT09IHN0cnVuZGVmaW5lZCAmJiBkb2N1bWVudElzSFRNTCApIHsKCQkJCXZhciBtID0gY29udGV4dC5nZXRFbGVtZW50QnlJZCggaWQgKTsKCQkJCS8vIENoZWNrIHBhcmVudE5vZGUgdG8gY2F0Y2ggd2hlbiBCbGFja2JlcnJ5IDQuNiByZXR1cm5zCgkJCQkvLyBub2RlcyB0aGF0IGFyZSBubyBsb25nZXIgaW4gdGhlIGRvY3VtZW50ICM2OTYzCgkJCQlyZXR1cm4gbSAmJiBtLnBhcmVudE5vZGUgPyBbIG0gXSA6IFtdOwoJCQl9CgkJfTsKCQlFeHByLmZpbHRlclsiSUQiXSA9IGZ1bmN0aW9uKCBpZCApIHsKCQkJdmFyIGF0dHJJZCA9IGlkLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICk7CgkJCXJldHVybiBmdW5jdGlvbiggZWxlbSApIHsKCQkJCXJldHVybiBlbGVtLmdldEF0dHJpYnV0ZSgiaWQiKSA9PT0gYXR0cklkOwoJCQl9OwoJCX07Cgl9IGVsc2UgewoJCS8vIFN1cHBvcnQ6IElFNi83CgkJLy8gZ2V0RWxlbWVudEJ5SWQgaXMgbm90IHJlbGlhYmxlIGFzIGEgZmluZCBzaG9ydGN1dAoJCWRlbGV0ZSBFeHByLmZpbmRbIklEIl07CgoJCUV4cHIuZmlsdGVyWyJJRCJdID0gIGZ1bmN0aW9uKCBpZCApIHsKCQkJdmFyIGF0dHJJZCA9IGlkLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICk7CgkJCXJldHVybiBmdW5jdGlvbiggZWxlbSApIHsKCQkJCXZhciBub2RlID0gdHlwZW9mIGVsZW0uZ2V0QXR0cmlidXRlTm9kZSAhPT0gc3RydW5kZWZpbmVkICYmIGVsZW0uZ2V0QXR0cmlidXRlTm9kZSgiaWQiKTsKCQkJCXJldHVybiBub2RlICYmIG5vZGUudmFsdWUgPT09IGF0dHJJZDsKCQkJfTsKCQl9OwoJfQoKCS8vIFRhZwoJRXhwci5maW5kWyJUQUciXSA9IHN1cHBvcnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgPwoJCWZ1bmN0aW9uKCB0YWcsIGNvbnRleHQgKSB7CgkJCWlmICggdHlwZW9mIGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgIT09IHN0cnVuZGVmaW5lZCApIHsKCQkJCXJldHVybiBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lKCB0YWcgKTsKCQkJfQoJCX0gOgoJCWZ1bmN0aW9uKCB0YWcsIGNvbnRleHQgKSB7CgkJCXZhciBlbGVtLAoJCQkJdG1wID0gW10sCgkJCQlpID0gMCwKCQkJCXJlc3VsdHMgPSBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lKCB0YWcgKTsKCgkJCS8vIEZpbHRlciBvdXQgcG9zc2libGUgY29tbWVudHMKCQkJaWYgKCB0YWcgPT09ICIqIiApIHsKCQkJCXdoaWxlICggKGVsZW0gPSByZXN1bHRzW2krK10pICkgewoJCQkJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHsKCQkJCQkJdG1wLnB1c2goIGVsZW0gKTsKCQkJCQl9CgkJCQl9CgoJCQkJcmV0dXJuIHRtcDsKCQkJfQoJCQlyZXR1cm4gcmVzdWx0czsKCQl9OwoKCS8vIENsYXNzCglFeHByLmZpbmRbIkNMQVNTIl0gPSBzdXBwb3J0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgZnVuY3Rpb24oIGNsYXNzTmFtZSwgY29udGV4dCApIHsKCQlpZiAoIHR5cGVvZiBjb250ZXh0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgIT09IHN0cnVuZGVmaW5lZCAmJiBkb2N1bWVudElzSFRNTCApIHsKCQkJcmV0dXJuIGNvbnRleHQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSggY2xhc3NOYW1lICk7CgkJfQoJfTsKCgkvKiBRU0EvbWF0Y2hlc1NlbGVjdG9yCgktLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCgoJLy8gUVNBIGFuZCBtYXRjaGVzU2VsZWN0b3Igc3VwcG9ydAoKCS8vIG1hdGNoZXNTZWxlY3Rvcig6YWN0aXZlKSByZXBvcnRzIGZhbHNlIHdoZW4gdHJ1ZSAoSUU5L09wZXJhIDExLjUpCglyYnVnZ3lNYXRjaGVzID0gW107CgoJLy8gcVNhKDpmb2N1cykgcmVwb3J0cyBmYWxzZSB3aGVuIHRydWUgKENocm9tZSAyMSkKCS8vIFdlIGFsbG93IHRoaXMgYmVjYXVzZSBvZiBhIGJ1ZyBpbiBJRTgvOSB0aGF0IHRocm93cyBhbiBlcnJvcgoJLy8gd2hlbmV2ZXIgYGRvY3VtZW50LmFjdGl2ZUVsZW1lbnRgIGlzIGFjY2Vzc2VkIG9uIGFuIGlmcmFtZQoJLy8gU28sIHdlIGFsbG93IDpmb2N1cyB0byBwYXNzIHRocm91Z2ggUVNBIGFsbCB0aGUgdGltZSB0byBhdm9pZCB0aGUgSUUgZXJyb3IKCS8vIFNlZSBodHRwOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC8xMzM3OAoJcmJ1Z2d5UVNBID0gW107CgoJaWYgKCAoc3VwcG9ydC5xc2EgPSBybmF0aXZlLnRlc3QoIGRvYy5xdWVyeVNlbGVjdG9yQWxsICkpICkgewoJCS8vIEJ1aWxkIFFTQSByZWdleAoJCS8vIFJlZ2V4IHN0cmF0ZWd5IGFkb3B0ZWQgZnJvbSBEaWVnbyBQZXJpbmkKCQlhc3NlcnQoZnVuY3Rpb24oIGRpdiApIHsKCQkJLy8gU2VsZWN0IGlzIHNldCB0byBlbXB0eSBzdHJpbmcgb24gcHVycG9zZQoJCQkvLyBUaGlzIGlzIHRvIHRlc3QgSUUncyB0cmVhdG1lbnQgb2Ygbm90IGV4cGxpY2l0bHkKCQkJLy8gc2V0dGluZyBhIGJvb2xlYW4gY29udGVudCBhdHRyaWJ1dGUsCgkJCS8vIHNpbmNlIGl0cyBwcmVzZW5jZSBzaG91bGQgYmUgZW5vdWdoCgkJCS8vIGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzEyMzU5CgkJCWRpdi5pbm5lckhUTUwgPSAiPHNlbGVjdCBtc2FsbG93Y2xpcD0nJz48b3B0aW9uIHNlbGVjdGVkPScnPjwvb3B0aW9uPjwvc2VsZWN0PiI7CgoJCQkvLyBTdXBwb3J0OiBJRTgsIE9wZXJhIDExLTEyLjE2CgkJCS8vIE5vdGhpbmcgc2hvdWxkIGJlIHNlbGVjdGVkIHdoZW4gZW1wdHkgc3RyaW5ncyBmb2xsb3cgXj0gb3IgJD0gb3IgKj0KCQkJLy8gVGhlIHRlc3QgYXR0cmlidXRlIG11c3QgYmUgdW5rbm93biBpbiBPcGVyYSBidXQgInNhZmUiIGZvciBXaW5SVAoJCQkvLyBodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvaWUvaGg0NjUzODguYXNweCNhdHRyaWJ1dGVfc2VjdGlvbgoJCQlpZiAoIGRpdi5xdWVyeVNlbGVjdG9yQWxsKCJbbXNhbGxvd2NsaXBePScnXSIpLmxlbmd0aCApIHsKCQkJCXJidWdneVFTQS5wdXNoKCAiWypeJF09IiArIHdoaXRlc3BhY2UgKyAiKig/OicnfFwiXCIpIiApOwoJCQl9CgoJCQkvLyBTdXBwb3J0OiBJRTgKCQkJLy8gQm9vbGVhbiBhdHRyaWJ1dGVzIGFuZCAidmFsdWUiIGFyZSBub3QgdHJlYXRlZCBjb3JyZWN0bHkKCQkJaWYgKCAhZGl2LnF1ZXJ5U2VsZWN0b3JBbGwoIltzZWxlY3RlZF0iKS5sZW5ndGggKSB7CgkJCQlyYnVnZ3lRU0EucHVzaCggIlxcWyIgKyB3aGl0ZXNwYWNlICsgIiooPzp2YWx1ZXwiICsgYm9vbGVhbnMgKyAiKSIgKTsKCQkJfQoKCQkJLy8gV2Via2l0L09wZXJhIC0gOmNoZWNrZWQgc2hvdWxkIHJldHVybiBzZWxlY3RlZCBvcHRpb24gZWxlbWVudHMKCQkJLy8gaHR0cDovL3d3dy53My5vcmcvVFIvMjAxMS9SRUMtY3NzMy1zZWxlY3RvcnMtMjAxMTA5MjkvI2NoZWNrZWQKCQkJLy8gSUU4IHRocm93cyBlcnJvciBoZXJlIGFuZCB3aWxsIG5vdCBzZWUgbGF0ZXIgdGVzdHMKCQkJaWYgKCAhZGl2LnF1ZXJ5U2VsZWN0b3JBbGwoIjpjaGVja2VkIikubGVuZ3RoICkgewoJCQkJcmJ1Z2d5UVNBLnB1c2goIjpjaGVja2VkIik7CgkJCX0KCQl9KTsKCgkJYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7CgkJCS8vIFN1cHBvcnQ6IFdpbmRvd3MgOCBOYXRpdmUgQXBwcwoJCQkvLyBUaGUgdHlwZSBhbmQgbmFtZSBhdHRyaWJ1dGVzIGFyZSByZXN0cmljdGVkIGR1cmluZyAuaW5uZXJIVE1MIGFzc2lnbm1lbnQKCQkJdmFyIGlucHV0ID0gZG9jLmNyZWF0ZUVsZW1lbnQoImlucHV0Iik7CgkJCWlucHV0LnNldEF0dHJpYnV0ZSggInR5cGUiLCAiaGlkZGVuIiApOwoJCQlkaXYuYXBwZW5kQ2hpbGQoIGlucHV0ICkuc2V0QXR0cmlidXRlKCAibmFtZSIsICJEIiApOwoKCQkJLy8gU3VwcG9ydDogSUU4CgkJCS8vIEVuZm9yY2UgY2FzZS1zZW5zaXRpdml0eSBvZiBuYW1lIGF0dHJpYnV0ZQoJCQlpZiAoIGRpdi5xdWVyeVNlbGVjdG9yQWxsKCJbbmFtZT1kXSIpLmxlbmd0aCApIHsKCQkJCXJidWdneVFTQS5wdXNoKCAibmFtZSIgKyB3aGl0ZXNwYWNlICsgIipbKl4kfCF+XT89IiApOwoJCQl9CgoJCQkvLyBGRiAzLjUgLSA6ZW5hYmxlZC86ZGlzYWJsZWQgYW5kIGhpZGRlbiBlbGVtZW50cyAoaGlkZGVuIGVsZW1lbnRzIGFyZSBzdGlsbCBlbmFibGVkKQoJCQkvLyBJRTggdGhyb3dzIGVycm9yIGhlcmUgYW5kIHdpbGwgbm90IHNlZSBsYXRlciB0ZXN0cwoJCQlpZiAoICFkaXYucXVlcnlTZWxlY3RvckFsbCgiOmVuYWJsZWQiKS5sZW5ndGggKSB7CgkJCQlyYnVnZ3lRU0EucHVzaCggIjplbmFibGVkIiwgIjpkaXNhYmxlZCIgKTsKCQkJfQoKCQkJLy8gT3BlcmEgMTAtMTEgZG9lcyBub3QgdGhyb3cgb24gcG9zdC1jb21tYSBpbnZhbGlkIHBzZXVkb3MKCQkJZGl2LnF1ZXJ5U2VsZWN0b3JBbGwoIiosOngiKTsKCQkJcmJ1Z2d5UVNBLnB1c2goIiwuKjoiKTsKCQl9KTsKCX0KCglpZiAoIChzdXBwb3J0Lm1hdGNoZXNTZWxlY3RvciA9IHJuYXRpdmUudGVzdCggKG1hdGNoZXMgPSBkb2NFbGVtLm1hdGNoZXMgfHwKCQlkb2NFbGVtLndlYmtpdE1hdGNoZXNTZWxlY3RvciB8fAoJCWRvY0VsZW0ubW96TWF0Y2hlc1NlbGVjdG9yIHx8CgkJZG9jRWxlbS5vTWF0Y2hlc1NlbGVjdG9yIHx8CgkJZG9jRWxlbS5tc01hdGNoZXNTZWxlY3RvcikgKSkgKSB7CgoJCWFzc2VydChmdW5jdGlvbiggZGl2ICkgewoJCQkvLyBDaGVjayB0byBzZWUgaWYgaXQncyBwb3NzaWJsZSB0byBkbyBtYXRjaGVzU2VsZWN0b3IKCQkJLy8gb24gYSBkaXNjb25uZWN0ZWQgbm9kZSAoSUUgOSkKCQkJc3VwcG9ydC5kaXNjb25uZWN0ZWRNYXRjaCA9IG1hdGNoZXMuY2FsbCggZGl2LCAiZGl2IiApOwoKCQkJLy8gVGhpcyBzaG91bGQgZmFpbCB3aXRoIGFuIGV4Y2VwdGlvbgoJCQkvLyBHZWNrbyBkb2VzIG5vdCBlcnJvciwgcmV0dXJucyBmYWxzZSBpbnN0ZWFkCgkJCW1hdGNoZXMuY2FsbCggZGl2LCAiW3MhPScnXTp4IiApOwoJCQlyYnVnZ3lNYXRjaGVzLnB1c2goICIhPSIsIHBzZXVkb3MgKTsKCQl9KTsKCX0KCglyYnVnZ3lRU0EgPSByYnVnZ3lRU0EubGVuZ3RoICYmIG5ldyBSZWdFeHAoIHJidWdneVFTQS5qb2luKCJ8IikgKTsKCXJidWdneU1hdGNoZXMgPSByYnVnZ3lNYXRjaGVzLmxlbmd0aCAmJiBuZXcgUmVnRXhwKCByYnVnZ3lNYXRjaGVzLmpvaW4oInwiKSApOwoKCS8qIENvbnRhaW5zCgktLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCgloYXNDb21wYXJlID0gcm5hdGl2ZS50ZXN0KCBkb2NFbGVtLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uICk7CgoJLy8gRWxlbWVudCBjb250YWlucyBhbm90aGVyCgkvLyBQdXJwb3NlZnVsbHkgZG9lcyBub3QgaW1wbGVtZW50IGluY2x1c2l2ZSBkZXNjZW5kZW50CgkvLyBBcyBpbiwgYW4gZWxlbWVudCBkb2VzIG5vdCBjb250YWluIGl0c2VsZgoJY29udGFpbnMgPSBoYXNDb21wYXJlIHx8IHJuYXRpdmUudGVzdCggZG9jRWxlbS5jb250YWlucyApID8KCQlmdW5jdGlvbiggYSwgYiApIHsKCQkJdmFyIGFkb3duID0gYS5ub2RlVHlwZSA9PT0gOSA/IGEuZG9jdW1lbnRFbGVtZW50IDogYSwKCQkJCWJ1cCA9IGIgJiYgYi5wYXJlbnROb2RlOwoJCQlyZXR1cm4gYSA9PT0gYnVwIHx8ICEhKCBidXAgJiYgYnVwLm5vZGVUeXBlID09PSAxICYmICgKCQkJCWFkb3duLmNvbnRhaW5zID8KCQkJCQlhZG93bi5jb250YWlucyggYnVwICkgOgoJCQkJCWEuY29tcGFyZURvY3VtZW50UG9zaXRpb24gJiYgYS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggYnVwICkgJiAxNgoJCQkpKTsKCQl9IDoKCQlmdW5jdGlvbiggYSwgYiApIHsKCQkJaWYgKCBiICkgewoJCQkJd2hpbGUgKCAoYiA9IGIucGFyZW50Tm9kZSkgKSB7CgkJCQkJaWYgKCBiID09PSBhICkgewoJCQkJCQlyZXR1cm4gdHJ1ZTsKCQkJCQl9CgkJCQl9CgkJCX0KCQkJcmV0dXJuIGZhbHNlOwoJCX07CgoJLyogU29ydGluZwoJLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwoKCS8vIERvY3VtZW50IG9yZGVyIHNvcnRpbmcKCXNvcnRPcmRlciA9IGhhc0NvbXBhcmUgPwoJZnVuY3Rpb24oIGEsIGIgKSB7CgoJCS8vIEZsYWcgZm9yIGR1cGxpY2F0ZSByZW1vdmFsCgkJaWYgKCBhID09PSBiICkgewoJCQloYXNEdXBsaWNhdGUgPSB0cnVlOwoJCQlyZXR1cm4gMDsKCQl9CgoJCS8vIFNvcnQgb24gbWV0aG9kIGV4aXN0ZW5jZSBpZiBvbmx5IG9uZSBpbnB1dCBoYXMgY29tcGFyZURvY3VtZW50UG9zaXRpb24KCQl2YXIgY29tcGFyZSA9ICFhLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uIC0gIWIuY29tcGFyZURvY3VtZW50UG9zaXRpb247CgkJaWYgKCBjb21wYXJlICkgewoJCQlyZXR1cm4gY29tcGFyZTsKCQl9CgoJCS8vIENhbGN1bGF0ZSBwb3NpdGlvbiBpZiBib3RoIGlucHV0cyBiZWxvbmcgdG8gdGhlIHNhbWUgZG9jdW1lbnQKCQljb21wYXJlID0gKCBhLm93bmVyRG9jdW1lbnQgfHwgYSApID09PSAoIGIub3duZXJEb2N1bWVudCB8fCBiICkgPwoJCQlhLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKCBiICkgOgoKCQkJLy8gT3RoZXJ3aXNlIHdlIGtub3cgdGhleSBhcmUgZGlzY29ubmVjdGVkCgkJCTE7CgoJCS8vIERpc2Nvbm5lY3RlZCBub2RlcwoJCWlmICggY29tcGFyZSAmIDEgfHwKCQkJKCFzdXBwb3J0LnNvcnREZXRhY2hlZCAmJiBiLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKCBhICkgPT09IGNvbXBhcmUpICkgewoKCQkJLy8gQ2hvb3NlIHRoZSBmaXJzdCBlbGVtZW50IHRoYXQgaXMgcmVsYXRlZCB0byBvdXIgcHJlZmVycmVkIGRvY3VtZW50CgkJCWlmICggYSA9PT0gZG9jIHx8IGEub3duZXJEb2N1bWVudCA9PT0gcHJlZmVycmVkRG9jICYmIGNvbnRhaW5zKHByZWZlcnJlZERvYywgYSkgKSB7CgkJCQlyZXR1cm4gLTE7CgkJCX0KCQkJaWYgKCBiID09PSBkb2MgfHwgYi5vd25lckRvY3VtZW50ID09PSBwcmVmZXJyZWREb2MgJiYgY29udGFpbnMocHJlZmVycmVkRG9jLCBiKSApIHsKCQkJCXJldHVybiAxOwoJCQl9CgoJCQkvLyBNYWludGFpbiBvcmlnaW5hbCBvcmRlcgoJCQlyZXR1cm4gc29ydElucHV0ID8KCQkJCSggaW5kZXhPZi5jYWxsKCBzb3J0SW5wdXQsIGEgKSAtIGluZGV4T2YuY2FsbCggc29ydElucHV0LCBiICkgKSA6CgkJCQkwOwoJCX0KCgkJcmV0dXJuIGNvbXBhcmUgJiA0ID8gLTEgOiAxOwoJfSA6CglmdW5jdGlvbiggYSwgYiApIHsKCQkvLyBFeGl0IGVhcmx5IGlmIHRoZSBub2RlcyBhcmUgaWRlbnRpY2FsCgkJaWYgKCBhID09PSBiICkgewoJCQloYXNEdXBsaWNhdGUgPSB0cnVlOwoJCQlyZXR1cm4gMDsKCQl9CgoJCXZhciBjdXIsCgkJCWkgPSAwLAoJCQlhdXAgPSBhLnBhcmVudE5vZGUsCgkJCWJ1cCA9IGIucGFyZW50Tm9kZSwKCQkJYXAgPSBbIGEgXSwKCQkJYnAgPSBbIGIgXTsKCgkJLy8gUGFyZW50bGVzcyBub2RlcyBhcmUgZWl0aGVyIGRvY3VtZW50cyBvciBkaXNjb25uZWN0ZWQKCQlpZiAoICFhdXAgfHwgIWJ1cCApIHsKCQkJcmV0dXJuIGEgPT09IGRvYyA/IC0xIDoKCQkJCWIgPT09IGRvYyA/IDEgOgoJCQkJYXVwID8gLTEgOgoJCQkJYnVwID8gMSA6CgkJCQlzb3J0SW5wdXQgPwoJCQkJKCBpbmRleE9mLmNhbGwoIHNvcnRJbnB1dCwgYSApIC0gaW5kZXhPZi5jYWxsKCBzb3J0SW5wdXQsIGIgKSApIDoKCQkJCTA7CgoJCS8vIElmIHRoZSBub2RlcyBhcmUgc2libGluZ3MsIHdlIGNhbiBkbyBhIHF1aWNrIGNoZWNrCgkJfSBlbHNlIGlmICggYXVwID09PSBidXAgKSB7CgkJCXJldHVybiBzaWJsaW5nQ2hlY2soIGEsIGIgKTsKCQl9CgoJCS8vIE90aGVyd2lzZSB3ZSBuZWVkIGZ1bGwgbGlzdHMgb2YgdGhlaXIgYW5jZXN0b3JzIGZvciBjb21wYXJpc29uCgkJY3VyID0gYTsKCQl3aGlsZSAoIChjdXIgPSBjdXIucGFyZW50Tm9kZSkgKSB7CgkJCWFwLnVuc2hpZnQoIGN1ciApOwoJCX0KCQljdXIgPSBiOwoJCXdoaWxlICggKGN1ciA9IGN1ci5wYXJlbnROb2RlKSApIHsKCQkJYnAudW5zaGlmdCggY3VyICk7CgkJfQoKCQkvLyBXYWxrIGRvd24gdGhlIHRyZWUgbG9va2luZyBmb3IgYSBkaXNjcmVwYW5jeQoJCXdoaWxlICggYXBbaV0gPT09IGJwW2ldICkgewoJCQlpKys7CgkJfQoKCQlyZXR1cm4gaSA/CgkJCS8vIERvIGEgc2libGluZyBjaGVjayBpZiB0aGUgbm9kZXMgaGF2ZSBhIGNvbW1vbiBhbmNlc3RvcgoJCQlzaWJsaW5nQ2hlY2soIGFwW2ldLCBicFtpXSApIDoKCgkJCS8vIE90aGVyd2lzZSBub2RlcyBpbiBvdXIgZG9jdW1lbnQgc29ydCBmaXJzdAoJCQlhcFtpXSA9PT0gcHJlZmVycmVkRG9jID8gLTEgOgoJCQlicFtpXSA9PT0gcHJlZmVycmVkRG9jID8gMSA6CgkJCTA7Cgl9OwoKCXJldHVybiBkb2M7Cn07CgpTaXp6bGUubWF0Y2hlcyA9IGZ1bmN0aW9uKCBleHByLCBlbGVtZW50cyApIHsKCXJldHVybiBTaXp6bGUoIGV4cHIsIG51bGwsIG51bGwsIGVsZW1lbnRzICk7Cn07CgpTaXp6bGUubWF0Y2hlc1NlbGVjdG9yID0gZnVuY3Rpb24oIGVsZW0sIGV4cHIgKSB7CgkvLyBTZXQgZG9jdW1lbnQgdmFycyBpZiBuZWVkZWQKCWlmICggKCBlbGVtLm93bmVyRG9jdW1lbnQgfHwgZWxlbSApICE9PSBkb2N1bWVudCApIHsKCQlzZXREb2N1bWVudCggZWxlbSApOwoJfQoKCS8vIE1ha2Ugc3VyZSB0aGF0IGF0dHJpYnV0ZSBzZWxlY3RvcnMgYXJlIHF1b3RlZAoJZXhwciA9IGV4cHIucmVwbGFjZSggcmF0dHJpYnV0ZVF1b3RlcywgIj0nJDEnXSIgKTsKCglpZiAoIHN1cHBvcnQubWF0Y2hlc1NlbGVjdG9yICYmIGRvY3VtZW50SXNIVE1MICYmCgkJKCAhcmJ1Z2d5TWF0Y2hlcyB8fCAhcmJ1Z2d5TWF0Y2hlcy50ZXN0KCBleHByICkgKSAmJgoJCSggIXJidWdneVFTQSAgICAgfHwgIXJidWdneVFTQS50ZXN0KCBleHByICkgKSApIHsKCgkJdHJ5IHsKCQkJdmFyIHJldCA9IG1hdGNoZXMuY2FsbCggZWxlbSwgZXhwciApOwoKCQkJLy8gSUUgOSdzIG1hdGNoZXNTZWxlY3RvciByZXR1cm5zIGZhbHNlIG9uIGRpc2Nvbm5lY3RlZCBub2RlcwoJCQlpZiAoIHJldCB8fCBzdXBwb3J0LmRpc2Nvbm5lY3RlZE1hdGNoIHx8CgkJCQkJLy8gQXMgd2VsbCwgZGlzY29ubmVjdGVkIG5vZGVzIGFyZSBzYWlkIHRvIGJlIGluIGEgZG9jdW1lbnQKCQkJCQkvLyBmcmFnbWVudCBpbiBJRSA5CgkJCQkJZWxlbS5kb2N1bWVudCAmJiBlbGVtLmRvY3VtZW50Lm5vZGVUeXBlICE9PSAxMSApIHsKCQkJCXJldHVybiByZXQ7CgkJCX0KCQl9IGNhdGNoKGUpIHt9Cgl9CgoJcmV0dXJuIFNpenpsZSggZXhwciwgZG9jdW1lbnQsIG51bGwsIFsgZWxlbSBdICkubGVuZ3RoID4gMDsKfTsKClNpenpsZS5jb250YWlucyA9IGZ1bmN0aW9uKCBjb250ZXh0LCBlbGVtICkgewoJLy8gU2V0IGRvY3VtZW50IHZhcnMgaWYgbmVlZGVkCglpZiAoICggY29udGV4dC5vd25lckRvY3VtZW50IHx8IGNvbnRleHQgKSAhPT0gZG9jdW1lbnQgKSB7CgkJc2V0RG9jdW1lbnQoIGNvbnRleHQgKTsKCX0KCXJldHVybiBjb250YWlucyggY29udGV4dCwgZWxlbSApOwp9OwoKU2l6emxlLmF0dHIgPSBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHsKCS8vIFNldCBkb2N1bWVudCB2YXJzIGlmIG5lZWRlZAoJaWYgKCAoIGVsZW0ub3duZXJEb2N1bWVudCB8fCBlbGVtICkgIT09IGRvY3VtZW50ICkgewoJCXNldERvY3VtZW50KCBlbGVtICk7Cgl9CgoJdmFyIGZuID0gRXhwci5hdHRySGFuZGxlWyBuYW1lLnRvTG93ZXJDYXNlKCkgXSwKCQkvLyBEb24ndCBnZXQgZm9vbGVkIGJ5IE9iamVjdC5wcm90b3R5cGUgcHJvcGVydGllcyAoalF1ZXJ5ICMxMzgwNykKCQl2YWwgPSBmbiAmJiBoYXNPd24uY2FsbCggRXhwci5hdHRySGFuZGxlLCBuYW1lLnRvTG93ZXJDYXNlKCkgKSA/CgkJCWZuKCBlbGVtLCBuYW1lLCAhZG9jdW1lbnRJc0hUTUwgKSA6CgkJCXVuZGVmaW5lZDsKCglyZXR1cm4gdmFsICE9PSB1bmRlZmluZWQgPwoJCXZhbCA6CgkJc3VwcG9ydC5hdHRyaWJ1dGVzIHx8ICFkb2N1bWVudElzSFRNTCA/CgkJCWVsZW0uZ2V0QXR0cmlidXRlKCBuYW1lICkgOgoJCQkodmFsID0gZWxlbS5nZXRBdHRyaWJ1dGVOb2RlKG5hbWUpKSAmJiB2YWwuc3BlY2lmaWVkID8KCQkJCXZhbC52YWx1ZSA6CgkJCQludWxsOwp9OwoKU2l6emxlLmVycm9yID0gZnVuY3Rpb24oIG1zZyApIHsKCXRocm93IG5ldyBFcnJvciggIlN5bnRheCBlcnJvciwgdW5yZWNvZ25pemVkIGV4cHJlc3Npb246ICIgKyBtc2cgKTsKfTsKCi8qKgogKiBEb2N1bWVudCBzb3J0aW5nIGFuZCByZW1vdmluZyBkdXBsaWNhdGVzCiAqIEBwYXJhbSB7QXJyYXlMaWtlfSByZXN1bHRzCiAqLwpTaXp6bGUudW5pcXVlU29ydCA9IGZ1bmN0aW9uKCByZXN1bHRzICkgewoJdmFyIGVsZW0sCgkJZHVwbGljYXRlcyA9IFtdLAoJCWogPSAwLAoJCWkgPSAwOwoKCS8vIFVubGVzcyB3ZSAqa25vdyogd2UgY2FuIGRldGVjdCBkdXBsaWNhdGVzLCBhc3N1bWUgdGhlaXIgcHJlc2VuY2UKCWhhc0R1cGxpY2F0ZSA9ICFzdXBwb3J0LmRldGVjdER1cGxpY2F0ZXM7Cglzb3J0SW5wdXQgPSAhc3VwcG9ydC5zb3J0U3RhYmxlICYmIHJlc3VsdHMuc2xpY2UoIDAgKTsKCXJlc3VsdHMuc29ydCggc29ydE9yZGVyICk7CgoJaWYgKCBoYXNEdXBsaWNhdGUgKSB7CgkJd2hpbGUgKCAoZWxlbSA9IHJlc3VsdHNbaSsrXSkgKSB7CgkJCWlmICggZWxlbSA9PT0gcmVzdWx0c1sgaSBdICkgewoJCQkJaiA9IGR1cGxpY2F0ZXMucHVzaCggaSApOwoJCQl9CgkJfQoJCXdoaWxlICggai0tICkgewoJCQlyZXN1bHRzLnNwbGljZSggZHVwbGljYXRlc1sgaiBdLCAxICk7CgkJfQoJfQoKCS8vIENsZWFyIGlucHV0IGFmdGVyIHNvcnRpbmcgdG8gcmVsZWFzZSBvYmplY3RzCgkvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2pxdWVyeS9zaXp6bGUvcHVsbC8yMjUKCXNvcnRJbnB1dCA9IG51bGw7CgoJcmV0dXJuIHJlc3VsdHM7Cn07CgovKioKICogVXRpbGl0eSBmdW5jdGlvbiBmb3IgcmV0cmlldmluZyB0aGUgdGV4dCB2YWx1ZSBvZiBhbiBhcnJheSBvZiBET00gbm9kZXMKICogQHBhcmFtIHtBcnJheXxFbGVtZW50fSBlbGVtCiAqLwpnZXRUZXh0ID0gU2l6emxlLmdldFRleHQgPSBmdW5jdGlvbiggZWxlbSApIHsKCXZhciBub2RlLAoJCXJldCA9ICIiLAoJCWkgPSAwLAoJCW5vZGVUeXBlID0gZWxlbS5ub2RlVHlwZTsKCglpZiAoICFub2RlVHlwZSApIHsKCQkvLyBJZiBubyBub2RlVHlwZSwgdGhpcyBpcyBleHBlY3RlZCB0byBiZSBhbiBhcnJheQoJCXdoaWxlICggKG5vZGUgPSBlbGVtW2krK10pICkgewoJCQkvLyBEbyBub3QgdHJhdmVyc2UgY29tbWVudCBub2RlcwoJCQlyZXQgKz0gZ2V0VGV4dCggbm9kZSApOwoJCX0KCX0gZWxzZSBpZiAoIG5vZGVUeXBlID09PSAxIHx8IG5vZGVUeXBlID09PSA5IHx8IG5vZGVUeXBlID09PSAxMSApIHsKCQkvLyBVc2UgdGV4dENvbnRlbnQgZm9yIGVsZW1lbnRzCgkJLy8gaW5uZXJUZXh0IHVzYWdlIHJlbW92ZWQgZm9yIGNvbnNpc3RlbmN5IG9mIG5ldyBsaW5lcyAoalF1ZXJ5ICMxMTE1MykKCQlpZiAoIHR5cGVvZiBlbGVtLnRleHRDb250ZW50ID09PSAic3RyaW5nIiApIHsKCQkJcmV0dXJuIGVsZW0udGV4dENvbnRlbnQ7CgkJfSBlbHNlIHsKCQkJLy8gVHJhdmVyc2UgaXRzIGNoaWxkcmVuCgkJCWZvciAoIGVsZW0gPSBlbGVtLmZpcnN0Q2hpbGQ7IGVsZW07IGVsZW0gPSBlbGVtLm5leHRTaWJsaW5nICkgewoJCQkJcmV0ICs9IGdldFRleHQoIGVsZW0gKTsKCQkJfQoJCX0KCX0gZWxzZSBpZiAoIG5vZGVUeXBlID09PSAzIHx8IG5vZGVUeXBlID09PSA0ICkgewoJCXJldHVybiBlbGVtLm5vZGVWYWx1ZTsKCX0KCS8vIERvIG5vdCBpbmNsdWRlIGNvbW1lbnQgb3IgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbiBub2RlcwoKCXJldHVybiByZXQ7Cn07CgpFeHByID0gU2l6emxlLnNlbGVjdG9ycyA9IHsKCgkvLyBDYW4gYmUgYWRqdXN0ZWQgYnkgdGhlIHVzZXIKCWNhY2hlTGVuZ3RoOiA1MCwKCgljcmVhdGVQc2V1ZG86IG1hcmtGdW5jdGlvbiwKCgltYXRjaDogbWF0Y2hFeHByLAoKCWF0dHJIYW5kbGU6IHt9LAoKCWZpbmQ6IHt9LAoKCXJlbGF0aXZlOiB7CgkJIj4iOiB7IGRpcjogInBhcmVudE5vZGUiLCBmaXJzdDogdHJ1ZSB9LAoJCSIgIjogeyBkaXI6ICJwYXJlbnROb2RlIiB9LAoJCSIrIjogeyBkaXI6ICJwcmV2aW91c1NpYmxpbmciLCBmaXJzdDogdHJ1ZSB9LAoJCSJ+IjogeyBkaXI6ICJwcmV2aW91c1NpYmxpbmciIH0KCX0sCgoJcHJlRmlsdGVyOiB7CgkJIkFUVFIiOiBmdW5jdGlvbiggbWF0Y2ggKSB7CgkJCW1hdGNoWzFdID0gbWF0Y2hbMV0ucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKTsKCgkJCS8vIE1vdmUgdGhlIGdpdmVuIHZhbHVlIHRvIG1hdGNoWzNdIHdoZXRoZXIgcXVvdGVkIG9yIHVucXVvdGVkCgkJCW1hdGNoWzNdID0gKCBtYXRjaFszXSB8fCBtYXRjaFs0XSB8fCBtYXRjaFs1XSB8fCAiIiApLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICk7CgoJCQlpZiAoIG1hdGNoWzJdID09PSAifj0iICkgewoJCQkJbWF0Y2hbM10gPSAiICIgKyBtYXRjaFszXSArICIgIjsKCQkJfQoKCQkJcmV0dXJuIG1hdGNoLnNsaWNlKCAwLCA0ICk7CgkJfSwKCgkJIkNISUxEIjogZnVuY3Rpb24oIG1hdGNoICkgewoJCQkvKiBtYXRjaGVzIGZyb20gbWF0Y2hFeHByWyJDSElMRCJdCgkJCQkxIHR5cGUgKG9ubHl8bnRofC4uLikKCQkJCTIgd2hhdCAoY2hpbGR8b2YtdHlwZSkKCQkJCTMgYXJndW1lbnQgKGV2ZW58b2RkfFxkKnxcZCpuKFsrLV1cZCspP3wuLi4pCgkJCQk0IHhuLWNvbXBvbmVudCBvZiB4bit5IGFyZ3VtZW50IChbKy1dP1xkKm58KQoJCQkJNSBzaWduIG9mIHhuLWNvbXBvbmVudAoJCQkJNiB4IG9mIHhuLWNvbXBvbmVudAoJCQkJNyBzaWduIG9mIHktY29tcG9uZW50CgkJCQk4IHkgb2YgeS1jb21wb25lbnQKCQkJKi8KCQkJbWF0Y2hbMV0gPSBtYXRjaFsxXS50b0xvd2VyQ2FzZSgpOwoKCQkJaWYgKCBtYXRjaFsxXS5zbGljZSggMCwgMyApID09PSAibnRoIiApIHsKCQkJCS8vIG50aC0qIHJlcXVpcmVzIGFyZ3VtZW50CgkJCQlpZiAoICFtYXRjaFszXSApIHsKCQkJCQlTaXp6bGUuZXJyb3IoIG1hdGNoWzBdICk7CgkJCQl9CgoJCQkJLy8gbnVtZXJpYyB4IGFuZCB5IHBhcmFtZXRlcnMgZm9yIEV4cHIuZmlsdGVyLkNISUxECgkJCQkvLyByZW1lbWJlciB0aGF0IGZhbHNlL3RydWUgY2FzdCByZXNwZWN0aXZlbHkgdG8gMC8xCgkJCQltYXRjaFs0XSA9ICsoIG1hdGNoWzRdID8gbWF0Y2hbNV0gKyAobWF0Y2hbNl0gfHwgMSkgOiAyICogKCBtYXRjaFszXSA9PT0gImV2ZW4iIHx8IG1hdGNoWzNdID09PSAib2RkIiApICk7CgkJCQltYXRjaFs1XSA9ICsoICggbWF0Y2hbN10gKyBtYXRjaFs4XSApIHx8IG1hdGNoWzNdID09PSAib2RkIiApOwoKCQkJLy8gb3RoZXIgdHlwZXMgcHJvaGliaXQgYXJndW1lbnRzCgkJCX0gZWxzZSBpZiAoIG1hdGNoWzNdICkgewoJCQkJU2l6emxlLmVycm9yKCBtYXRjaFswXSApOwoJCQl9CgoJCQlyZXR1cm4gbWF0Y2g7CgkJfSwKCgkJIlBTRVVETyI6IGZ1bmN0aW9uKCBtYXRjaCApIHsKCQkJdmFyIGV4Y2VzcywKCQkJCXVucXVvdGVkID0gIW1hdGNoWzZdICYmIG1hdGNoWzJdOwoKCQkJaWYgKCBtYXRjaEV4cHJbIkNISUxEIl0udGVzdCggbWF0Y2hbMF0gKSApIHsKCQkJCXJldHVybiBudWxsOwoJCQl9CgoJCQkvLyBBY2NlcHQgcXVvdGVkIGFyZ3VtZW50cyBhcy1pcwoJCQlpZiAoIG1hdGNoWzNdICkgewoJCQkJbWF0Y2hbMl0gPSBtYXRjaFs0XSB8fCBtYXRjaFs1XSB8fCAiIjsKCgkJCS8vIFN0cmlwIGV4Y2VzcyBjaGFyYWN0ZXJzIGZyb20gdW5xdW90ZWQgYXJndW1lbnRzCgkJCX0gZWxzZSBpZiAoIHVucXVvdGVkICYmIHJwc2V1ZG8udGVzdCggdW5xdW90ZWQgKSAmJgoJCQkJLy8gR2V0IGV4Y2VzcyBmcm9tIHRva2VuaXplIChyZWN1cnNpdmVseSkKCQkJCShleGNlc3MgPSB0b2tlbml6ZSggdW5xdW90ZWQsIHRydWUgKSkgJiYKCQkJCS8vIGFkdmFuY2UgdG8gdGhlIG5leHQgY2xvc2luZyBwYXJlbnRoZXNpcwoJCQkJKGV4Y2VzcyA9IHVucXVvdGVkLmluZGV4T2YoICIpIiwgdW5xdW90ZWQubGVuZ3RoIC0gZXhjZXNzICkgLSB1bnF1b3RlZC5sZW5ndGgpICkgewoKCQkJCS8vIGV4Y2VzcyBpcyBhIG5lZ2F0aXZlIGluZGV4CgkJCQltYXRjaFswXSA9IG1hdGNoWzBdLnNsaWNlKCAwLCBleGNlc3MgKTsKCQkJCW1hdGNoWzJdID0gdW5xdW90ZWQuc2xpY2UoIDAsIGV4Y2VzcyApOwoJCQl9CgoJCQkvLyBSZXR1cm4gb25seSBjYXB0dXJlcyBuZWVkZWQgYnkgdGhlIHBzZXVkbyBmaWx0ZXIgbWV0aG9kICh0eXBlIGFuZCBhcmd1bWVudCkKCQkJcmV0dXJuIG1hdGNoLnNsaWNlKCAwLCAzICk7CgkJfQoJfSwKCglmaWx0ZXI6IHsKCgkJIlRBRyI6IGZ1bmN0aW9uKCBub2RlTmFtZVNlbGVjdG9yICkgewoJCQl2YXIgbm9kZU5hbWUgPSBub2RlTmFtZVNlbGVjdG9yLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICkudG9Mb3dlckNhc2UoKTsKCQkJcmV0dXJuIG5vZGVOYW1lU2VsZWN0b3IgPT09ICIqIiA/CgkJCQlmdW5jdGlvbigpIHsgcmV0dXJuIHRydWU7IH0gOgoJCQkJZnVuY3Rpb24oIGVsZW0gKSB7CgkJCQkJcmV0dXJuIGVsZW0ubm9kZU5hbWUgJiYgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBub2RlTmFtZTsKCQkJCX07CgkJfSwKCgkJIkNMQVNTIjogZnVuY3Rpb24oIGNsYXNzTmFtZSApIHsKCQkJdmFyIHBhdHRlcm4gPSBjbGFzc0NhY2hlWyBjbGFzc05hbWUgKyAiICIgXTsKCgkJCXJldHVybiBwYXR0ZXJuIHx8CgkJCQkocGF0dGVybiA9IG5ldyBSZWdFeHAoICIoXnwiICsgd2hpdGVzcGFjZSArICIpIiArIGNsYXNzTmFtZSArICIoIiArIHdoaXRlc3BhY2UgKyAifCQpIiApKSAmJgoJCQkJY2xhc3NDYWNoZSggY2xhc3NOYW1lLCBmdW5jdGlvbiggZWxlbSApIHsKCQkJCQlyZXR1cm4gcGF0dGVybi50ZXN0KCB0eXBlb2YgZWxlbS5jbGFzc05hbWUgPT09ICJzdHJpbmciICYmIGVsZW0uY2xhc3NOYW1lIHx8IHR5cGVvZiBlbGVtLmdldEF0dHJpYnV0ZSAhPT0gc3RydW5kZWZpbmVkICYmIGVsZW0uZ2V0QXR0cmlidXRlKCJjbGFzcyIpIHx8ICIiICk7CgkJCQl9KTsKCQl9LAoKCQkiQVRUUiI6IGZ1bmN0aW9uKCBuYW1lLCBvcGVyYXRvciwgY2hlY2sgKSB7CgkJCXJldHVybiBmdW5jdGlvbiggZWxlbSApIHsKCQkJCXZhciByZXN1bHQgPSBTaXp6bGUuYXR0ciggZWxlbSwgbmFtZSApOwoKCQkJCWlmICggcmVzdWx0ID09IG51bGwgKSB7CgkJCQkJcmV0dXJuIG9wZXJhdG9yID09PSAiIT0iOwoJCQkJfQoJCQkJaWYgKCAhb3BlcmF0b3IgKSB7CgkJCQkJcmV0dXJuIHRydWU7CgkJCQl9CgoJCQkJcmVzdWx0ICs9ICIiOwoKCQkJCXJldHVybiBvcGVyYXRvciA9PT0gIj0iID8gcmVzdWx0ID09PSBjaGVjayA6CgkJCQkJb3BlcmF0b3IgPT09ICIhPSIgPyByZXN1bHQgIT09IGNoZWNrIDoKCQkJCQlvcGVyYXRvciA9PT0gIl49IiA/IGNoZWNrICYmIHJlc3VsdC5pbmRleE9mKCBjaGVjayApID09PSAwIDoKCQkJCQlvcGVyYXRvciA9PT0gIio9IiA/IGNoZWNrICYmIHJlc3VsdC5pbmRleE9mKCBjaGVjayApID4gLTEgOgoJCQkJCW9wZXJhdG9yID09PSAiJD0iID8gY2hlY2sgJiYgcmVzdWx0LnNsaWNlKCAtY2hlY2subGVuZ3RoICkgPT09IGNoZWNrIDoKCQkJCQlvcGVyYXRvciA9PT0gIn49IiA/ICggIiAiICsgcmVzdWx0ICsgIiAiICkuaW5kZXhPZiggY2hlY2sgKSA+IC0xIDoKCQkJCQlvcGVyYXRvciA9PT0gInw9IiA/IHJlc3VsdCA9PT0gY2hlY2sgfHwgcmVzdWx0LnNsaWNlKCAwLCBjaGVjay5sZW5ndGggKyAxICkgPT09IGNoZWNrICsgIi0iIDoKCQkJCQlmYWxzZTsKCQkJfTsKCQl9LAoKCQkiQ0hJTEQiOiBmdW5jdGlvbiggdHlwZSwgd2hhdCwgYXJndW1lbnQsIGZpcnN0LCBsYXN0ICkgewoJCQl2YXIgc2ltcGxlID0gdHlwZS5zbGljZSggMCwgMyApICE9PSAibnRoIiwKCQkJCWZvcndhcmQgPSB0eXBlLnNsaWNlKCAtNCApICE9PSAibGFzdCIsCgkJCQlvZlR5cGUgPSB3aGF0ID09PSAib2YtdHlwZSI7CgoJCQlyZXR1cm4gZmlyc3QgPT09IDEgJiYgbGFzdCA9PT0gMCA/CgoJCQkJLy8gU2hvcnRjdXQgZm9yIDpudGgtKihuKQoJCQkJZnVuY3Rpb24oIGVsZW0gKSB7CgkJCQkJcmV0dXJuICEhZWxlbS5wYXJlbnROb2RlOwoJCQkJfSA6CgoJCQkJZnVuY3Rpb24oIGVsZW0sIGNvbnRleHQsIHhtbCApIHsKCQkJCQl2YXIgY2FjaGUsIG91dGVyQ2FjaGUsIG5vZGUsIGRpZmYsIG5vZGVJbmRleCwgc3RhcnQsCgkJCQkJCWRpciA9IHNpbXBsZSAhPT0gZm9yd2FyZCA/ICJuZXh0U2libGluZyIgOiAicHJldmlvdXNTaWJsaW5nIiwKCQkJCQkJcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlLAoJCQkJCQluYW1lID0gb2ZUeXBlICYmIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSwKCQkJCQkJdXNlQ2FjaGUgPSAheG1sICYmICFvZlR5cGU7CgoJCQkJCWlmICggcGFyZW50ICkgewoKCQkJCQkJLy8gOihmaXJzdHxsYXN0fG9ubHkpLShjaGlsZHxvZi10eXBlKQoJCQkJCQlpZiAoIHNpbXBsZSApIHsKCQkJCQkJCXdoaWxlICggZGlyICkgewoJCQkJCQkJCW5vZGUgPSBlbGVtOwoJCQkJCQkJCXdoaWxlICggKG5vZGUgPSBub2RlWyBkaXIgXSkgKSB7CgkJCQkJCQkJCWlmICggb2ZUeXBlID8gbm9kZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBuYW1lIDogbm9kZS5ub2RlVHlwZSA9PT0gMSApIHsKCQkJCQkJCQkJCXJldHVybiBmYWxzZTsKCQkJCQkJCQkJfQoJCQkJCQkJCX0KCQkJCQkJCQkvLyBSZXZlcnNlIGRpcmVjdGlvbiBmb3IgOm9ubHktKiAoaWYgd2UgaGF2ZW4ndCB5ZXQgZG9uZSBzbykKCQkJCQkJCQlzdGFydCA9IGRpciA9IHR5cGUgPT09ICJvbmx5IiAmJiAhc3RhcnQgJiYgIm5leHRTaWJsaW5nIjsKCQkJCQkJCX0KCQkJCQkJCXJldHVybiB0cnVlOwoJCQkJCQl9CgoJCQkJCQlzdGFydCA9IFsgZm9yd2FyZCA/IHBhcmVudC5maXJzdENoaWxkIDogcGFyZW50Lmxhc3RDaGlsZCBdOwoKCQkJCQkJLy8gbm9uLXhtbCA6bnRoLWNoaWxkKC4uLikgc3RvcmVzIGNhY2hlIGRhdGEgb24gYHBhcmVudGAKCQkJCQkJaWYgKCBmb3J3YXJkICYmIHVzZUNhY2hlICkgewoJCQkJCQkJLy8gU2VlayBgZWxlbWAgZnJvbSBhIHByZXZpb3VzbHktY2FjaGVkIGluZGV4CgkJCQkJCQlvdXRlckNhY2hlID0gcGFyZW50WyBleHBhbmRvIF0gfHwgKHBhcmVudFsgZXhwYW5kbyBdID0ge30pOwoJCQkJCQkJY2FjaGUgPSBvdXRlckNhY2hlWyB0eXBlIF0gfHwgW107CgkJCQkJCQlub2RlSW5kZXggPSBjYWNoZVswXSA9PT0gZGlycnVucyAmJiBjYWNoZVsxXTsKCQkJCQkJCWRpZmYgPSBjYWNoZVswXSA9PT0gZGlycnVucyAmJiBjYWNoZVsyXTsKCQkJCQkJCW5vZGUgPSBub2RlSW5kZXggJiYgcGFyZW50LmNoaWxkTm9kZXNbIG5vZGVJbmRleCBdOwoKCQkJCQkJCXdoaWxlICggKG5vZGUgPSArK25vZGVJbmRleCAmJiBub2RlICYmIG5vZGVbIGRpciBdIHx8CgoJCQkJCQkJCS8vIEZhbGxiYWNrIHRvIHNlZWtpbmcgYGVsZW1gIGZyb20gdGhlIHN0YXJ0CgkJCQkJCQkJKGRpZmYgPSBub2RlSW5kZXggPSAwKSB8fCBzdGFydC5wb3AoKSkgKSB7CgoJCQkJCQkJCS8vIFdoZW4gZm91bmQsIGNhY2hlIGluZGV4ZXMgb24gYHBhcmVudGAgYW5kIGJyZWFrCgkJCQkJCQkJaWYgKCBub2RlLm5vZGVUeXBlID09PSAxICYmICsrZGlmZiAmJiBub2RlID09PSBlbGVtICkgewoJCQkJCQkJCQlvdXRlckNhY2hlWyB0eXBlIF0gPSBbIGRpcnJ1bnMsIG5vZGVJbmRleCwgZGlmZiBdOwoJCQkJCQkJCQlicmVhazsKCQkJCQkJCQl9CgkJCQkJCQl9CgoJCQkJCQkvLyBVc2UgcHJldmlvdXNseS1jYWNoZWQgZWxlbWVudCBpbmRleCBpZiBhdmFpbGFibGUKCQkJCQkJfSBlbHNlIGlmICggdXNlQ2FjaGUgJiYgKGNhY2hlID0gKGVsZW1bIGV4cGFuZG8gXSB8fCAoZWxlbVsgZXhwYW5kbyBdID0ge30pKVsgdHlwZSBdKSAmJiBjYWNoZVswXSA9PT0gZGlycnVucyApIHsKCQkJCQkJCWRpZmYgPSBjYWNoZVsxXTsKCgkJCQkJCS8vIHhtbCA6bnRoLWNoaWxkKC4uLikgb3IgOm50aC1sYXN0LWNoaWxkKC4uLikgb3IgOm50aCgtbGFzdCk/LW9mLXR5cGUoLi4uKQoJCQkJCQl9IGVsc2UgewoJCQkJCQkJLy8gVXNlIHRoZSBzYW1lIGxvb3AgYXMgYWJvdmUgdG8gc2VlayBgZWxlbWAgZnJvbSB0aGUgc3RhcnQKCQkJCQkJCXdoaWxlICggKG5vZGUgPSArK25vZGVJbmRleCAmJiBub2RlICYmIG5vZGVbIGRpciBdIHx8CgkJCQkJCQkJKGRpZmYgPSBub2RlSW5kZXggPSAwKSB8fCBzdGFydC5wb3AoKSkgKSB7CgoJCQkJCQkJCWlmICggKCBvZlR5cGUgPyBub2RlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IG5hbWUgOiBub2RlLm5vZGVUeXBlID09PSAxICkgJiYgKytkaWZmICkgewoJCQkJCQkJCQkvLyBDYWNoZSB0aGUgaW5kZXggb2YgZWFjaCBlbmNvdW50ZXJlZCBlbGVtZW50CgkJCQkJCQkJCWlmICggdXNlQ2FjaGUgKSB7CgkJCQkJCQkJCQkobm9kZVsgZXhwYW5kbyBdIHx8IChub2RlWyBleHBhbmRvIF0gPSB7fSkpWyB0eXBlIF0gPSBbIGRpcnJ1bnMsIGRpZmYgXTsKCQkJCQkJCQkJfQoKCQkJCQkJCQkJaWYgKCBub2RlID09PSBlbGVtICkgewoJCQkJCQkJCQkJYnJlYWs7CgkJCQkJCQkJCX0KCQkJCQkJCQl9CgkJCQkJCQl9CgkJCQkJCX0KCgkJCQkJCS8vIEluY29ycG9yYXRlIHRoZSBvZmZzZXQsIHRoZW4gY2hlY2sgYWdhaW5zdCBjeWNsZSBzaXplCgkJCQkJCWRpZmYgLT0gbGFzdDsKCQkJCQkJcmV0dXJuIGRpZmYgPT09IGZpcnN0IHx8ICggZGlmZiAlIGZpcnN0ID09PSAwICYmIGRpZmYgLyBmaXJzdCA+PSAwICk7CgkJCQkJfQoJCQkJfTsKCQl9LAoKCQkiUFNFVURPIjogZnVuY3Rpb24oIHBzZXVkbywgYXJndW1lbnQgKSB7CgkJCS8vIHBzZXVkby1jbGFzcyBuYW1lcyBhcmUgY2FzZS1pbnNlbnNpdGl2ZQoJCQkvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9zZWxlY3RvcnMvI3BzZXVkby1jbGFzc2VzCgkJCS8vIFByaW9yaXRpemUgYnkgY2FzZSBzZW5zaXRpdml0eSBpbiBjYXNlIGN1c3RvbSBwc2V1ZG9zIGFyZSBhZGRlZCB3aXRoIHVwcGVyY2FzZSBsZXR0ZXJzCgkJCS8vIFJlbWVtYmVyIHRoYXQgc2V0RmlsdGVycyBpbmhlcml0cyBmcm9tIHBzZXVkb3MKCQkJdmFyIGFyZ3MsCgkJCQlmbiA9IEV4cHIucHNldWRvc1sgcHNldWRvIF0gfHwgRXhwci5zZXRGaWx0ZXJzWyBwc2V1ZG8udG9Mb3dlckNhc2UoKSBdIHx8CgkJCQkJU2l6emxlLmVycm9yKCAidW5zdXBwb3J0ZWQgcHNldWRvOiAiICsgcHNldWRvICk7CgoJCQkvLyBUaGUgdXNlciBtYXkgdXNlIGNyZWF0ZVBzZXVkbyB0byBpbmRpY2F0ZSB0aGF0CgkJCS8vIGFyZ3VtZW50cyBhcmUgbmVlZGVkIHRvIGNyZWF0ZSB0aGUgZmlsdGVyIGZ1bmN0aW9uCgkJCS8vIGp1c3QgYXMgU2l6emxlIGRvZXMKCQkJaWYgKCBmblsgZXhwYW5kbyBdICkgewoJCQkJcmV0dXJuIGZuKCBhcmd1bWVudCApOwoJCQl9CgoJCQkvLyBCdXQgbWFpbnRhaW4gc3VwcG9ydCBmb3Igb2xkIHNpZ25hdHVyZXMKCQkJaWYgKCBmbi5sZW5ndGggPiAxICkgewoJCQkJYXJncyA9IFsgcHNldWRvLCBwc2V1ZG8sICIiLCBhcmd1bWVudCBdOwoJCQkJcmV0dXJuIEV4cHIuc2V0RmlsdGVycy5oYXNPd25Qcm9wZXJ0eSggcHNldWRvLnRvTG93ZXJDYXNlKCkgKSA/CgkJCQkJbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWVkLCBtYXRjaGVzICkgewoJCQkJCQl2YXIgaWR4LAoJCQkJCQkJbWF0Y2hlZCA9IGZuKCBzZWVkLCBhcmd1bWVudCApLAoJCQkJCQkJaSA9IG1hdGNoZWQubGVuZ3RoOwoJCQkJCQl3aGlsZSAoIGktLSApIHsKCQkJCQkJCWlkeCA9IGluZGV4T2YuY2FsbCggc2VlZCwgbWF0Y2hlZFtpXSApOwoJCQkJCQkJc2VlZFsgaWR4IF0gPSAhKCBtYXRjaGVzWyBpZHggXSA9IG1hdGNoZWRbaV0gKTsKCQkJCQkJfQoJCQkJCX0pIDoKCQkJCQlmdW5jdGlvbiggZWxlbSApIHsKCQkJCQkJcmV0dXJuIGZuKCBlbGVtLCAwLCBhcmdzICk7CgkJCQkJfTsKCQkJfQoKCQkJcmV0dXJuIGZuOwoJCX0KCX0sCgoJcHNldWRvczogewoJCS8vIFBvdGVudGlhbGx5IGNvbXBsZXggcHNldWRvcwoJCSJub3QiOiBtYXJrRnVuY3Rpb24oZnVuY3Rpb24oIHNlbGVjdG9yICkgewoJCQkvLyBUcmltIHRoZSBzZWxlY3RvciBwYXNzZWQgdG8gY29tcGlsZQoJCQkvLyB0byBhdm9pZCB0cmVhdGluZyBsZWFkaW5nIGFuZCB0cmFpbGluZwoJCQkvLyBzcGFjZXMgYXMgY29tYmluYXRvcnMKCQkJdmFyIGlucHV0ID0gW10sCgkJCQlyZXN1bHRzID0gW10sCgkJCQltYXRjaGVyID0gY29tcGlsZSggc2VsZWN0b3IucmVwbGFjZSggcnRyaW0sICIkMSIgKSApOwoKCQkJcmV0dXJuIG1hdGNoZXJbIGV4cGFuZG8gXSA/CgkJCQltYXJrRnVuY3Rpb24oZnVuY3Rpb24oIHNlZWQsIG1hdGNoZXMsIGNvbnRleHQsIHhtbCApIHsKCQkJCQl2YXIgZWxlbSwKCQkJCQkJdW5tYXRjaGVkID0gbWF0Y2hlciggc2VlZCwgbnVsbCwgeG1sLCBbXSApLAoJCQkJCQlpID0gc2VlZC5sZW5ndGg7CgoJCQkJCS8vIE1hdGNoIGVsZW1lbnRzIHVubWF0Y2hlZCBieSBgbWF0Y2hlcmAKCQkJCQl3aGlsZSAoIGktLSApIHsKCQkJCQkJaWYgKCAoZWxlbSA9IHVubWF0Y2hlZFtpXSkgKSB7CgkJCQkJCQlzZWVkW2ldID0gIShtYXRjaGVzW2ldID0gZWxlbSk7CgkJCQkJCX0KCQkJCQl9CgkJCQl9KSA6CgkJCQlmdW5jdGlvbiggZWxlbSwgY29udGV4dCwgeG1sICkgewoJCQkJCWlucHV0WzBdID0gZWxlbTsKCQkJCQltYXRjaGVyKCBpbnB1dCwgbnVsbCwgeG1sLCByZXN1bHRzICk7CgkJCQkJcmV0dXJuICFyZXN1bHRzLnBvcCgpOwoJCQkJfTsKCQl9KSwKCgkJImhhcyI6IG1hcmtGdW5jdGlvbihmdW5jdGlvbiggc2VsZWN0b3IgKSB7CgkJCXJldHVybiBmdW5jdGlvbiggZWxlbSApIHsKCQkJCXJldHVybiBTaXp6bGUoIHNlbGVjdG9yLCBlbGVtICkubGVuZ3RoID4gMDsKCQkJfTsKCQl9KSwKCgkJImNvbnRhaW5zIjogbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCB0ZXh0ICkgewoJCQlyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7CgkJCQlyZXR1cm4gKCBlbGVtLnRleHRDb250ZW50IHx8IGVsZW0uaW5uZXJUZXh0IHx8IGdldFRleHQoIGVsZW0gKSApLmluZGV4T2YoIHRleHQgKSA+IC0xOwoJCQl9OwoJCX0pLAoKCQkvLyAiV2hldGhlciBhbiBlbGVtZW50IGlzIHJlcHJlc2VudGVkIGJ5IGEgOmxhbmcoKSBzZWxlY3RvcgoJCS8vIGlzIGJhc2VkIHNvbGVseSBvbiB0aGUgZWxlbWVudCdzIGxhbmd1YWdlIHZhbHVlCgkJLy8gYmVpbmcgZXF1YWwgdG8gdGhlIGlkZW50aWZpZXIgQywKCQkvLyBvciBiZWdpbm5pbmcgd2l0aCB0aGUgaWRlbnRpZmllciBDIGltbWVkaWF0ZWx5IGZvbGxvd2VkIGJ5ICItIi4KCQkvLyBUaGUgbWF0Y2hpbmcgb2YgQyBhZ2FpbnN0IHRoZSBlbGVtZW50J3MgbGFuZ3VhZ2UgdmFsdWUgaXMgcGVyZm9ybWVkIGNhc2UtaW5zZW5zaXRpdmVseS4KCQkvLyBUaGUgaWRlbnRpZmllciBDIGRvZXMgbm90IGhhdmUgdG8gYmUgYSB2YWxpZCBsYW5ndWFnZSBuYW1lLiIKCQkvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9zZWxlY3RvcnMvI2xhbmctcHNldWRvCgkJImxhbmciOiBtYXJrRnVuY3Rpb24oIGZ1bmN0aW9uKCBsYW5nICkgewoJCQkvLyBsYW5nIHZhbHVlIG11c3QgYmUgYSB2YWxpZCBpZGVudGlmaWVyCgkJCWlmICggIXJpZGVudGlmaWVyLnRlc3QobGFuZyB8fCAiIikgKSB7CgkJCQlTaXp6bGUuZXJyb3IoICJ1bnN1cHBvcnRlZCBsYW5nOiAiICsgbGFuZyApOwoJCQl9CgkJCWxhbmcgPSBsYW5nLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICkudG9Mb3dlckNhc2UoKTsKCQkJcmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkgewoJCQkJdmFyIGVsZW1MYW5nOwoJCQkJZG8gewoJCQkJCWlmICggKGVsZW1MYW5nID0gZG9jdW1lbnRJc0hUTUwgPwoJCQkJCQllbGVtLmxhbmcgOgoJCQkJCQllbGVtLmdldEF0dHJpYnV0ZSgieG1sOmxhbmciKSB8fCBlbGVtLmdldEF0dHJpYnV0ZSgibGFuZyIpKSApIHsKCgkJCQkJCWVsZW1MYW5nID0gZWxlbUxhbmcudG9Mb3dlckNhc2UoKTsKCQkJCQkJcmV0dXJuIGVsZW1MYW5nID09PSBsYW5nIHx8IGVsZW1MYW5nLmluZGV4T2YoIGxhbmcgKyAiLSIgKSA9PT0gMDsKCQkJCQl9CgkJCQl9IHdoaWxlICggKGVsZW0gPSBlbGVtLnBhcmVudE5vZGUpICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgKTsKCQkJCXJldHVybiBmYWxzZTsKCQkJfTsKCQl9KSwKCgkJLy8gTWlzY2VsbGFuZW91cwoJCSJ0YXJnZXQiOiBmdW5jdGlvbiggZWxlbSApIHsKCQkJdmFyIGhhc2ggPSB3aW5kb3cubG9jYXRpb24gJiYgd2luZG93LmxvY2F0aW9uLmhhc2g7CgkJCXJldHVybiBoYXNoICYmIGhhc2guc2xpY2UoIDEgKSA9PT0gZWxlbS5pZDsKCQl9LAoKCQkicm9vdCI6IGZ1bmN0aW9uKCBlbGVtICkgewoJCQlyZXR1cm4gZWxlbSA9PT0gZG9jRWxlbTsKCQl9LAoKCQkiZm9jdXMiOiBmdW5jdGlvbiggZWxlbSApIHsKCQkJcmV0dXJuIGVsZW0gPT09IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgJiYgKCFkb2N1bWVudC5oYXNGb2N1cyB8fCBkb2N1bWVudC5oYXNGb2N1cygpKSAmJiAhIShlbGVtLnR5cGUgfHwgZWxlbS5ocmVmIHx8IH5lbGVtLnRhYkluZGV4KTsKCQl9LAoKCQkvLyBCb29sZWFuIHByb3BlcnRpZXMKCQkiZW5hYmxlZCI6IGZ1bmN0aW9uKCBlbGVtICkgewoJCQlyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gZmFsc2U7CgkJfSwKCgkJImRpc2FibGVkIjogZnVuY3Rpb24oIGVsZW0gKSB7CgkJCXJldHVybiBlbGVtLmRpc2FibGVkID09PSB0cnVlOwoJCX0sCgoJCSJjaGVja2VkIjogZnVuY3Rpb24oIGVsZW0gKSB7CgkJCS8vIEluIENTUzMsIDpjaGVja2VkIHNob3VsZCByZXR1cm4gYm90aCBjaGVja2VkIGFuZCBzZWxlY3RlZCBlbGVtZW50cwoJCQkvLyBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDExL1JFQy1jc3MzLXNlbGVjdG9ycy0yMDExMDkyOS8jY2hlY2tlZAoJCQl2YXIgbm9kZU5hbWUgPSBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7CgkJCXJldHVybiAobm9kZU5hbWUgPT09ICJpbnB1dCIgJiYgISFlbGVtLmNoZWNrZWQpIHx8IChub2RlTmFtZSA9PT0gIm9wdGlvbiIgJiYgISFlbGVtLnNlbGVjdGVkKTsKCQl9LAoKCQkic2VsZWN0ZWQiOiBmdW5jdGlvbiggZWxlbSApIHsKCQkJLy8gQWNjZXNzaW5nIHRoaXMgcHJvcGVydHkgbWFrZXMgc2VsZWN0ZWQtYnktZGVmYXVsdAoJCQkvLyBvcHRpb25zIGluIFNhZmFyaSB3b3JrIHByb3Blcmx5CgkJCWlmICggZWxlbS5wYXJlbnROb2RlICkgewoJCQkJZWxlbS5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXg7CgkJCX0KCgkJCXJldHVybiBlbGVtLnNlbGVjdGVkID09PSB0cnVlOwoJCX0sCgoJCS8vIENvbnRlbnRzCgkJImVtcHR5IjogZnVuY3Rpb24oIGVsZW0gKSB7CgkJCS8vIGh0dHA6Ly93d3cudzMub3JnL1RSL3NlbGVjdG9ycy8jZW1wdHktcHNldWRvCgkJCS8vIDplbXB0eSBpcyBuZWdhdGVkIGJ5IGVsZW1lbnQgKDEpIG9yIGNvbnRlbnQgbm9kZXMgKHRleHQ6IDM7IGNkYXRhOiA0OyBlbnRpdHkgcmVmOiA1KSwKCQkJLy8gICBidXQgbm90IGJ5IG90aGVycyAoY29tbWVudDogODsgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbjogNzsgZXRjLikKCQkJLy8gbm9kZVR5cGUgPCA2IHdvcmtzIGJlY2F1c2UgYXR0cmlidXRlcyAoMikgZG8gbm90IGFwcGVhciBhcyBjaGlsZHJlbgoJCQlmb3IgKCBlbGVtID0gZWxlbS5maXJzdENoaWxkOyBlbGVtOyBlbGVtID0gZWxlbS5uZXh0U2libGluZyApIHsKCQkJCWlmICggZWxlbS5ub2RlVHlwZSA8IDYgKSB7CgkJCQkJcmV0dXJuIGZhbHNlOwoJCQkJfQoJCQl9CgkJCXJldHVybiB0cnVlOwoJCX0sCgoJCSJwYXJlbnQiOiBmdW5jdGlvbiggZWxlbSApIHsKCQkJcmV0dXJuICFFeHByLnBzZXVkb3NbImVtcHR5Il0oIGVsZW0gKTsKCQl9LAoKCQkvLyBFbGVtZW50L2lucHV0IHR5cGVzCgkJImhlYWRlciI6IGZ1bmN0aW9uKCBlbGVtICkgewoJCQlyZXR1cm4gcmhlYWRlci50ZXN0KCBlbGVtLm5vZGVOYW1lICk7CgkJfSwKCgkJImlucHV0IjogZnVuY3Rpb24oIGVsZW0gKSB7CgkJCXJldHVybiByaW5wdXRzLnRlc3QoIGVsZW0ubm9kZU5hbWUgKTsKCQl9LAoKCQkiYnV0dG9uIjogZnVuY3Rpb24oIGVsZW0gKSB7CgkJCXZhciBuYW1lID0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOwoJCQlyZXR1cm4gbmFtZSA9PT0gImlucHV0IiAmJiBlbGVtLnR5cGUgPT09ICJidXR0b24iIHx8IG5hbWUgPT09ICJidXR0b24iOwoJCX0sCgoJCSJ0ZXh0IjogZnVuY3Rpb24oIGVsZW0gKSB7CgkJCXZhciBhdHRyOwoJCQlyZXR1cm4gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSAiaW5wdXQiICYmCgkJCQllbGVtLnR5cGUgPT09ICJ0ZXh0IiAmJgoKCQkJCS8vIFN1cHBvcnQ6IElFPDgKCQkJCS8vIE5ldyBIVE1MNSBhdHRyaWJ1dGUgdmFsdWVzIChlLmcuLCAic2VhcmNoIikgYXBwZWFyIHdpdGggZWxlbS50eXBlID09PSAidGV4dCIKCQkJCSggKGF0dHIgPSBlbGVtLmdldEF0dHJpYnV0ZSgidHlwZSIpKSA9PSBudWxsIHx8IGF0dHIudG9Mb3dlckNhc2UoKSA9PT0gInRleHQiICk7CgkJfSwKCgkJLy8gUG9zaXRpb24taW4tY29sbGVjdGlvbgoJCSJmaXJzdCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oKSB7CgkJCXJldHVybiBbIDAgXTsKCQl9KSwKCgkJImxhc3QiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCApIHsKCQkJcmV0dXJuIFsgbGVuZ3RoIC0gMSBdOwoJCX0pLAoKCQkiZXEiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCwgYXJndW1lbnQgKSB7CgkJCXJldHVybiBbIGFyZ3VtZW50IDwgMCA/IGFyZ3VtZW50ICsgbGVuZ3RoIDogYXJndW1lbnQgXTsKCQl9KSwKCgkJImV2ZW4iOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCApIHsKCQkJdmFyIGkgPSAwOwoJCQlmb3IgKCA7IGkgPCBsZW5ndGg7IGkgKz0gMiApIHsKCQkJCW1hdGNoSW5kZXhlcy5wdXNoKCBpICk7CgkJCX0KCQkJcmV0dXJuIG1hdGNoSW5kZXhlczsKCQl9KSwKCgkJIm9kZCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oIG1hdGNoSW5kZXhlcywgbGVuZ3RoICkgewoJCQl2YXIgaSA9IDE7CgkJCWZvciAoIDsgaSA8IGxlbmd0aDsgaSArPSAyICkgewoJCQkJbWF0Y2hJbmRleGVzLnB1c2goIGkgKTsKCQkJfQoJCQlyZXR1cm4gbWF0Y2hJbmRleGVzOwoJCX0pLAoKCQkibHQiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCwgYXJndW1lbnQgKSB7CgkJCXZhciBpID0gYXJndW1lbnQgPCAwID8gYXJndW1lbnQgKyBsZW5ndGggOiBhcmd1bWVudDsKCQkJZm9yICggOyAtLWkgPj0gMDsgKSB7CgkJCQltYXRjaEluZGV4ZXMucHVzaCggaSApOwoJCQl9CgkJCXJldHVybiBtYXRjaEluZGV4ZXM7CgkJfSksCgoJCSJndCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oIG1hdGNoSW5kZXhlcywgbGVuZ3RoLCBhcmd1bWVudCApIHsKCQkJdmFyIGkgPSBhcmd1bWVudCA8IDAgPyBhcmd1bWVudCArIGxlbmd0aCA6IGFyZ3VtZW50OwoJCQlmb3IgKCA7ICsraSA8IGxlbmd0aDsgKSB7CgkJCQltYXRjaEluZGV4ZXMucHVzaCggaSApOwoJCQl9CgkJCXJldHVybiBtYXRjaEluZGV4ZXM7CgkJfSkKCX0KfTsKCkV4cHIucHNldWRvc1sibnRoIl0gPSBFeHByLnBzZXVkb3NbImVxIl07CgovLyBBZGQgYnV0dG9uL2lucHV0IHR5cGUgcHNldWRvcwpmb3IgKCBpIGluIHsgcmFkaW86IHRydWUsIGNoZWNrYm94OiB0cnVlLCBmaWxlOiB0cnVlLCBwYXNzd29yZDogdHJ1ZSwgaW1hZ2U6IHRydWUgfSApIHsKCUV4cHIucHNldWRvc1sgaSBdID0gY3JlYXRlSW5wdXRQc2V1ZG8oIGkgKTsKfQpmb3IgKCBpIGluIHsgc3VibWl0OiB0cnVlLCByZXNldDogdHJ1ZSB9ICkgewoJRXhwci5wc2V1ZG9zWyBpIF0gPSBjcmVhdGVCdXR0b25Qc2V1ZG8oIGkgKTsKfQoKLy8gRWFzeSBBUEkgZm9yIGNyZWF0aW5nIG5ldyBzZXRGaWx0ZXJzCmZ1bmN0aW9uIHNldEZpbHRlcnMoKSB7fQpzZXRGaWx0ZXJzLnByb3RvdHlwZSA9IEV4cHIuZmlsdGVycyA9IEV4cHIucHNldWRvczsKRXhwci5zZXRGaWx0ZXJzID0gbmV3IHNldEZpbHRlcnMoKTsKCnRva2VuaXplID0gU2l6emxlLnRva2VuaXplID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBwYXJzZU9ubHkgKSB7Cgl2YXIgbWF0Y2hlZCwgbWF0Y2gsIHRva2VucywgdHlwZSwKCQlzb0ZhciwgZ3JvdXBzLCBwcmVGaWx0ZXJzLAoJCWNhY2hlZCA9IHRva2VuQ2FjaGVbIHNlbGVjdG9yICsgIiAiIF07CgoJaWYgKCBjYWNoZWQgKSB7CgkJcmV0dXJuIHBhcnNlT25seSA/IDAgOiBjYWNoZWQuc2xpY2UoIDAgKTsKCX0KCglzb0ZhciA9IHNlbGVjdG9yOwoJZ3JvdXBzID0gW107CglwcmVGaWx0ZXJzID0gRXhwci5wcmVGaWx0ZXI7CgoJd2hpbGUgKCBzb0ZhciApIHsKCgkJLy8gQ29tbWEgYW5kIGZpcnN0IHJ1bgoJCWlmICggIW1hdGNoZWQgfHwgKG1hdGNoID0gcmNvbW1hLmV4ZWMoIHNvRmFyICkpICkgewoJCQlpZiAoIG1hdGNoICkgewoJCQkJLy8gRG9uJ3QgY29uc3VtZSB0cmFpbGluZyBjb21tYXMgYXMgdmFsaWQKCQkJCXNvRmFyID0gc29GYXIuc2xpY2UoIG1hdGNoWzBdLmxlbmd0aCApIHx8IHNvRmFyOwoJCQl9CgkJCWdyb3Vwcy5wdXNoKCAodG9rZW5zID0gW10pICk7CgkJfQoKCQltYXRjaGVkID0gZmFsc2U7CgoJCS8vIENvbWJpbmF0b3JzCgkJaWYgKCAobWF0Y2ggPSByY29tYmluYXRvcnMuZXhlYyggc29GYXIgKSkgKSB7CgkJCW1hdGNoZWQgPSBtYXRjaC5zaGlmdCgpOwoJCQl0b2tlbnMucHVzaCh7CgkJCQl2YWx1ZTogbWF0Y2hlZCwKCQkJCS8vIENhc3QgZGVzY2VuZGFudCBjb21iaW5hdG9ycyB0byBzcGFjZQoJCQkJdHlwZTogbWF0Y2hbMF0ucmVwbGFjZSggcnRyaW0sICIgIiApCgkJCX0pOwoJCQlzb0ZhciA9IHNvRmFyLnNsaWNlKCBtYXRjaGVkLmxlbmd0aCApOwoJCX0KCgkJLy8gRmlsdGVycwoJCWZvciAoIHR5cGUgaW4gRXhwci5maWx0ZXIgKSB7CgkJCWlmICggKG1hdGNoID0gbWF0Y2hFeHByWyB0eXBlIF0uZXhlYyggc29GYXIgKSkgJiYgKCFwcmVGaWx0ZXJzWyB0eXBlIF0gfHwKCQkJCShtYXRjaCA9IHByZUZpbHRlcnNbIHR5cGUgXSggbWF0Y2ggKSkpICkgewoJCQkJbWF0Y2hlZCA9IG1hdGNoLnNoaWZ0KCk7CgkJCQl0b2tlbnMucHVzaCh7CgkJCQkJdmFsdWU6IG1hdGNoZWQsCgkJCQkJdHlwZTogdHlwZSwKCQkJCQltYXRjaGVzOiBtYXRjaAoJCQkJfSk7CgkJCQlzb0ZhciA9IHNvRmFyLnNsaWNlKCBtYXRjaGVkLmxlbmd0aCApOwoJCQl9CgkJfQoKCQlpZiAoICFtYXRjaGVkICkgewoJCQlicmVhazsKCQl9Cgl9CgoJLy8gUmV0dXJuIHRoZSBsZW5ndGggb2YgdGhlIGludmFsaWQgZXhjZXNzCgkvLyBpZiB3ZSdyZSBqdXN0IHBhcnNpbmcKCS8vIE90aGVyd2lzZSwgdGhyb3cgYW4gZXJyb3Igb3IgcmV0dXJuIHRva2VucwoJcmV0dXJuIHBhcnNlT25seSA/CgkJc29GYXIubGVuZ3RoIDoKCQlzb0ZhciA/CgkJCVNpenpsZS5lcnJvciggc2VsZWN0b3IgKSA6CgkJCS8vIENhY2hlIHRoZSB0b2tlbnMKCQkJdG9rZW5DYWNoZSggc2VsZWN0b3IsIGdyb3VwcyApLnNsaWNlKCAwICk7Cn07CgpmdW5jdGlvbiB0b1NlbGVjdG9yKCB0b2tlbnMgKSB7Cgl2YXIgaSA9IDAsCgkJbGVuID0gdG9rZW5zLmxlbmd0aCwKCQlzZWxlY3RvciA9ICIiOwoJZm9yICggOyBpIDwgbGVuOyBpKysgKSB7CgkJc2VsZWN0b3IgKz0gdG9rZW5zW2ldLnZhbHVlOwoJfQoJcmV0dXJuIHNlbGVjdG9yOwp9CgpmdW5jdGlvbiBhZGRDb21iaW5hdG9yKCBtYXRjaGVyLCBjb21iaW5hdG9yLCBiYXNlICkgewoJdmFyIGRpciA9IGNvbWJpbmF0b3IuZGlyLAoJCWNoZWNrTm9uRWxlbWVudHMgPSBiYXNlICYmIGRpciA9PT0gInBhcmVudE5vZGUiLAoJCWRvbmVOYW1lID0gZG9uZSsrOwoKCXJldHVybiBjb21iaW5hdG9yLmZpcnN0ID8KCQkvLyBDaGVjayBhZ2FpbnN0IGNsb3Nlc3QgYW5jZXN0b3IvcHJlY2VkaW5nIGVsZW1lbnQKCQlmdW5jdGlvbiggZWxlbSwgY29udGV4dCwgeG1sICkgewoJCQl3aGlsZSAoIChlbGVtID0gZWxlbVsgZGlyIF0pICkgewoJCQkJaWYgKCBlbGVtLm5vZGVUeXBlID09PSAxIHx8IGNoZWNrTm9uRWxlbWVudHMgKSB7CgkJCQkJcmV0dXJuIG1hdGNoZXIoIGVsZW0sIGNvbnRleHQsIHhtbCApOwoJCQkJfQoJCQl9CgkJfSA6CgoJCS8vIENoZWNrIGFnYWluc3QgYWxsIGFuY2VzdG9yL3ByZWNlZGluZyBlbGVtZW50cwoJCWZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7CgkJCXZhciBvbGRDYWNoZSwgb3V0ZXJDYWNoZSwKCQkJCW5ld0NhY2hlID0gWyBkaXJydW5zLCBkb25lTmFtZSBdOwoKCQkJLy8gV2UgY2FuJ3Qgc2V0IGFyYml0cmFyeSBkYXRhIG9uIFhNTCBub2Rlcywgc28gdGhleSBkb24ndCBiZW5lZml0IGZyb20gZGlyIGNhY2hpbmcKCQkJaWYgKCB4bWwgKSB7CgkJCQl3aGlsZSAoIChlbGVtID0gZWxlbVsgZGlyIF0pICkgewoJCQkJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSB8fCBjaGVja05vbkVsZW1lbnRzICkgewoJCQkJCQlpZiAoIG1hdGNoZXIoIGVsZW0sIGNvbnRleHQsIHhtbCApICkgewoJCQkJCQkJcmV0dXJuIHRydWU7CgkJCQkJCX0KCQkJCQl9CgkJCQl9CgkJCX0gZWxzZSB7CgkJCQl3aGlsZSAoIChlbGVtID0gZWxlbVsgZGlyIF0pICkgewoJCQkJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSB8fCBjaGVja05vbkVsZW1lbnRzICkgewoJCQkJCQlvdXRlckNhY2hlID0gZWxlbVsgZXhwYW5kbyBdIHx8IChlbGVtWyBleHBhbmRvIF0gPSB7fSk7CgkJCQkJCWlmICggKG9sZENhY2hlID0gb3V0ZXJDYWNoZVsgZGlyIF0pICYmCgkJCQkJCQlvbGRDYWNoZVsgMCBdID09PSBkaXJydW5zICYmIG9sZENhY2hlWyAxIF0gPT09IGRvbmVOYW1lICkgewoKCQkJCQkJCS8vIEFzc2lnbiB0byBuZXdDYWNoZSBzbyByZXN1bHRzIGJhY2stcHJvcGFnYXRlIHRvIHByZXZpb3VzIGVsZW1lbnRzCgkJCQkJCQlyZXR1cm4gKG5ld0NhY2hlWyAyIF0gPSBvbGRDYWNoZVsgMiBdKTsKCQkJCQkJfSBlbHNlIHsKCQkJCQkJCS8vIFJldXNlIG5ld2NhY2hlIHNvIHJlc3VsdHMgYmFjay1wcm9wYWdhdGUgdG8gcHJldmlvdXMgZWxlbWVudHMKCQkJCQkJCW91dGVyQ2FjaGVbIGRpciBdID0gbmV3Q2FjaGU7CgoJCQkJCQkJLy8gQSBtYXRjaCBtZWFucyB3ZSdyZSBkb25lOyBhIGZhaWwgbWVhbnMgd2UgaGF2ZSB0byBrZWVwIGNoZWNraW5nCgkJCQkJCQlpZiAoIChuZXdDYWNoZVsgMiBdID0gbWF0Y2hlciggZWxlbSwgY29udGV4dCwgeG1sICkpICkgewoJCQkJCQkJCXJldHVybiB0cnVlOwoJCQkJCQkJfQoJCQkJCQl9CgkJCQkJfQoJCQkJfQoJCQl9CgkJfTsKfQoKZnVuY3Rpb24gZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICkgewoJcmV0dXJuIG1hdGNoZXJzLmxlbmd0aCA+IDEgPwoJCWZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7CgkJCXZhciBpID0gbWF0Y2hlcnMubGVuZ3RoOwoJCQl3aGlsZSAoIGktLSApIHsKCQkJCWlmICggIW1hdGNoZXJzW2ldKCBlbGVtLCBjb250ZXh0LCB4bWwgKSApIHsKCQkJCQlyZXR1cm4gZmFsc2U7CgkJCQl9CgkJCX0KCQkJcmV0dXJuIHRydWU7CgkJfSA6CgkJbWF0Y2hlcnNbMF07Cn0KCmZ1bmN0aW9uIG11bHRpcGxlQ29udGV4dHMoIHNlbGVjdG9yLCBjb250ZXh0cywgcmVzdWx0cyApIHsKCXZhciBpID0gMCwKCQlsZW4gPSBjb250ZXh0cy5sZW5ndGg7Cglmb3IgKCA7IGkgPCBsZW47IGkrKyApIHsKCQlTaXp6bGUoIHNlbGVjdG9yLCBjb250ZXh0c1tpXSwgcmVzdWx0cyApOwoJfQoJcmV0dXJuIHJlc3VsdHM7Cn0KCmZ1bmN0aW9uIGNvbmRlbnNlKCB1bm1hdGNoZWQsIG1hcCwgZmlsdGVyLCBjb250ZXh0LCB4bWwgKSB7Cgl2YXIgZWxlbSwKCQluZXdVbm1hdGNoZWQgPSBbXSwKCQlpID0gMCwKCQlsZW4gPSB1bm1hdGNoZWQubGVuZ3RoLAoJCW1hcHBlZCA9IG1hcCAhPSBudWxsOwoKCWZvciAoIDsgaSA8IGxlbjsgaSsrICkgewoJCWlmICggKGVsZW0gPSB1bm1hdGNoZWRbaV0pICkgewoJCQlpZiAoICFmaWx0ZXIgfHwgZmlsdGVyKCBlbGVtLCBjb250ZXh0LCB4bWwgKSApIHsKCQkJCW5ld1VubWF0Y2hlZC5wdXNoKCBlbGVtICk7CgkJCQlpZiAoIG1hcHBlZCApIHsKCQkJCQltYXAucHVzaCggaSApOwoJCQkJfQoJCQl9CgkJfQoJfQoKCXJldHVybiBuZXdVbm1hdGNoZWQ7Cn0KCmZ1bmN0aW9uIHNldE1hdGNoZXIoIHByZUZpbHRlciwgc2VsZWN0b3IsIG1hdGNoZXIsIHBvc3RGaWx0ZXIsIHBvc3RGaW5kZXIsIHBvc3RTZWxlY3RvciApIHsKCWlmICggcG9zdEZpbHRlciAmJiAhcG9zdEZpbHRlclsgZXhwYW5kbyBdICkgewoJCXBvc3RGaWx0ZXIgPSBzZXRNYXRjaGVyKCBwb3N0RmlsdGVyICk7Cgl9CglpZiAoIHBvc3RGaW5kZXIgJiYgIXBvc3RGaW5kZXJbIGV4cGFuZG8gXSApIHsKCQlwb3N0RmluZGVyID0gc2V0TWF0Y2hlciggcG9zdEZpbmRlciwgcG9zdFNlbGVjdG9yICk7Cgl9CglyZXR1cm4gbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWVkLCByZXN1bHRzLCBjb250ZXh0LCB4bWwgKSB7CgkJdmFyIHRlbXAsIGksIGVsZW0sCgkJCXByZU1hcCA9IFtdLAoJCQlwb3N0TWFwID0gW10sCgkJCXByZWV4aXN0aW5nID0gcmVzdWx0cy5sZW5ndGgsCgoJCQkvLyBHZXQgaW5pdGlhbCBlbGVtZW50cyBmcm9tIHNlZWQgb3IgY29udGV4dAoJCQllbGVtcyA9IHNlZWQgfHwgbXVsdGlwbGVDb250ZXh0cyggc2VsZWN0b3IgfHwgIioiLCBjb250ZXh0Lm5vZGVUeXBlID8gWyBjb250ZXh0IF0gOiBjb250ZXh0LCBbXSApLAoKCQkJLy8gUHJlZmlsdGVyIHRvIGdldCBtYXRjaGVyIGlucHV0LCBwcmVzZXJ2aW5nIGEgbWFwIGZvciBzZWVkLXJlc3VsdHMgc3luY2hyb25pemF0aW9uCgkJCW1hdGNoZXJJbiA9IHByZUZpbHRlciAmJiAoIHNlZWQgfHwgIXNlbGVjdG9yICkgPwoJCQkJY29uZGVuc2UoIGVsZW1zLCBwcmVNYXAsIHByZUZpbHRlciwgY29udGV4dCwgeG1sICkgOgoJCQkJZWxlbXMsCgoJCQltYXRjaGVyT3V0ID0gbWF0Y2hlciA/CgkJCQkvLyBJZiB3ZSBoYXZlIGEgcG9zdEZpbmRlciwgb3IgZmlsdGVyZWQgc2VlZCwgb3Igbm9uLXNlZWQgcG9zdEZpbHRlciBvciBwcmVleGlzdGluZyByZXN1bHRzLAoJCQkJcG9zdEZpbmRlciB8fCAoIHNlZWQgPyBwcmVGaWx0ZXIgOiBwcmVleGlzdGluZyB8fCBwb3N0RmlsdGVyICkgPwoKCQkJCQkvLyAuLi5pbnRlcm1lZGlhdGUgcHJvY2Vzc2luZyBpcyBuZWNlc3NhcnkKCQkJCQlbXSA6CgoJCQkJCS8vIC4uLm90aGVyd2lzZSB1c2UgcmVzdWx0cyBkaXJlY3RseQoJCQkJCXJlc3VsdHMgOgoJCQkJbWF0Y2hlckluOwoKCQkvLyBGaW5kIHByaW1hcnkgbWF0Y2hlcwoJCWlmICggbWF0Y2hlciApIHsKCQkJbWF0Y2hlciggbWF0Y2hlckluLCBtYXRjaGVyT3V0LCBjb250ZXh0LCB4bWwgKTsKCQl9CgoJCS8vIEFwcGx5IHBvc3RGaWx0ZXIKCQlpZiAoIHBvc3RGaWx0ZXIgKSB7CgkJCXRlbXAgPSBjb25kZW5zZSggbWF0Y2hlck91dCwgcG9zdE1hcCApOwoJCQlwb3N0RmlsdGVyKCB0ZW1wLCBbXSwgY29udGV4dCwgeG1sICk7CgoJCQkvLyBVbi1tYXRjaCBmYWlsaW5nIGVsZW1lbnRzIGJ5IG1vdmluZyB0aGVtIGJhY2sgdG8gbWF0Y2hlckluCgkJCWkgPSB0ZW1wLmxlbmd0aDsKCQkJd2hpbGUgKCBpLS0gKSB7CgkJCQlpZiAoIChlbGVtID0gdGVtcFtpXSkgKSB7CgkJCQkJbWF0Y2hlck91dFsgcG9zdE1hcFtpXSBdID0gIShtYXRjaGVySW5bIHBvc3RNYXBbaV0gXSA9IGVsZW0pOwoJCQkJfQoJCQl9CgkJfQoKCQlpZiAoIHNlZWQgKSB7CgkJCWlmICggcG9zdEZpbmRlciB8fCBwcmVGaWx0ZXIgKSB7CgkJCQlpZiAoIHBvc3RGaW5kZXIgKSB7CgkJCQkJLy8gR2V0IHRoZSBmaW5hbCBtYXRjaGVyT3V0IGJ5IGNvbmRlbnNpbmcgdGhpcyBpbnRlcm1lZGlhdGUgaW50byBwb3N0RmluZGVyIGNvbnRleHRzCgkJCQkJdGVtcCA9IFtdOwoJCQkJCWkgPSBtYXRjaGVyT3V0Lmxlbmd0aDsKCQkJCQl3aGlsZSAoIGktLSApIHsKCQkJCQkJaWYgKCAoZWxlbSA9IG1hdGNoZXJPdXRbaV0pICkgewoJCQkJCQkJLy8gUmVzdG9yZSBtYXRjaGVySW4gc2luY2UgZWxlbSBpcyBub3QgeWV0IGEgZmluYWwgbWF0Y2gKCQkJCQkJCXRlbXAucHVzaCggKG1hdGNoZXJJbltpXSA9IGVsZW0pICk7CgkJCQkJCX0KCQkJCQl9CgkJCQkJcG9zdEZpbmRlciggbnVsbCwgKG1hdGNoZXJPdXQgPSBbXSksIHRlbXAsIHhtbCApOwoJCQkJfQoKCQkJCS8vIE1vdmUgbWF0Y2hlZCBlbGVtZW50cyBmcm9tIHNlZWQgdG8gcmVzdWx0cyB0byBrZWVwIHRoZW0gc3luY2hyb25pemVkCgkJCQlpID0gbWF0Y2hlck91dC5sZW5ndGg7CgkJCQl3aGlsZSAoIGktLSApIHsKCQkJCQlpZiAoIChlbGVtID0gbWF0Y2hlck91dFtpXSkgJiYKCQkJCQkJKHRlbXAgPSBwb3N0RmluZGVyID8gaW5kZXhPZi5jYWxsKCBzZWVkLCBlbGVtICkgOiBwcmVNYXBbaV0pID4gLTEgKSB7CgoJCQkJCQlzZWVkW3RlbXBdID0gIShyZXN1bHRzW3RlbXBdID0gZWxlbSk7CgkJCQkJfQoJCQkJfQoJCQl9CgoJCS8vIEFkZCBlbGVtZW50cyB0byByZXN1bHRzLCB0aHJvdWdoIHBvc3RGaW5kZXIgaWYgZGVmaW5lZAoJCX0gZWxzZSB7CgkJCW1hdGNoZXJPdXQgPSBjb25kZW5zZSgKCQkJCW1hdGNoZXJPdXQgPT09IHJlc3VsdHMgPwoJCQkJCW1hdGNoZXJPdXQuc3BsaWNlKCBwcmVleGlzdGluZywgbWF0Y2hlck91dC5sZW5ndGggKSA6CgkJCQkJbWF0Y2hlck91dAoJCQkpOwoJCQlpZiAoIHBvc3RGaW5kZXIgKSB7CgkJCQlwb3N0RmluZGVyKCBudWxsLCByZXN1bHRzLCBtYXRjaGVyT3V0LCB4bWwgKTsKCQkJfSBlbHNlIHsKCQkJCXB1c2guYXBwbHkoIHJlc3VsdHMsIG1hdGNoZXJPdXQgKTsKCQkJfQoJCX0KCX0pOwp9CgpmdW5jdGlvbiBtYXRjaGVyRnJvbVRva2VucyggdG9rZW5zICkgewoJdmFyIGNoZWNrQ29udGV4dCwgbWF0Y2hlciwgaiwKCQlsZW4gPSB0b2tlbnMubGVuZ3RoLAoJCWxlYWRpbmdSZWxhdGl2ZSA9IEV4cHIucmVsYXRpdmVbIHRva2Vuc1swXS50eXBlIF0sCgkJaW1wbGljaXRSZWxhdGl2ZSA9IGxlYWRpbmdSZWxhdGl2ZSB8fCBFeHByLnJlbGF0aXZlWyIgIl0sCgkJaSA9IGxlYWRpbmdSZWxhdGl2ZSA/IDEgOiAwLAoKCQkvLyBUaGUgZm91bmRhdGlvbmFsIG1hdGNoZXIgZW5zdXJlcyB0aGF0IGVsZW1lbnRzIGFyZSByZWFjaGFibGUgZnJvbSB0b3AtbGV2ZWwgY29udGV4dChzKQoJCW1hdGNoQ29udGV4dCA9IGFkZENvbWJpbmF0b3IoIGZ1bmN0aW9uKCBlbGVtICkgewoJCQlyZXR1cm4gZWxlbSA9PT0gY2hlY2tDb250ZXh0OwoJCX0sIGltcGxpY2l0UmVsYXRpdmUsIHRydWUgKSwKCQltYXRjaEFueUNvbnRleHQgPSBhZGRDb21iaW5hdG9yKCBmdW5jdGlvbiggZWxlbSApIHsKCQkJcmV0dXJuIGluZGV4T2YuY2FsbCggY2hlY2tDb250ZXh0LCBlbGVtICkgPiAtMTsKCQl9LCBpbXBsaWNpdFJlbGF0aXZlLCB0cnVlICksCgkJbWF0Y2hlcnMgPSBbIGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7CgkJCXJldHVybiAoICFsZWFkaW5nUmVsYXRpdmUgJiYgKCB4bWwgfHwgY29udGV4dCAhPT0gb3V0ZXJtb3N0Q29udGV4dCApICkgfHwgKAoJCQkJKGNoZWNrQ29udGV4dCA9IGNvbnRleHQpLm5vZGVUeXBlID8KCQkJCQltYXRjaENvbnRleHQoIGVsZW0sIGNvbnRleHQsIHhtbCApIDoKCQkJCQltYXRjaEFueUNvbnRleHQoIGVsZW0sIGNvbnRleHQsIHhtbCApICk7CgkJfSBdOwoKCWZvciAoIDsgaSA8IGxlbjsgaSsrICkgewoJCWlmICggKG1hdGNoZXIgPSBFeHByLnJlbGF0aXZlWyB0b2tlbnNbaV0udHlwZSBdKSApIHsKCQkJbWF0Y2hlcnMgPSBbIGFkZENvbWJpbmF0b3IoZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICksIG1hdGNoZXIpIF07CgkJfSBlbHNlIHsKCQkJbWF0Y2hlciA9IEV4cHIuZmlsdGVyWyB0b2tlbnNbaV0udHlwZSBdLmFwcGx5KCBudWxsLCB0b2tlbnNbaV0ubWF0Y2hlcyApOwoKCQkJLy8gUmV0dXJuIHNwZWNpYWwgdXBvbiBzZWVpbmcgYSBwb3NpdGlvbmFsIG1hdGNoZXIKCQkJaWYgKCBtYXRjaGVyWyBleHBhbmRvIF0gKSB7CgkJCQkvLyBGaW5kIHRoZSBuZXh0IHJlbGF0aXZlIG9wZXJhdG9yIChpZiBhbnkpIGZvciBwcm9wZXIgaGFuZGxpbmcKCQkJCWogPSArK2k7CgkJCQlmb3IgKCA7IGogPCBsZW47IGorKyApIHsKCQkJCQlpZiAoIEV4cHIucmVsYXRpdmVbIHRva2Vuc1tqXS50eXBlIF0gKSB7CgkJCQkJCWJyZWFrOwoJCQkJCX0KCQkJCX0KCQkJCXJldHVybiBzZXRNYXRjaGVyKAoJCQkJCWkgPiAxICYmIGVsZW1lbnRNYXRjaGVyKCBtYXRjaGVycyApLAoJCQkJCWkgPiAxICYmIHRvU2VsZWN0b3IoCgkJCQkJCS8vIElmIHRoZSBwcmVjZWRpbmcgdG9rZW4gd2FzIGEgZGVzY2VuZGFudCBjb21iaW5hdG9yLCBpbnNlcnQgYW4gaW1wbGljaXQgYW55LWVsZW1lbnQgYCpgCgkJCQkJCXRva2Vucy5zbGljZSggMCwgaSAtIDEgKS5jb25jYXQoeyB2YWx1ZTogdG9rZW5zWyBpIC0gMiBdLnR5cGUgPT09ICIgIiA/ICIqIiA6ICIiIH0pCgkJCQkJKS5yZXBsYWNlKCBydHJpbSwgIiQxIiApLAoJCQkJCW1hdGNoZXIsCgkJCQkJaSA8IGogJiYgbWF0Y2hlckZyb21Ub2tlbnMoIHRva2Vucy5zbGljZSggaSwgaiApICksCgkJCQkJaiA8IGxlbiAmJiBtYXRjaGVyRnJvbVRva2VucyggKHRva2VucyA9IHRva2Vucy5zbGljZSggaiApKSApLAoJCQkJCWogPCBsZW4gJiYgdG9TZWxlY3RvciggdG9rZW5zICkKCQkJCSk7CgkJCX0KCQkJbWF0Y2hlcnMucHVzaCggbWF0Y2hlciApOwoJCX0KCX0KCglyZXR1cm4gZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICk7Cn0KCmZ1bmN0aW9uIG1hdGNoZXJGcm9tR3JvdXBNYXRjaGVycyggZWxlbWVudE1hdGNoZXJzLCBzZXRNYXRjaGVycyApIHsKCXZhciBieVNldCA9IHNldE1hdGNoZXJzLmxlbmd0aCA+IDAsCgkJYnlFbGVtZW50ID0gZWxlbWVudE1hdGNoZXJzLmxlbmd0aCA+IDAsCgkJc3VwZXJNYXRjaGVyID0gZnVuY3Rpb24oIHNlZWQsIGNvbnRleHQsIHhtbCwgcmVzdWx0cywgb3V0ZXJtb3N0ICkgewoJCQl2YXIgZWxlbSwgaiwgbWF0Y2hlciwKCQkJCW1hdGNoZWRDb3VudCA9IDAsCgkJCQlpID0gIjAiLAoJCQkJdW5tYXRjaGVkID0gc2VlZCAmJiBbXSwKCQkJCXNldE1hdGNoZWQgPSBbXSwKCQkJCWNvbnRleHRCYWNrdXAgPSBvdXRlcm1vc3RDb250ZXh0LAoJCQkJLy8gV2UgbXVzdCBhbHdheXMgaGF2ZSBlaXRoZXIgc2VlZCBlbGVtZW50cyBvciBvdXRlcm1vc3QgY29udGV4dAoJCQkJZWxlbXMgPSBzZWVkIHx8IGJ5RWxlbWVudCAmJiBFeHByLmZpbmRbIlRBRyJdKCAiKiIsIG91dGVybW9zdCApLAoJCQkJLy8gVXNlIGludGVnZXIgZGlycnVucyBpZmYgdGhpcyBpcyB0aGUgb3V0ZXJtb3N0IG1hdGNoZXIKCQkJCWRpcnJ1bnNVbmlxdWUgPSAoZGlycnVucyArPSBjb250ZXh0QmFja3VwID09IG51bGwgPyAxIDogTWF0aC5yYW5kb20oKSB8fCAwLjEpLAoJCQkJbGVuID0gZWxlbXMubGVuZ3RoOwoKCQkJaWYgKCBvdXRlcm1vc3QgKSB7CgkJCQlvdXRlcm1vc3RDb250ZXh0ID0gY29udGV4dCAhPT0gZG9jdW1lbnQgJiYgY29udGV4dDsKCQkJfQoKCQkJLy8gQWRkIGVsZW1lbnRzIHBhc3NpbmcgZWxlbWVudE1hdGNoZXJzIGRpcmVjdGx5IHRvIHJlc3VsdHMKCQkJLy8gS2VlcCBgaWAgYSBzdHJpbmcgaWYgdGhlcmUgYXJlIG5vIGVsZW1lbnRzIHNvIGBtYXRjaGVkQ291bnRgIHdpbGwgYmUgIjAwIiBiZWxvdwoJCQkvLyBTdXBwb3J0OiBJRTw5LCBTYWZhcmkKCQkJLy8gVG9sZXJhdGUgTm9kZUxpc3QgcHJvcGVydGllcyAoSUU6ICJsZW5ndGgiOyBTYWZhcmk6IDxudW1iZXI+KSBtYXRjaGluZyBlbGVtZW50cyBieSBpZAoJCQlmb3IgKCA7IGkgIT09IGxlbiAmJiAoZWxlbSA9IGVsZW1zW2ldKSAhPSBudWxsOyBpKysgKSB7CgkJCQlpZiAoIGJ5RWxlbWVudCAmJiBlbGVtICkgewoJCQkJCWogPSAwOwoJCQkJCXdoaWxlICggKG1hdGNoZXIgPSBlbGVtZW50TWF0Y2hlcnNbaisrXSkgKSB7CgkJCQkJCWlmICggbWF0Y2hlciggZWxlbSwgY29udGV4dCwgeG1sICkgKSB7CgkJCQkJCQlyZXN1bHRzLnB1c2goIGVsZW0gKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQl9CgkJCQkJfQoJCQkJCWlmICggb3V0ZXJtb3N0ICkgewoJCQkJCQlkaXJydW5zID0gZGlycnVuc1VuaXF1ZTsKCQkJCQl9CgkJCQl9CgoJCQkJLy8gVHJhY2sgdW5tYXRjaGVkIGVsZW1lbnRzIGZvciBzZXQgZmlsdGVycwoJCQkJaWYgKCBieVNldCApIHsKCQkJCQkvLyBUaGV5IHdpbGwgaGF2ZSBnb25lIHRocm91Z2ggYWxsIHBvc3NpYmxlIG1hdGNoZXJzCgkJCQkJaWYgKCAoZWxlbSA9ICFtYXRjaGVyICYmIGVsZW0pICkgewoJCQkJCQltYXRjaGVkQ291bnQtLTsKCQkJCQl9CgoJCQkJCS8vIExlbmd0aGVuIHRoZSBhcnJheSBmb3IgZXZlcnkgZWxlbWVudCwgbWF0Y2hlZCBvciBub3QKCQkJCQlpZiAoIHNlZWQgKSB7CgkJCQkJCXVubWF0Y2hlZC5wdXNoKCBlbGVtICk7CgkJCQkJfQoJCQkJfQoJCQl9CgoJCQkvLyBBcHBseSBzZXQgZmlsdGVycyB0byB1bm1hdGNoZWQgZWxlbWVudHMKCQkJbWF0Y2hlZENvdW50ICs9IGk7CgkJCWlmICggYnlTZXQgJiYgaSAhPT0gbWF0Y2hlZENvdW50ICkgewoJCQkJaiA9IDA7CgkJCQl3aGlsZSAoIChtYXRjaGVyID0gc2V0TWF0Y2hlcnNbaisrXSkgKSB7CgkJCQkJbWF0Y2hlciggdW5tYXRjaGVkLCBzZXRNYXRjaGVkLCBjb250ZXh0LCB4bWwgKTsKCQkJCX0KCgkJCQlpZiAoIHNlZWQgKSB7CgkJCQkJLy8gUmVpbnRlZ3JhdGUgZWxlbWVudCBtYXRjaGVzIHRvIGVsaW1pbmF0ZSB0aGUgbmVlZCBmb3Igc29ydGluZwoJCQkJCWlmICggbWF0Y2hlZENvdW50ID4gMCApIHsKCQkJCQkJd2hpbGUgKCBpLS0gKSB7CgkJCQkJCQlpZiAoICEodW5tYXRjaGVkW2ldIHx8IHNldE1hdGNoZWRbaV0pICkgewoJCQkJCQkJCXNldE1hdGNoZWRbaV0gPSBwb3AuY2FsbCggcmVzdWx0cyApOwoJCQkJCQkJfQoJCQkJCQl9CgkJCQkJfQoKCQkJCQkvLyBEaXNjYXJkIGluZGV4IHBsYWNlaG9sZGVyIHZhbHVlcyB0byBnZXQgb25seSBhY3R1YWwgbWF0Y2hlcwoJCQkJCXNldE1hdGNoZWQgPSBjb25kZW5zZSggc2V0TWF0Y2hlZCApOwoJCQkJfQoKCQkJCS8vIEFkZCBtYXRjaGVzIHRvIHJlc3VsdHMKCQkJCXB1c2guYXBwbHkoIHJlc3VsdHMsIHNldE1hdGNoZWQgKTsKCgkJCQkvLyBTZWVkbGVzcyBzZXQgbWF0Y2hlcyBzdWNjZWVkaW5nIG11bHRpcGxlIHN1Y2Nlc3NmdWwgbWF0Y2hlcnMgc3RpcHVsYXRlIHNvcnRpbmcKCQkJCWlmICggb3V0ZXJtb3N0ICYmICFzZWVkICYmIHNldE1hdGNoZWQubGVuZ3RoID4gMCAmJgoJCQkJCSggbWF0Y2hlZENvdW50ICsgc2V0TWF0Y2hlcnMubGVuZ3RoICkgPiAxICkgewoKCQkJCQlTaXp6bGUudW5pcXVlU29ydCggcmVzdWx0cyApOwoJCQkJfQoJCQl9CgoJCQkvLyBPdmVycmlkZSBtYW5pcHVsYXRpb24gb2YgZ2xvYmFscyBieSBuZXN0ZWQgbWF0Y2hlcnMKCQkJaWYgKCBvdXRlcm1vc3QgKSB7CgkJCQlkaXJydW5zID0gZGlycnVuc1VuaXF1ZTsKCQkJCW91dGVybW9zdENvbnRleHQgPSBjb250ZXh0QmFja3VwOwoJCQl9CgoJCQlyZXR1cm4gdW5tYXRjaGVkOwoJCX07CgoJcmV0dXJuIGJ5U2V0ID8KCQltYXJrRnVuY3Rpb24oIHN1cGVyTWF0Y2hlciApIDoKCQlzdXBlck1hdGNoZXI7Cn0KCmNvbXBpbGUgPSBTaXp6bGUuY29tcGlsZSA9IGZ1bmN0aW9uKCBzZWxlY3RvciwgbWF0Y2ggLyogSW50ZXJuYWwgVXNlIE9ubHkgKi8gKSB7Cgl2YXIgaSwKCQlzZXRNYXRjaGVycyA9IFtdLAoJCWVsZW1lbnRNYXRjaGVycyA9IFtdLAoJCWNhY2hlZCA9IGNvbXBpbGVyQ2FjaGVbIHNlbGVjdG9yICsgIiAiIF07CgoJaWYgKCAhY2FjaGVkICkgewoJCS8vIEdlbmVyYXRlIGEgZnVuY3Rpb24gb2YgcmVjdXJzaXZlIGZ1bmN0aW9ucyB0aGF0IGNhbiBiZSB1c2VkIHRvIGNoZWNrIGVhY2ggZWxlbWVudAoJCWlmICggIW1hdGNoICkgewoJCQltYXRjaCA9IHRva2VuaXplKCBzZWxlY3RvciApOwoJCX0KCQlpID0gbWF0Y2gubGVuZ3RoOwoJCXdoaWxlICggaS0tICkgewoJCQljYWNoZWQgPSBtYXRjaGVyRnJvbVRva2VucyggbWF0Y2hbaV0gKTsKCQkJaWYgKCBjYWNoZWRbIGV4cGFuZG8gXSApIHsKCQkJCXNldE1hdGNoZXJzLnB1c2goIGNhY2hlZCApOwoJCQl9IGVsc2UgewoJCQkJZWxlbWVudE1hdGNoZXJzLnB1c2goIGNhY2hlZCApOwoJCQl9CgkJfQoKCQkvLyBDYWNoZSB0aGUgY29tcGlsZWQgZnVuY3Rpb24KCQljYWNoZWQgPSBjb21waWxlckNhY2hlKCBzZWxlY3RvciwgbWF0Y2hlckZyb21Hcm91cE1hdGNoZXJzKCBlbGVtZW50TWF0Y2hlcnMsIHNldE1hdGNoZXJzICkgKTsKCgkJLy8gU2F2ZSBzZWxlY3RvciBhbmQgdG9rZW5pemF0aW9uCgkJY2FjaGVkLnNlbGVjdG9yID0gc2VsZWN0b3I7Cgl9CglyZXR1cm4gY2FjaGVkOwp9OwoKLyoqCiAqIEEgbG93LWxldmVsIHNlbGVjdGlvbiBmdW5jdGlvbiB0aGF0IHdvcmtzIHdpdGggU2l6emxlJ3MgY29tcGlsZWQKICogIHNlbGVjdG9yIGZ1bmN0aW9ucwogKiBAcGFyYW0ge1N0cmluZ3xGdW5jdGlvbn0gc2VsZWN0b3IgQSBzZWxlY3RvciBvciBhIHByZS1jb21waWxlZAogKiAgc2VsZWN0b3IgZnVuY3Rpb24gYnVpbHQgd2l0aCBTaXp6bGUuY29tcGlsZQogKiBAcGFyYW0ge0VsZW1lbnR9IGNvbnRleHQKICogQHBhcmFtIHtBcnJheX0gW3Jlc3VsdHNdCiAqIEBwYXJhbSB7QXJyYXl9IFtzZWVkXSBBIHNldCBvZiBlbGVtZW50cyB0byBtYXRjaCBhZ2FpbnN0CiAqLwpzZWxlY3QgPSBTaXp6bGUuc2VsZWN0ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0LCByZXN1bHRzLCBzZWVkICkgewoJdmFyIGksIHRva2VucywgdG9rZW4sIHR5cGUsIGZpbmQsCgkJY29tcGlsZWQgPSB0eXBlb2Ygc2VsZWN0b3IgPT09ICJmdW5jdGlvbiIgJiYgc2VsZWN0b3IsCgkJbWF0Y2ggPSAhc2VlZCAmJiB0b2tlbml6ZSggKHNlbGVjdG9yID0gY29tcGlsZWQuc2VsZWN0b3IgfHwgc2VsZWN0b3IpICk7CgoJcmVzdWx0cyA9IHJlc3VsdHMgfHwgW107CgoJLy8gVHJ5IHRvIG1pbmltaXplIG9wZXJhdGlvbnMgaWYgdGhlcmUgaXMgbm8gc2VlZCBhbmQgb25seSBvbmUgZ3JvdXAKCWlmICggbWF0Y2gubGVuZ3RoID09PSAxICkgewoKCQkvLyBUYWtlIGEgc2hvcnRjdXQgYW5kIHNldCB0aGUgY29udGV4dCBpZiB0aGUgcm9vdCBzZWxlY3RvciBpcyBhbiBJRAoJCXRva2VucyA9IG1hdGNoWzBdID0gbWF0Y2hbMF0uc2xpY2UoIDAgKTsKCQlpZiAoIHRva2Vucy5sZW5ndGggPiAyICYmICh0b2tlbiA9IHRva2Vuc1swXSkudHlwZSA9PT0gIklEIiAmJgoJCQkJc3VwcG9ydC5nZXRCeUlkICYmIGNvbnRleHQubm9kZVR5cGUgPT09IDkgJiYgZG9jdW1lbnRJc0hUTUwgJiYKCQkJCUV4cHIucmVsYXRpdmVbIHRva2Vuc1sxXS50eXBlIF0gKSB7CgoJCQljb250ZXh0ID0gKCBFeHByLmZpbmRbIklEIl0oIHRva2VuLm1hdGNoZXNbMF0ucmVwbGFjZShydW5lc2NhcGUsIGZ1bmVzY2FwZSksIGNvbnRleHQgKSB8fCBbXSApWzBdOwoJCQlpZiAoICFjb250ZXh0ICkgewoJCQkJcmV0dXJuIHJlc3VsdHM7CgoJCQkvLyBQcmVjb21waWxlZCBtYXRjaGVycyB3aWxsIHN0aWxsIHZlcmlmeSBhbmNlc3RyeSwgc28gc3RlcCB1cCBhIGxldmVsCgkJCX0gZWxzZSBpZiAoIGNvbXBpbGVkICkgewoJCQkJY29udGV4dCA9IGNvbnRleHQucGFyZW50Tm9kZTsKCQkJfQoKCQkJc2VsZWN0b3IgPSBzZWxlY3Rvci5zbGljZSggdG9rZW5zLnNoaWZ0KCkudmFsdWUubGVuZ3RoICk7CgkJfQoKCQkvLyBGZXRjaCBhIHNlZWQgc2V0IGZvciByaWdodC10by1sZWZ0IG1hdGNoaW5nCgkJaSA9IG1hdGNoRXhwclsibmVlZHNDb250ZXh0Il0udGVzdCggc2VsZWN0b3IgKSA/IDAgOiB0b2tlbnMubGVuZ3RoOwoJCXdoaWxlICggaS0tICkgewoJCQl0b2tlbiA9IHRva2Vuc1tpXTsKCgkJCS8vIEFib3J0IGlmIHdlIGhpdCBhIGNvbWJpbmF0b3IKCQkJaWYgKCBFeHByLnJlbGF0aXZlWyAodHlwZSA9IHRva2VuLnR5cGUpIF0gKSB7CgkJCQlicmVhazsKCQkJfQoJCQlpZiAoIChmaW5kID0gRXhwci5maW5kWyB0eXBlIF0pICkgewoJCQkJLy8gU2VhcmNoLCBleHBhbmRpbmcgY29udGV4dCBmb3IgbGVhZGluZyBzaWJsaW5nIGNvbWJpbmF0b3JzCgkJCQlpZiAoIChzZWVkID0gZmluZCgKCQkJCQl0b2tlbi5tYXRjaGVzWzBdLnJlcGxhY2UoIHJ1bmVzY2FwZSwgZnVuZXNjYXBlICksCgkJCQkJcnNpYmxpbmcudGVzdCggdG9rZW5zWzBdLnR5cGUgKSAmJiB0ZXN0Q29udGV4dCggY29udGV4dC5wYXJlbnROb2RlICkgfHwgY29udGV4dAoJCQkJKSkgKSB7CgoJCQkJCS8vIElmIHNlZWQgaXMgZW1wdHkgb3Igbm8gdG9rZW5zIHJlbWFpbiwgd2UgY2FuIHJldHVybiBlYXJseQoJCQkJCXRva2Vucy5zcGxpY2UoIGksIDEgKTsKCQkJCQlzZWxlY3RvciA9IHNlZWQubGVuZ3RoICYmIHRvU2VsZWN0b3IoIHRva2VucyApOwoJCQkJCWlmICggIXNlbGVjdG9yICkgewoJCQkJCQlwdXNoLmFwcGx5KCByZXN1bHRzLCBzZWVkICk7CgkJCQkJCXJldHVybiByZXN1bHRzOwoJCQkJCX0KCgkJCQkJYnJlYWs7CgkJCQl9CgkJCX0KCQl9Cgl9CgoJLy8gQ29tcGlsZSBhbmQgZXhlY3V0ZSBhIGZpbHRlcmluZyBmdW5jdGlvbiBpZiBvbmUgaXMgbm90IHByb3ZpZGVkCgkvLyBQcm92aWRlIGBtYXRjaGAgdG8gYXZvaWQgcmV0b2tlbml6YXRpb24gaWYgd2UgbW9kaWZpZWQgdGhlIHNlbGVjdG9yIGFib3ZlCgkoIGNvbXBpbGVkIHx8IGNvbXBpbGUoIHNlbGVjdG9yLCBtYXRjaCApICkoCgkJc2VlZCwKCQljb250ZXh0LAoJCSFkb2N1bWVudElzSFRNTCwKCQlyZXN1bHRzLAoJCXJzaWJsaW5nLnRlc3QoIHNlbGVjdG9yICkgJiYgdGVzdENvbnRleHQoIGNvbnRleHQucGFyZW50Tm9kZSApIHx8IGNvbnRleHQKCSk7CglyZXR1cm4gcmVzdWx0czsKfTsKCi8vIE9uZS10aW1lIGFzc2lnbm1lbnRzCgovLyBTb3J0IHN0YWJpbGl0eQpzdXBwb3J0LnNvcnRTdGFibGUgPSBleHBhbmRvLnNwbGl0KCIiKS5zb3J0KCBzb3J0T3JkZXIgKS5qb2luKCIiKSA9PT0gZXhwYW5kbzsKCi8vIFN1cHBvcnQ6IENocm9tZTwxNAovLyBBbHdheXMgYXNzdW1lIGR1cGxpY2F0ZXMgaWYgdGhleSBhcmVuJ3QgcGFzc2VkIHRvIHRoZSBjb21wYXJpc29uIGZ1bmN0aW9uCnN1cHBvcnQuZGV0ZWN0RHVwbGljYXRlcyA9ICEhaGFzRHVwbGljYXRlOwoKLy8gSW5pdGlhbGl6ZSBhZ2FpbnN0IHRoZSBkZWZhdWx0IGRvY3VtZW50CnNldERvY3VtZW50KCk7CgovLyBTdXBwb3J0OiBXZWJraXQ8NTM3LjMyIC0gU2FmYXJpIDYuMC4zL0Nocm9tZSAyNSAoZml4ZWQgaW4gQ2hyb21lIDI3KQovLyBEZXRhY2hlZCBub2RlcyBjb25mb3VuZGluZ2x5IGZvbGxvdyAqZWFjaCBvdGhlcioKc3VwcG9ydC5zb3J0RGV0YWNoZWQgPSBhc3NlcnQoZnVuY3Rpb24oIGRpdjEgKSB7CgkvLyBTaG91bGQgcmV0dXJuIDEsIGJ1dCByZXR1cm5zIDQgKGZvbGxvd2luZykKCXJldHVybiBkaXYxLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSApICYgMTsKfSk7CgovLyBTdXBwb3J0OiBJRTw4Ci8vIFByZXZlbnQgYXR0cmlidXRlL3Byb3BlcnR5ICJpbnRlcnBvbGF0aW9uIgovLyBodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvbXM1MzY0MjklMjhWUy44NSUyOS5hc3B4CmlmICggIWFzc2VydChmdW5jdGlvbiggZGl2ICkgewoJZGl2LmlubmVySFRNTCA9ICI8YSBocmVmPScjJz48L2E+IjsKCXJldHVybiBkaXYuZmlyc3RDaGlsZC5nZXRBdHRyaWJ1dGUoImhyZWYiKSA9PT0gIiMiIDsKfSkgKSB7CglhZGRIYW5kbGUoICJ0eXBlfGhyZWZ8aGVpZ2h0fHdpZHRoIiwgZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGlzWE1MICkgewoJCWlmICggIWlzWE1MICkgewoJCQlyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoIG5hbWUsIG5hbWUudG9Mb3dlckNhc2UoKSA9PT0gInR5cGUiID8gMSA6IDIgKTsKCQl9Cgl9KTsKfQoKLy8gU3VwcG9ydDogSUU8OQovLyBVc2UgZGVmYXVsdFZhbHVlIGluIHBsYWNlIG9mIGdldEF0dHJpYnV0ZSgidmFsdWUiKQppZiAoICFzdXBwb3J0LmF0dHJpYnV0ZXMgfHwgIWFzc2VydChmdW5jdGlvbiggZGl2ICkgewoJZGl2LmlubmVySFRNTCA9ICI8aW5wdXQvPiI7CglkaXYuZmlyc3RDaGlsZC5zZXRBdHRyaWJ1dGUoICJ2YWx1ZSIsICIiICk7CglyZXR1cm4gZGl2LmZpcnN0Q2hpbGQuZ2V0QXR0cmlidXRlKCAidmFsdWUiICkgPT09ICIiOwp9KSApIHsKCWFkZEhhbmRsZSggInZhbHVlIiwgZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGlzWE1MICkgewoJCWlmICggIWlzWE1MICYmIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gImlucHV0IiApIHsKCQkJcmV0dXJuIGVsZW0uZGVmYXVsdFZhbHVlOwoJCX0KCX0pOwp9CgovLyBTdXBwb3J0OiBJRTw5Ci8vIFVzZSBnZXRBdHRyaWJ1dGVOb2RlIHRvIGZldGNoIGJvb2xlYW5zIHdoZW4gZ2V0QXR0cmlidXRlIGxpZXMKaWYgKCAhYXNzZXJ0KGZ1bmN0aW9uKCBkaXYgKSB7CglyZXR1cm4gZGl2LmdldEF0dHJpYnV0ZSgiZGlzYWJsZWQiKSA9PSBudWxsOwp9KSApIHsKCWFkZEhhbmRsZSggYm9vbGVhbnMsIGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCBpc1hNTCApIHsKCQl2YXIgdmFsOwoJCWlmICggIWlzWE1MICkgewoJCQlyZXR1cm4gZWxlbVsgbmFtZSBdID09PSB0cnVlID8gbmFtZS50b0xvd2VyQ2FzZSgpIDoKCQkJCQkodmFsID0gZWxlbS5nZXRBdHRyaWJ1dGVOb2RlKCBuYW1lICkpICYmIHZhbC5zcGVjaWZpZWQgPwoJCQkJCXZhbC52YWx1ZSA6CgkJCQludWxsOwoJCX0KCX0pOwp9CgpyZXR1cm4gU2l6emxlOwoKfSkoIHdpbmRvdyApOwoKCgpqUXVlcnkuZmluZCA9IFNpenpsZTsKalF1ZXJ5LmV4cHIgPSBTaXp6bGUuc2VsZWN0b3JzOwpqUXVlcnkuZXhwclsiOiJdID0galF1ZXJ5LmV4cHIucHNldWRvczsKalF1ZXJ5LnVuaXF1ZSA9IFNpenpsZS51bmlxdWVTb3J0OwpqUXVlcnkudGV4dCA9IFNpenpsZS5nZXRUZXh0OwpqUXVlcnkuaXNYTUxEb2MgPSBTaXp6bGUuaXNYTUw7CmpRdWVyeS5jb250YWlucyA9IFNpenpsZS5jb250YWluczsKCgoKdmFyIHJuZWVkc0NvbnRleHQgPSBqUXVlcnkuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQ7Cgp2YXIgcnNpbmdsZVRhZyA9ICgvXjwoXHcrKVxzKlwvPz4oPzo8XC9cMT58KSQvKTsKCgoKdmFyIHJpc1NpbXBsZSA9IC9eLlteOiNcW1wuLF0qJC87CgovLyBJbXBsZW1lbnQgdGhlIGlkZW50aWNhbCBmdW5jdGlvbmFsaXR5IGZvciBmaWx0ZXIgYW5kIG5vdApmdW5jdGlvbiB3aW5ub3coIGVsZW1lbnRzLCBxdWFsaWZpZXIsIG5vdCApIHsKCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIHF1YWxpZmllciApICkgewoJCXJldHVybiBqUXVlcnkuZ3JlcCggZWxlbWVudHMsIGZ1bmN0aW9uKCBlbGVtLCBpICkgewoJCQkvKiBqc2hpbnQgLVcwMTggKi8KCQkJcmV0dXJuICEhcXVhbGlmaWVyLmNhbGwoIGVsZW0sIGksIGVsZW0gKSAhPT0gbm90OwoJCX0pOwoKCX0KCglpZiAoIHF1YWxpZmllci5ub2RlVHlwZSApIHsKCQlyZXR1cm4galF1ZXJ5LmdyZXAoIGVsZW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHsKCQkJcmV0dXJuICggZWxlbSA9PT0gcXVhbGlmaWVyICkgIT09IG5vdDsKCQl9KTsKCgl9CgoJaWYgKCB0eXBlb2YgcXVhbGlmaWVyID09PSAic3RyaW5nIiApIHsKCQlpZiAoIHJpc1NpbXBsZS50ZXN0KCBxdWFsaWZpZXIgKSApIHsKCQkJcmV0dXJuIGpRdWVyeS5maWx0ZXIoIHF1YWxpZmllciwgZWxlbWVudHMsIG5vdCApOwoJCX0KCgkJcXVhbGlmaWVyID0galF1ZXJ5LmZpbHRlciggcXVhbGlmaWVyLCBlbGVtZW50cyApOwoJfQoKCXJldHVybiBqUXVlcnkuZ3JlcCggZWxlbWVudHMsIGZ1bmN0aW9uKCBlbGVtICkgewoJCXJldHVybiAoIGluZGV4T2YuY2FsbCggcXVhbGlmaWVyLCBlbGVtICkgPj0gMCApICE9PSBub3Q7Cgl9KTsKfQoKalF1ZXJ5LmZpbHRlciA9IGZ1bmN0aW9uKCBleHByLCBlbGVtcywgbm90ICkgewoJdmFyIGVsZW0gPSBlbGVtc1sgMCBdOwoKCWlmICggbm90ICkgewoJCWV4cHIgPSAiOm5vdCgiICsgZXhwciArICIpIjsKCX0KCglyZXR1cm4gZWxlbXMubGVuZ3RoID09PSAxICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgPwoJCWpRdWVyeS5maW5kLm1hdGNoZXNTZWxlY3RvciggZWxlbSwgZXhwciApID8gWyBlbGVtIF0gOiBbXSA6CgkJalF1ZXJ5LmZpbmQubWF0Y2hlcyggZXhwciwgalF1ZXJ5LmdyZXAoIGVsZW1zLCBmdW5jdGlvbiggZWxlbSApIHsKCQkJcmV0dXJuIGVsZW0ubm9kZVR5cGUgPT09IDE7CgkJfSkpOwp9OwoKalF1ZXJ5LmZuLmV4dGVuZCh7CglmaW5kOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7CgkJdmFyIGksCgkJCWxlbiA9IHRoaXMubGVuZ3RoLAoJCQlyZXQgPSBbXSwKCQkJc2VsZiA9IHRoaXM7CgoJCWlmICggdHlwZW9mIHNlbGVjdG9yICE9PSAic3RyaW5nIiApIHsKCQkJcmV0dXJuIHRoaXMucHVzaFN0YWNrKCBqUXVlcnkoIHNlbGVjdG9yICkuZmlsdGVyKGZ1bmN0aW9uKCkgewoJCQkJZm9yICggaSA9IDA7IGkgPCBsZW47IGkrKyApIHsKCQkJCQlpZiAoIGpRdWVyeS5jb250YWlucyggc2VsZlsgaSBdLCB0aGlzICkgKSB7CgkJCQkJCXJldHVybiB0cnVlOwoJCQkJCX0KCQkJCX0KCQkJfSkgKTsKCQl9CgoJCWZvciAoIGkgPSAwOyBpIDwgbGVuOyBpKysgKSB7CgkJCWpRdWVyeS5maW5kKCBzZWxlY3Rvciwgc2VsZlsgaSBdLCByZXQgKTsKCQl9CgoJCS8vIE5lZWRlZCBiZWNhdXNlICQoIHNlbGVjdG9yLCBjb250ZXh0ICkgYmVjb21lcyAkKCBjb250ZXh0ICkuZmluZCggc2VsZWN0b3IgKQoJCXJldCA9IHRoaXMucHVzaFN0YWNrKCBsZW4gPiAxID8galF1ZXJ5LnVuaXF1ZSggcmV0ICkgOiByZXQgKTsKCQlyZXQuc2VsZWN0b3IgPSB0aGlzLnNlbGVjdG9yID8gdGhpcy5zZWxlY3RvciArICIgIiArIHNlbGVjdG9yIDogc2VsZWN0b3I7CgkJcmV0dXJuIHJldDsKCX0sCglmaWx0ZXI6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHsKCQlyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHdpbm5vdyh0aGlzLCBzZWxlY3RvciB8fCBbXSwgZmFsc2UpICk7Cgl9LAoJbm90OiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7CgkJcmV0dXJuIHRoaXMucHVzaFN0YWNrKCB3aW5ub3codGhpcywgc2VsZWN0b3IgfHwgW10sIHRydWUpICk7Cgl9LAoJaXM6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHsKCQlyZXR1cm4gISF3aW5ub3coCgkJCXRoaXMsCgoJCQkvLyBJZiB0aGlzIGlzIGEgcG9zaXRpb25hbC9yZWxhdGl2ZSBzZWxlY3RvciwgY2hlY2sgbWVtYmVyc2hpcCBpbiB0aGUgcmV0dXJuZWQgc2V0CgkJCS8vIHNvICQoInA6Zmlyc3QiKS5pcygicDpsYXN0Iikgd29uJ3QgcmV0dXJuIHRydWUgZm9yIGEgZG9jIHdpdGggdHdvICJwIi4KCQkJdHlwZW9mIHNlbGVjdG9yID09PSAic3RyaW5nIiAmJiBybmVlZHNDb250ZXh0LnRlc3QoIHNlbGVjdG9yICkgPwoJCQkJalF1ZXJ5KCBzZWxlY3RvciApIDoKCQkJCXNlbGVjdG9yIHx8IFtdLAoJCQlmYWxzZQoJCSkubGVuZ3RoOwoJfQp9KTsKCgovLyBJbml0aWFsaXplIGEgalF1ZXJ5IG9iamVjdAoKCi8vIEEgY2VudHJhbCByZWZlcmVuY2UgdG8gdGhlIHJvb3QgalF1ZXJ5KGRvY3VtZW50KQp2YXIgcm9vdGpRdWVyeSwKCgkvLyBBIHNpbXBsZSB3YXkgdG8gY2hlY2sgZm9yIEhUTUwgc3RyaW5ncwoJLy8gUHJpb3JpdGl6ZSAjaWQgb3ZlciA8dGFnPiB0byBhdm9pZCBYU1MgdmlhIGxvY2F0aW9uLmhhc2ggKCM5NTIxKQoJLy8gU3RyaWN0IEhUTUwgcmVjb2duaXRpb24gKCMxMTI5MDogbXVzdCBzdGFydCB3aXRoIDwpCglycXVpY2tFeHByID0gL14oPzpccyooPFtcd1xXXSs+KVtePl0qfCMoW1x3LV0qKSkkLywKCglpbml0ID0galF1ZXJ5LmZuLmluaXQgPSBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7CgkJdmFyIG1hdGNoLCBlbGVtOwoKCQkvLyBIQU5ETEU6ICQoIiIpLCAkKG51bGwpLCAkKHVuZGVmaW5lZCksICQoZmFsc2UpCgkJaWYgKCAhc2VsZWN0b3IgKSB7CgkJCXJldHVybiB0aGlzOwoJCX0KCgkJLy8gSGFuZGxlIEhUTUwgc3RyaW5ncwoJCWlmICggdHlwZW9mIHNlbGVjdG9yID09PSAic3RyaW5nIiApIHsKCQkJaWYgKCBzZWxlY3RvclswXSA9PT0gIjwiICYmIHNlbGVjdG9yWyBzZWxlY3Rvci5sZW5ndGggLSAxIF0gPT09ICI+IiAmJiBzZWxlY3Rvci5sZW5ndGggPj0gMyApIHsKCQkJCS8vIEFzc3VtZSB0aGF0IHN0cmluZ3MgdGhhdCBzdGFydCBhbmQgZW5kIHdpdGggPD4gYXJlIEhUTUwgYW5kIHNraXAgdGhlIHJlZ2V4IGNoZWNrCgkJCQltYXRjaCA9IFsgbnVsbCwgc2VsZWN0b3IsIG51bGwgXTsKCgkJCX0gZWxzZSB7CgkJCQltYXRjaCA9IHJxdWlja0V4cHIuZXhlYyggc2VsZWN0b3IgKTsKCQkJfQoKCQkJLy8gTWF0Y2ggaHRtbCBvciBtYWtlIHN1cmUgbm8gY29udGV4dCBpcyBzcGVjaWZpZWQgZm9yICNpZAoJCQlpZiAoIG1hdGNoICYmIChtYXRjaFsxXSB8fCAhY29udGV4dCkgKSB7CgoJCQkJLy8gSEFORExFOiAkKGh0bWwpIC0+ICQoYXJyYXkpCgkJCQlpZiAoIG1hdGNoWzFdICkgewoJCQkJCWNvbnRleHQgPSBjb250ZXh0IGluc3RhbmNlb2YgalF1ZXJ5ID8gY29udGV4dFswXSA6IGNvbnRleHQ7CgoJCQkJCS8vIHNjcmlwdHMgaXMgdHJ1ZSBmb3IgYmFjay1jb21wYXQKCQkJCQkvLyBJbnRlbnRpb25hbGx5IGxldCB0aGUgZXJyb3IgYmUgdGhyb3duIGlmIHBhcnNlSFRNTCBpcyBub3QgcHJlc2VudAoJCQkJCWpRdWVyeS5tZXJnZSggdGhpcywgalF1ZXJ5LnBhcnNlSFRNTCgKCQkJCQkJbWF0Y2hbMV0sCgkJCQkJCWNvbnRleHQgJiYgY29udGV4dC5ub2RlVHlwZSA/IGNvbnRleHQub3duZXJEb2N1bWVudCB8fCBjb250ZXh0IDogZG9jdW1lbnQsCgkJCQkJCXRydWUKCQkJCQkpICk7CgoJCQkJCS8vIEhBTkRMRTogJChodG1sLCBwcm9wcykKCQkJCQlpZiAoIHJzaW5nbGVUYWcudGVzdCggbWF0Y2hbMV0gKSAmJiBqUXVlcnkuaXNQbGFpbk9iamVjdCggY29udGV4dCApICkgewoJCQkJCQlmb3IgKCBtYXRjaCBpbiBjb250ZXh0ICkgewoJCQkJCQkJLy8gUHJvcGVydGllcyBvZiBjb250ZXh0IGFyZSBjYWxsZWQgYXMgbWV0aG9kcyBpZiBwb3NzaWJsZQoJCQkJCQkJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggdGhpc1sgbWF0Y2ggXSApICkgewoJCQkJCQkJCXRoaXNbIG1hdGNoIF0oIGNvbnRleHRbIG1hdGNoIF0gKTsKCgkJCQkJCQkvLyAuLi5hbmQgb3RoZXJ3aXNlIHNldCBhcyBhdHRyaWJ1dGVzCgkJCQkJCQl9IGVsc2UgewoJCQkJCQkJCXRoaXMuYXR0ciggbWF0Y2gsIGNvbnRleHRbIG1hdGNoIF0gKTsKCQkJCQkJCX0KCQkJCQkJfQoJCQkJCX0KCgkJCQkJcmV0dXJuIHRoaXM7CgoJCQkJLy8gSEFORExFOiAkKCNpZCkKCQkJCX0gZWxzZSB7CgkJCQkJZWxlbSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCBtYXRjaFsyXSApOwoKCQkJCQkvLyBDaGVjayBwYXJlbnROb2RlIHRvIGNhdGNoIHdoZW4gQmxhY2tiZXJyeSA0LjYgcmV0dXJucwoJCQkJCS8vIG5vZGVzIHRoYXQgYXJlIG5vIGxvbmdlciBpbiB0aGUgZG9jdW1lbnQgIzY5NjMKCQkJCQlpZiAoIGVsZW0gJiYgZWxlbS5wYXJlbnROb2RlICkgewoJCQkJCQkvLyBJbmplY3QgdGhlIGVsZW1lbnQgZGlyZWN0bHkgaW50byB0aGUgalF1ZXJ5IG9iamVjdAoJCQkJCQl0aGlzLmxlbmd0aCA9IDE7CgkJCQkJCXRoaXNbMF0gPSBlbGVtOwoJCQkJCX0KCgkJCQkJdGhpcy5jb250ZXh0ID0gZG9jdW1lbnQ7CgkJCQkJdGhpcy5zZWxlY3RvciA9IHNlbGVjdG9yOwoJCQkJCXJldHVybiB0aGlzOwoJCQkJfQoKCQkJLy8gSEFORExFOiAkKGV4cHIsICQoLi4uKSkKCQkJfSBlbHNlIGlmICggIWNvbnRleHQgfHwgY29udGV4dC5qcXVlcnkgKSB7CgkJCQlyZXR1cm4gKCBjb250ZXh0IHx8IHJvb3RqUXVlcnkgKS5maW5kKCBzZWxlY3RvciApOwoKCQkJLy8gSEFORExFOiAkKGV4cHIsIGNvbnRleHQpCgkJCS8vICh3aGljaCBpcyBqdXN0IGVxdWl2YWxlbnQgdG86ICQoY29udGV4dCkuZmluZChleHByKQoJCQl9IGVsc2UgewoJCQkJcmV0dXJuIHRoaXMuY29uc3RydWN0b3IoIGNvbnRleHQgKS5maW5kKCBzZWxlY3RvciApOwoJCQl9CgoJCS8vIEhBTkRMRTogJChET01FbGVtZW50KQoJCX0gZWxzZSBpZiAoIHNlbGVjdG9yLm5vZGVUeXBlICkgewoJCQl0aGlzLmNvbnRleHQgPSB0aGlzWzBdID0gc2VsZWN0b3I7CgkJCXRoaXMubGVuZ3RoID0gMTsKCQkJcmV0dXJuIHRoaXM7CgoJCS8vIEhBTkRMRTogJChmdW5jdGlvbikKCQkvLyBTaG9ydGN1dCBmb3IgZG9jdW1lbnQgcmVhZHkKCQl9IGVsc2UgaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggc2VsZWN0b3IgKSApIHsKCQkJcmV0dXJuIHR5cGVvZiByb290alF1ZXJ5LnJlYWR5ICE9PSAidW5kZWZpbmVkIiA/CgkJCQlyb290alF1ZXJ5LnJlYWR5KCBzZWxlY3RvciApIDoKCQkJCS8vIEV4ZWN1dGUgaW1tZWRpYXRlbHkgaWYgcmVhZHkgaXMgbm90IHByZXNlbnQKCQkJCXNlbGVjdG9yKCBqUXVlcnkgKTsKCQl9CgoJCWlmICggc2VsZWN0b3Iuc2VsZWN0b3IgIT09IHVuZGVmaW5lZCApIHsKCQkJdGhpcy5zZWxlY3RvciA9IHNlbGVjdG9yLnNlbGVjdG9yOwoJCQl0aGlzLmNvbnRleHQgPSBzZWxlY3Rvci5jb250ZXh0OwoJCX0KCgkJcmV0dXJuIGpRdWVyeS5tYWtlQXJyYXkoIHNlbGVjdG9yLCB0aGlzICk7Cgl9OwoKLy8gR2l2ZSB0aGUgaW5pdCBmdW5jdGlvbiB0aGUgalF1ZXJ5IHByb3RvdHlwZSBmb3IgbGF0ZXIgaW5zdGFudGlhdGlvbgppbml0LnByb3RvdHlwZSA9IGpRdWVyeS5mbjsKCi8vIEluaXRpYWxpemUgY2VudHJhbCByZWZlcmVuY2UKcm9vdGpRdWVyeSA9IGpRdWVyeSggZG9jdW1lbnQgKTsKCgp2YXIgcnBhcmVudHNwcmV2ID0gL14oPzpwYXJlbnRzfHByZXYoPzpVbnRpbHxBbGwpKS8sCgkvLyBtZXRob2RzIGd1YXJhbnRlZWQgdG8gcHJvZHVjZSBhIHVuaXF1ZSBzZXQgd2hlbiBzdGFydGluZyBmcm9tIGEgdW5pcXVlIHNldAoJZ3VhcmFudGVlZFVuaXF1ZSA9IHsKCQljaGlsZHJlbjogdHJ1ZSwKCQljb250ZW50czogdHJ1ZSwKCQluZXh0OiB0cnVlLAoJCXByZXY6IHRydWUKCX07CgpqUXVlcnkuZXh0ZW5kKHsKCWRpcjogZnVuY3Rpb24oIGVsZW0sIGRpciwgdW50aWwgKSB7CgkJdmFyIG1hdGNoZWQgPSBbXSwKCQkJdHJ1bmNhdGUgPSB1bnRpbCAhPT0gdW5kZWZpbmVkOwoKCQl3aGlsZSAoIChlbGVtID0gZWxlbVsgZGlyIF0pICYmIGVsZW0ubm9kZVR5cGUgIT09IDkgKSB7CgkJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHsKCQkJCWlmICggdHJ1bmNhdGUgJiYgalF1ZXJ5KCBlbGVtICkuaXMoIHVudGlsICkgKSB7CgkJCQkJYnJlYWs7CgkJCQl9CgkJCQltYXRjaGVkLnB1c2goIGVsZW0gKTsKCQkJfQoJCX0KCQlyZXR1cm4gbWF0Y2hlZDsKCX0sCgoJc2libGluZzogZnVuY3Rpb24oIG4sIGVsZW0gKSB7CgkJdmFyIG1hdGNoZWQgPSBbXTsKCgkJZm9yICggOyBuOyBuID0gbi5uZXh0U2libGluZyApIHsKCQkJaWYgKCBuLm5vZGVUeXBlID09PSAxICYmIG4gIT09IGVsZW0gKSB7CgkJCQltYXRjaGVkLnB1c2goIG4gKTsKCQkJfQoJCX0KCgkJcmV0dXJuIG1hdGNoZWQ7Cgl9Cn0pOwoKalF1ZXJ5LmZuLmV4dGVuZCh7CgloYXM6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7CgkJdmFyIHRhcmdldHMgPSBqUXVlcnkoIHRhcmdldCwgdGhpcyApLAoJCQlsID0gdGFyZ2V0cy5sZW5ndGg7CgoJCXJldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbigpIHsKCQkJdmFyIGkgPSAwOwoJCQlmb3IgKCA7IGkgPCBsOyBpKysgKSB7CgkJCQlpZiAoIGpRdWVyeS5jb250YWlucyggdGhpcywgdGFyZ2V0c1tpXSApICkgewoJCQkJCXJldHVybiB0cnVlOwoJCQkJfQoJCQl9CgkJfSk7Cgl9LAoKCWNsb3Nlc3Q6IGZ1bmN0aW9uKCBzZWxlY3RvcnMsIGNvbnRleHQgKSB7CgkJdmFyIGN1ciwKCQkJaSA9IDAsCgkJCWwgPSB0aGlzLmxlbmd0aCwKCQkJbWF0Y2hlZCA9IFtdLAoJCQlwb3MgPSBybmVlZHNDb250ZXh0LnRlc3QoIHNlbGVjdG9ycyApIHx8IHR5cGVvZiBzZWxlY3RvcnMgIT09ICJzdHJpbmciID8KCQkJCWpRdWVyeSggc2VsZWN0b3JzLCBjb250ZXh0IHx8IHRoaXMuY29udGV4dCApIDoKCQkJCTA7CgoJCWZvciAoIDsgaSA8IGw7IGkrKyApIHsKCQkJZm9yICggY3VyID0gdGhpc1tpXTsgY3VyICYmIGN1ciAhPT0gY29udGV4dDsgY3VyID0gY3VyLnBhcmVudE5vZGUgKSB7CgkJCQkvLyBBbHdheXMgc2tpcCBkb2N1bWVudCBmcmFnbWVudHMKCQkJCWlmICggY3VyLm5vZGVUeXBlIDwgMTEgJiYgKHBvcyA/CgkJCQkJcG9zLmluZGV4KGN1cikgPiAtMSA6CgoJCQkJCS8vIERvbid0IHBhc3Mgbm9uLWVsZW1lbnRzIHRvIFNpenpsZQoJCQkJCWN1ci5ub2RlVHlwZSA9PT0gMSAmJgoJCQkJCQlqUXVlcnkuZmluZC5tYXRjaGVzU2VsZWN0b3IoY3VyLCBzZWxlY3RvcnMpKSApIHsKCgkJCQkJbWF0Y2hlZC5wdXNoKCBjdXIgKTsKCQkJCQlicmVhazsKCQkJCX0KCQkJfQoJCX0KCgkJcmV0dXJuIHRoaXMucHVzaFN0YWNrKCBtYXRjaGVkLmxlbmd0aCA+IDEgPyBqUXVlcnkudW5pcXVlKCBtYXRjaGVkICkgOiBtYXRjaGVkICk7Cgl9LAoKCS8vIERldGVybWluZSB0aGUgcG9zaXRpb24gb2YgYW4gZWxlbWVudCB3aXRoaW4KCS8vIHRoZSBtYXRjaGVkIHNldCBvZiBlbGVtZW50cwoJaW5kZXg6IGZ1bmN0aW9uKCBlbGVtICkgewoKCQkvLyBObyBhcmd1bWVudCwgcmV0dXJuIGluZGV4IGluIHBhcmVudAoJCWlmICggIWVsZW0gKSB7CgkJCXJldHVybiAoIHRoaXNbIDAgXSAmJiB0aGlzWyAwIF0ucGFyZW50Tm9kZSApID8gdGhpcy5maXJzdCgpLnByZXZBbGwoKS5sZW5ndGggOiAtMTsKCQl9CgoJCS8vIGluZGV4IGluIHNlbGVjdG9yCgkJaWYgKCB0eXBlb2YgZWxlbSA9PT0gInN0cmluZyIgKSB7CgkJCXJldHVybiBpbmRleE9mLmNhbGwoIGpRdWVyeSggZWxlbSApLCB0aGlzWyAwIF0gKTsKCQl9CgoJCS8vIExvY2F0ZSB0aGUgcG9zaXRpb24gb2YgdGhlIGRlc2lyZWQgZWxlbWVudAoJCXJldHVybiBpbmRleE9mLmNhbGwoIHRoaXMsCgoJCQkvLyBJZiBpdCByZWNlaXZlcyBhIGpRdWVyeSBvYmplY3QsIHRoZSBmaXJzdCBlbGVtZW50IGlzIHVzZWQKCQkJZWxlbS5qcXVlcnkgPyBlbGVtWyAwIF0gOiBlbGVtCgkJKTsKCX0sCgoJYWRkOiBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7CgkJcmV0dXJuIHRoaXMucHVzaFN0YWNrKAoJCQlqUXVlcnkudW5pcXVlKAoJCQkJalF1ZXJ5Lm1lcmdlKCB0aGlzLmdldCgpLCBqUXVlcnkoIHNlbGVjdG9yLCBjb250ZXh0ICkgKQoJCQkpCgkJKTsKCX0sCgoJYWRkQmFjazogZnVuY3Rpb24oIHNlbGVjdG9yICkgewoJCXJldHVybiB0aGlzLmFkZCggc2VsZWN0b3IgPT0gbnVsbCA/CgkJCXRoaXMucHJldk9iamVjdCA6IHRoaXMucHJldk9iamVjdC5maWx0ZXIoc2VsZWN0b3IpCgkJKTsKCX0KfSk7CgpmdW5jdGlvbiBzaWJsaW5nKCBjdXIsIGRpciApIHsKCXdoaWxlICggKGN1ciA9IGN1cltkaXJdKSAmJiBjdXIubm9kZVR5cGUgIT09IDEgKSB7fQoJcmV0dXJuIGN1cjsKfQoKalF1ZXJ5LmVhY2goewoJcGFyZW50OiBmdW5jdGlvbiggZWxlbSApIHsKCQl2YXIgcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlOwoJCXJldHVybiBwYXJlbnQgJiYgcGFyZW50Lm5vZGVUeXBlICE9PSAxMSA/IHBhcmVudCA6IG51bGw7Cgl9LAoJcGFyZW50czogZnVuY3Rpb24oIGVsZW0gKSB7CgkJcmV0dXJuIGpRdWVyeS5kaXIoIGVsZW0sICJwYXJlbnROb2RlIiApOwoJfSwKCXBhcmVudHNVbnRpbDogZnVuY3Rpb24oIGVsZW0sIGksIHVudGlsICkgewoJCXJldHVybiBqUXVlcnkuZGlyKCBlbGVtLCAicGFyZW50Tm9kZSIsIHVudGlsICk7Cgl9LAoJbmV4dDogZnVuY3Rpb24oIGVsZW0gKSB7CgkJcmV0dXJuIHNpYmxpbmcoIGVsZW0sICJuZXh0U2libGluZyIgKTsKCX0sCglwcmV2OiBmdW5jdGlvbiggZWxlbSApIHsKCQlyZXR1cm4gc2libGluZyggZWxlbSwgInByZXZpb3VzU2libGluZyIgKTsKCX0sCgluZXh0QWxsOiBmdW5jdGlvbiggZWxlbSApIHsKCQlyZXR1cm4galF1ZXJ5LmRpciggZWxlbSwgIm5leHRTaWJsaW5nIiApOwoJfSwKCXByZXZBbGw6IGZ1bmN0aW9uKCBlbGVtICkgewoJCXJldHVybiBqUXVlcnkuZGlyKCBlbGVtLCAicHJldmlvdXNTaWJsaW5nIiApOwoJfSwKCW5leHRVbnRpbDogZnVuY3Rpb24oIGVsZW0sIGksIHVudGlsICkgewoJCXJldHVybiBqUXVlcnkuZGlyKCBlbGVtLCAibmV4dFNpYmxpbmciLCB1bnRpbCApOwoJfSwKCXByZXZVbnRpbDogZnVuY3Rpb24oIGVsZW0sIGksIHVudGlsICkgewoJCXJldHVybiBqUXVlcnkuZGlyKCBlbGVtLCAicHJldmlvdXNTaWJsaW5nIiwgdW50aWwgKTsKCX0sCglzaWJsaW5nczogZnVuY3Rpb24oIGVsZW0gKSB7CgkJcmV0dXJuIGpRdWVyeS5zaWJsaW5nKCAoIGVsZW0ucGFyZW50Tm9kZSB8fCB7fSApLmZpcnN0Q2hpbGQsIGVsZW0gKTsKCX0sCgljaGlsZHJlbjogZnVuY3Rpb24oIGVsZW0gKSB7CgkJcmV0dXJuIGpRdWVyeS5zaWJsaW5nKCBlbGVtLmZpcnN0Q2hpbGQgKTsKCX0sCgljb250ZW50czogZnVuY3Rpb24oIGVsZW0gKSB7CgkJcmV0dXJuIGVsZW0uY29udGVudERvY3VtZW50IHx8IGpRdWVyeS5tZXJnZSggW10sIGVsZW0uY2hpbGROb2RlcyApOwoJfQp9LCBmdW5jdGlvbiggbmFtZSwgZm4gKSB7CglqUXVlcnkuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCB1bnRpbCwgc2VsZWN0b3IgKSB7CgkJdmFyIG1hdGNoZWQgPSBqUXVlcnkubWFwKCB0aGlzLCBmbiwgdW50aWwgKTsKCgkJaWYgKCBuYW1lLnNsaWNlKCAtNSApICE9PSAiVW50aWwiICkgewoJCQlzZWxlY3RvciA9IHVudGlsOwoJCX0KCgkJaWYgKCBzZWxlY3RvciAmJiB0eXBlb2Ygc2VsZWN0b3IgPT09ICJzdHJpbmciICkgewoJCQltYXRjaGVkID0galF1ZXJ5LmZpbHRlciggc2VsZWN0b3IsIG1hdGNoZWQgKTsKCQl9CgoJCWlmICggdGhpcy5sZW5ndGggPiAxICkgewoJCQkvLyBSZW1vdmUgZHVwbGljYXRlcwoJCQlpZiAoICFndWFyYW50ZWVkVW5pcXVlWyBuYW1lIF0gKSB7CgkJCQlqUXVlcnkudW5pcXVlKCBtYXRjaGVkICk7CgkJCX0KCgkJCS8vIFJldmVyc2Ugb3JkZXIgZm9yIHBhcmVudHMqIGFuZCBwcmV2LWRlcml2YXRpdmVzCgkJCWlmICggcnBhcmVudHNwcmV2LnRlc3QoIG5hbWUgKSApIHsKCQkJCW1hdGNoZWQucmV2ZXJzZSgpOwoJCQl9CgkJfQoKCQlyZXR1cm4gdGhpcy5wdXNoU3RhY2soIG1hdGNoZWQgKTsKCX07Cn0pOwp2YXIgcm5vdHdoaXRlID0gKC9cUysvZyk7CgoKCi8vIFN0cmluZyB0byBPYmplY3Qgb3B0aW9ucyBmb3JtYXQgY2FjaGUKdmFyIG9wdGlvbnNDYWNoZSA9IHt9OwoKLy8gQ29udmVydCBTdHJpbmctZm9ybWF0dGVkIG9wdGlvbnMgaW50byBPYmplY3QtZm9ybWF0dGVkIG9uZXMgYW5kIHN0b3JlIGluIGNhY2hlCmZ1bmN0aW9uIGNyZWF0ZU9wdGlvbnMoIG9wdGlvbnMgKSB7Cgl2YXIgb2JqZWN0ID0gb3B0aW9uc0NhY2hlWyBvcHRpb25zIF0gPSB7fTsKCWpRdWVyeS5lYWNoKCBvcHRpb25zLm1hdGNoKCBybm90d2hpdGUgKSB8fCBbXSwgZnVuY3Rpb24oIF8sIGZsYWcgKSB7CgkJb2JqZWN0WyBmbGFnIF0gPSB0cnVlOwoJfSk7CglyZXR1cm4gb2JqZWN0Owp9CgovKgogKiBDcmVhdGUgYSBjYWxsYmFjayBsaXN0IHVzaW5nIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczoKICoKICoJb3B0aW9uczogYW4gb3B0aW9uYWwgbGlzdCBvZiBzcGFjZS1zZXBhcmF0ZWQgb3B0aW9ucyB0aGF0IHdpbGwgY2hhbmdlIGhvdwogKgkJCXRoZSBjYWxsYmFjayBsaXN0IGJlaGF2ZXMgb3IgYSBtb3JlIHRyYWRpdGlvbmFsIG9wdGlvbiBvYmplY3QKICoKICogQnkgZGVmYXVsdCBhIGNhbGxiYWNrIGxpc3Qgd2lsbCBhY3QgbGlrZSBhbiBldmVudCBjYWxsYmFjayBsaXN0IGFuZCBjYW4gYmUKICogImZpcmVkIiBtdWx0aXBsZSB0aW1lcy4KICoKICogUG9zc2libGUgb3B0aW9uczoKICoKICoJb25jZToJCQl3aWxsIGVuc3VyZSB0aGUgY2FsbGJhY2sgbGlzdCBjYW4gb25seSBiZSBmaXJlZCBvbmNlIChsaWtlIGEgRGVmZXJyZWQpCiAqCiAqCW1lbW9yeToJCQl3aWxsIGtlZXAgdHJhY2sgb2YgcHJldmlvdXMgdmFsdWVzIGFuZCB3aWxsIGNhbGwgYW55IGNhbGxiYWNrIGFkZGVkCiAqCQkJCQlhZnRlciB0aGUgbGlzdCBoYXMgYmVlbiBmaXJlZCByaWdodCBhd2F5IHdpdGggdGhlIGxhdGVzdCAibWVtb3JpemVkIgogKgkJCQkJdmFsdWVzIChsaWtlIGEgRGVmZXJyZWQpCiAqCiAqCXVuaXF1ZToJCQl3aWxsIGVuc3VyZSBhIGNhbGxiYWNrIGNhbiBvbmx5IGJlIGFkZGVkIG9uY2UgKG5vIGR1cGxpY2F0ZSBpbiB0aGUgbGlzdCkKICoKICoJc3RvcE9uRmFsc2U6CWludGVycnVwdCBjYWxsaW5ncyB3aGVuIGEgY2FsbGJhY2sgcmV0dXJucyBmYWxzZQogKgogKi8KalF1ZXJ5LkNhbGxiYWNrcyA9IGZ1bmN0aW9uKCBvcHRpb25zICkgewoKCS8vIENvbnZlcnQgb3B0aW9ucyBmcm9tIFN0cmluZy1mb3JtYXR0ZWQgdG8gT2JqZWN0LWZvcm1hdHRlZCBpZiBuZWVkZWQKCS8vICh3ZSBjaGVjayBpbiBjYWNoZSBmaXJzdCkKCW9wdGlvbnMgPSB0eXBlb2Ygb3B0aW9ucyA9PT0gInN0cmluZyIgPwoJCSggb3B0aW9uc0NhY2hlWyBvcHRpb25zIF0gfHwgY3JlYXRlT3B0aW9ucyggb3B0aW9ucyApICkgOgoJCWpRdWVyeS5leHRlbmQoIHt9LCBvcHRpb25zICk7CgoJdmFyIC8vIExhc3QgZmlyZSB2YWx1ZSAoZm9yIG5vbi1mb3JnZXR0YWJsZSBsaXN0cykKCQltZW1vcnksCgkJLy8gRmxhZyB0byBrbm93IGlmIGxpc3Qgd2FzIGFscmVhZHkgZmlyZWQKCQlmaXJlZCwKCQkvLyBGbGFnIHRvIGtub3cgaWYgbGlzdCBpcyBjdXJyZW50bHkgZmlyaW5nCgkJZmlyaW5nLAoJCS8vIEZpcnN0IGNhbGxiYWNrIHRvIGZpcmUgKHVzZWQgaW50ZXJuYWxseSBieSBhZGQgYW5kIGZpcmVXaXRoKQoJCWZpcmluZ1N0YXJ0LAoJCS8vIEVuZCBvZiB0aGUgbG9vcCB3aGVuIGZpcmluZwoJCWZpcmluZ0xlbmd0aCwKCQkvLyBJbmRleCBvZiBjdXJyZW50bHkgZmlyaW5nIGNhbGxiYWNrIChtb2RpZmllZCBieSByZW1vdmUgaWYgbmVlZGVkKQoJCWZpcmluZ0luZGV4LAoJCS8vIEFjdHVhbCBjYWxsYmFjayBsaXN0CgkJbGlzdCA9IFtdLAoJCS8vIFN0YWNrIG9mIGZpcmUgY2FsbHMgZm9yIHJlcGVhdGFibGUgbGlzdHMKCQlzdGFjayA9ICFvcHRpb25zLm9uY2UgJiYgW10sCgkJLy8gRmlyZSBjYWxsYmFja3MKCQlmaXJlID0gZnVuY3Rpb24oIGRhdGEgKSB7CgkJCW1lbW9yeSA9IG9wdGlvbnMubWVtb3J5ICYmIGRhdGE7CgkJCWZpcmVkID0gdHJ1ZTsKCQkJZmlyaW5nSW5kZXggPSBmaXJpbmdTdGFydCB8fCAwOwoJCQlmaXJpbmdTdGFydCA9IDA7CgkJCWZpcmluZ0xlbmd0aCA9IGxpc3QubGVuZ3RoOwoJCQlmaXJpbmcgPSB0cnVlOwoJCQlmb3IgKCA7IGxpc3QgJiYgZmlyaW5nSW5kZXggPCBmaXJpbmdMZW5ndGg7IGZpcmluZ0luZGV4KysgKSB7CgkJCQlpZiAoIGxpc3RbIGZpcmluZ0luZGV4IF0uYXBwbHkoIGRhdGFbIDAgXSwgZGF0YVsgMSBdICkgPT09IGZhbHNlICYmIG9wdGlvbnMuc3RvcE9uRmFsc2UgKSB7CgkJCQkJbWVtb3J5ID0gZmFsc2U7IC8vIFRvIHByZXZlbnQgZnVydGhlciBjYWxscyB1c2luZyBhZGQKCQkJCQlicmVhazsKCQkJCX0KCQkJfQoJCQlmaXJpbmcgPSBmYWxzZTsKCQkJaWYgKCBsaXN0ICkgewoJCQkJaWYgKCBzdGFjayApIHsKCQkJCQlpZiAoIHN0YWNrLmxlbmd0aCApIHsKCQkJCQkJZmlyZSggc3RhY2suc2hpZnQoKSApOwoJCQkJCX0KCQkJCX0gZWxzZSBpZiAoIG1lbW9yeSApIHsKCQkJCQlsaXN0ID0gW107CgkJCQl9IGVsc2UgewoJCQkJCXNlbGYuZGlzYWJsZSgpOwoJCQkJfQoJCQl9CgkJfSwKCQkvLyBBY3R1YWwgQ2FsbGJhY2tzIG9iamVjdAoJCXNlbGYgPSB7CgkJCS8vIEFkZCBhIGNhbGxiYWNrIG9yIGEgY29sbGVjdGlvbiBvZiBjYWxsYmFja3MgdG8gdGhlIGxpc3QKCQkJYWRkOiBmdW5jdGlvbigpIHsKCQkJCWlmICggbGlzdCApIHsKCQkJCQkvLyBGaXJzdCwgd2Ugc2F2ZSB0aGUgY3VycmVudCBsZW5ndGgKCQkJCQl2YXIgc3RhcnQgPSBsaXN0Lmxlbmd0aDsKCQkJCQkoZnVuY3Rpb24gYWRkKCBhcmdzICkgewoJCQkJCQlqUXVlcnkuZWFjaCggYXJncywgZnVuY3Rpb24oIF8sIGFyZyApIHsKCQkJCQkJCXZhciB0eXBlID0galF1ZXJ5LnR5cGUoIGFyZyApOwoJCQkJCQkJaWYgKCB0eXBlID09PSAiZnVuY3Rpb24iICkgewoJCQkJCQkJCWlmICggIW9wdGlvbnMudW5pcXVlIHx8ICFzZWxmLmhhcyggYXJnICkgKSB7CgkJCQkJCQkJCWxpc3QucHVzaCggYXJnICk7CgkJCQkJCQkJfQoJCQkJCQkJfSBlbHNlIGlmICggYXJnICYmIGFyZy5sZW5ndGggJiYgdHlwZSAhPT0gInN0cmluZyIgKSB7CgkJCQkJCQkJLy8gSW5zcGVjdCByZWN1cnNpdmVseQoJCQkJCQkJCWFkZCggYXJnICk7CgkJCQkJCQl9CgkJCQkJCX0pOwoJCQkJCX0pKCBhcmd1bWVudHMgKTsKCQkJCQkvLyBEbyB3ZSBuZWVkIHRvIGFkZCB0aGUgY2FsbGJhY2tzIHRvIHRoZQoJCQkJCS8vIGN1cnJlbnQgZmlyaW5nIGJhdGNoPwoJCQkJCWlmICggZmlyaW5nICkgewoJCQkJCQlmaXJpbmdMZW5ndGggPSBsaXN0Lmxlbmd0aDsKCQkJCQkvLyBXaXRoIG1lbW9yeSwgaWYgd2UncmUgbm90IGZpcmluZyB0aGVuCgkJCQkJLy8gd2Ugc2hvdWxkIGNhbGwgcmlnaHQgYXdheQoJCQkJCX0gZWxzZSBpZiAoIG1lbW9yeSApIHsKCQkJCQkJZmlyaW5nU3RhcnQgPSBzdGFydDsKCQkJCQkJZmlyZSggbWVtb3J5ICk7CgkJCQkJfQoJCQkJfQoJCQkJcmV0dXJuIHRoaXM7CgkJCX0sCgkJCS8vIFJlbW92ZSBhIGNhbGxiYWNrIGZyb20gdGhlIGxpc3QKCQkJcmVtb3ZlOiBmdW5jdGlvbigpIHsKCQkJCWlmICggbGlzdCApIHsKCQkJCQlqUXVlcnkuZWFjaCggYXJndW1lbnRzLCBmdW5jdGlvbiggXywgYXJnICkgewoJCQkJCQl2YXIgaW5kZXg7CgkJCQkJCXdoaWxlICggKCBpbmRleCA9IGpRdWVyeS5pbkFycmF5KCBhcmcsIGxpc3QsIGluZGV4ICkgKSA+IC0xICkgewoJCQkJCQkJbGlzdC5zcGxpY2UoIGluZGV4LCAxICk7CgkJCQkJCQkvLyBIYW5kbGUgZmlyaW5nIGluZGV4ZXMKCQkJCQkJCWlmICggZmlyaW5nICkgewoJCQkJCQkJCWlmICggaW5kZXggPD0gZmlyaW5nTGVuZ3RoICkgewoJCQkJCQkJCQlmaXJpbmdMZW5ndGgtLTsKCQkJCQkJCQl9CgkJCQkJCQkJaWYgKCBpbmRleCA8PSBmaXJpbmdJbmRleCApIHsKCQkJCQkJCQkJZmlyaW5nSW5kZXgtLTsKCQkJCQkJCQl9CgkJCQkJCQl9CgkJCQkJCX0KCQkJCQl9KTsKCQkJCX0KCQkJCXJldHVybiB0aGlzOwoJCQl9LAoJCQkvLyBDaGVjayBpZiBhIGdpdmVuIGNhbGxiYWNrIGlzIGluIHRoZSBsaXN0LgoJCQkvLyBJZiBubyBhcmd1bWVudCBpcyBnaXZlbiwgcmV0dXJuIHdoZXRoZXIgb3Igbm90IGxpc3QgaGFzIGNhbGxiYWNrcyBhdHRhY2hlZC4KCQkJaGFzOiBmdW5jdGlvbiggZm4gKSB7CgkJCQlyZXR1cm4gZm4gPyBqUXVlcnkuaW5BcnJheSggZm4sIGxpc3QgKSA+IC0xIDogISEoIGxpc3QgJiYgbGlzdC5sZW5ndGggKTsKCQkJfSwKCQkJLy8gUmVtb3ZlIGFsbCBjYWxsYmFja3MgZnJvbSB0aGUgbGlzdAoJCQllbXB0eTogZnVuY3Rpb24oKSB7CgkJCQlsaXN0ID0gW107CgkJCQlmaXJpbmdMZW5ndGggPSAwOwoJCQkJcmV0dXJuIHRoaXM7CgkJCX0sCgkJCS8vIEhhdmUgdGhlIGxpc3QgZG8gbm90aGluZyBhbnltb3JlCgkJCWRpc2FibGU6IGZ1bmN0aW9uKCkgewoJCQkJbGlzdCA9IHN0YWNrID0gbWVtb3J5ID0gdW5kZWZpbmVkOwoJCQkJcmV0dXJuIHRoaXM7CgkJCX0sCgkJCS8vIElzIGl0IGRpc2FibGVkPwoJCQlkaXNhYmxlZDogZnVuY3Rpb24oKSB7CgkJCQlyZXR1cm4gIWxpc3Q7CgkJCX0sCgkJCS8vIExvY2sgdGhlIGxpc3QgaW4gaXRzIGN1cnJlbnQgc3RhdGUKCQkJbG9jazogZnVuY3Rpb24oKSB7CgkJCQlzdGFjayA9IHVuZGVmaW5lZDsKCQkJCWlmICggIW1lbW9yeSApIHsKCQkJCQlzZWxmLmRpc2FibGUoKTsKCQkJCX0KCQkJCXJldHVybiB0aGlzOwoJCQl9LAoJCQkvLyBJcyBpdCBsb2NrZWQ/CgkJCWxvY2tlZDogZnVuY3Rpb24oKSB7CgkJCQlyZXR1cm4gIXN0YWNrOwoJCQl9LAoJCQkvLyBDYWxsIGFsbCBjYWxsYmFja3Mgd2l0aCB0aGUgZ2l2ZW4gY29udGV4dCBhbmQgYXJndW1lbnRzCgkJCWZpcmVXaXRoOiBmdW5jdGlvbiggY29udGV4dCwgYXJncyApIHsKCQkJCWlmICggbGlzdCAmJiAoICFmaXJlZCB8fCBzdGFjayApICkgewoJCQkJCWFyZ3MgPSBhcmdzIHx8IFtdOwoJCQkJCWFyZ3MgPSBbIGNvbnRleHQsIGFyZ3Muc2xpY2UgPyBhcmdzLnNsaWNlKCkgOiBhcmdzIF07CgkJCQkJaWYgKCBmaXJpbmcgKSB7CgkJCQkJCXN0YWNrLnB1c2goIGFyZ3MgKTsKCQkJCQl9IGVsc2UgewoJCQkJCQlmaXJlKCBhcmdzICk7CgkJCQkJfQoJCQkJfQoJCQkJcmV0dXJuIHRoaXM7CgkJCX0sCgkJCS8vIENhbGwgYWxsIHRoZSBjYWxsYmFja3Mgd2l0aCB0aGUgZ2l2ZW4gYXJndW1lbnRzCgkJCWZpcmU6IGZ1bmN0aW9uKCkgewoJCQkJc2VsZi5maXJlV2l0aCggdGhpcywgYXJndW1lbnRzICk7CgkJCQlyZXR1cm4gdGhpczsKCQkJfSwKCQkJLy8gVG8ga25vdyBpZiB0aGUgY2FsbGJhY2tzIGhhdmUgYWxyZWFkeSBiZWVuIGNhbGxlZCBhdCBsZWFzdCBvbmNlCgkJCWZpcmVkOiBmdW5jdGlvbigpIHsKCQkJCXJldHVybiAhIWZpcmVkOwoJCQl9CgkJfTsKCglyZXR1cm4gc2VsZjsKfTsKCgpqUXVlcnkuZXh0ZW5kKHsKCglEZWZlcnJlZDogZnVuY3Rpb24oIGZ1bmMgKSB7CgkJdmFyIHR1cGxlcyA9IFsKCQkJCS8vIGFjdGlvbiwgYWRkIGxpc3RlbmVyLCBsaXN0ZW5lciBsaXN0LCBmaW5hbCBzdGF0ZQoJCQkJWyAicmVzb2x2ZSIsICJkb25lIiwgalF1ZXJ5LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwgInJlc29sdmVkIiBdLAoJCQkJWyAicmVqZWN0IiwgImZhaWwiLCBqUXVlcnkuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLCAicmVqZWN0ZWQiIF0sCgkJCQlbICJub3RpZnkiLCAicHJvZ3Jlc3MiLCBqUXVlcnkuQ2FsbGJhY2tzKCJtZW1vcnkiKSBdCgkJCV0sCgkJCXN0YXRlID0gInBlbmRpbmciLAoJCQlwcm9taXNlID0gewoJCQkJc3RhdGU6IGZ1bmN0aW9uKCkgewoJCQkJCXJldHVybiBzdGF0ZTsKCQkJCX0sCgkJCQlhbHdheXM6IGZ1bmN0aW9uKCkgewoJCQkJCWRlZmVycmVkLmRvbmUoIGFyZ3VtZW50cyApLmZhaWwoIGFyZ3VtZW50cyApOwoJCQkJCXJldHVybiB0aGlzOwoJCQkJfSwKCQkJCXRoZW46IGZ1bmN0aW9uKCAvKiBmbkRvbmUsIGZuRmFpbCwgZm5Qcm9ncmVzcyAqLyApIHsKCQkJCQl2YXIgZm5zID0gYXJndW1lbnRzOwoJCQkJCXJldHVybiBqUXVlcnkuRGVmZXJyZWQoZnVuY3Rpb24oIG5ld0RlZmVyICkgewoJCQkJCQlqUXVlcnkuZWFjaCggdHVwbGVzLCBmdW5jdGlvbiggaSwgdHVwbGUgKSB7CgkJCQkJCQl2YXIgZm4gPSBqUXVlcnkuaXNGdW5jdGlvbiggZm5zWyBpIF0gKSAmJiBmbnNbIGkgXTsKCQkJCQkJCS8vIGRlZmVycmVkWyBkb25lIHwgZmFpbCB8IHByb2dyZXNzIF0gZm9yIGZvcndhcmRpbmcgYWN0aW9ucyB0byBuZXdEZWZlcgoJCQkJCQkJZGVmZXJyZWRbIHR1cGxlWzFdIF0oZnVuY3Rpb24oKSB7CgkJCQkJCQkJdmFyIHJldHVybmVkID0gZm4gJiYgZm4uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApOwoJCQkJCQkJCWlmICggcmV0dXJuZWQgJiYgalF1ZXJ5LmlzRnVuY3Rpb24oIHJldHVybmVkLnByb21pc2UgKSApIHsKCQkJCQkJCQkJcmV0dXJuZWQucHJvbWlzZSgpCgkJCQkJCQkJCQkuZG9uZSggbmV3RGVmZXIucmVzb2x2ZSApCgkJCQkJCQkJCQkuZmFpbCggbmV3RGVmZXIucmVqZWN0ICkKCQkJCQkJCQkJCS5wcm9ncmVzcyggbmV3RGVmZXIubm90aWZ5ICk7CgkJCQkJCQkJfSBlbHNlIHsKCQkJCQkJCQkJbmV3RGVmZXJbIHR1cGxlWyAwIF0gKyAiV2l0aCIgXSggdGhpcyA9PT0gcHJvbWlzZSA/IG5ld0RlZmVyLnByb21pc2UoKSA6IHRoaXMsIGZuID8gWyByZXR1cm5lZCBdIDogYXJndW1lbnRzICk7CgkJCQkJCQkJfQoJCQkJCQkJfSk7CgkJCQkJCX0pOwoJCQkJCQlmbnMgPSBudWxsOwoJCQkJCX0pLnByb21pc2UoKTsKCQkJCX0sCgkJCQkvLyBHZXQgYSBwcm9taXNlIGZvciB0aGlzIGRlZmVycmVkCgkJCQkvLyBJZiBvYmogaXMgcHJvdmlkZWQsIHRoZSBwcm9taXNlIGFzcGVjdCBpcyBhZGRlZCB0byB0aGUgb2JqZWN0CgkJCQlwcm9taXNlOiBmdW5jdGlvbiggb2JqICkgewoJCQkJCXJldHVybiBvYmogIT0gbnVsbCA/IGpRdWVyeS5leHRlbmQoIG9iaiwgcHJvbWlzZSApIDogcHJvbWlzZTsKCQkJCX0KCQkJfSwKCQkJZGVmZXJyZWQgPSB7fTsKCgkJLy8gS2VlcCBwaXBlIGZvciBiYWNrLWNvbXBhdAoJCXByb21pc2UucGlwZSA9IHByb21pc2UudGhlbjsKCgkJLy8gQWRkIGxpc3Qtc3BlY2lmaWMgbWV0aG9kcwoJCWpRdWVyeS5lYWNoKCB0dXBsZXMsIGZ1bmN0aW9uKCBpLCB0dXBsZSApIHsKCQkJdmFyIGxpc3QgPSB0dXBsZVsgMiBdLAoJCQkJc3RhdGVTdHJpbmcgPSB0dXBsZVsgMyBdOwoKCQkJLy8gcHJvbWlzZVsgZG9uZSB8IGZhaWwgfCBwcm9ncmVzcyBdID0gbGlzdC5hZGQKCQkJcHJvbWlzZVsgdHVwbGVbMV0gXSA9IGxpc3QuYWRkOwoKCQkJLy8gSGFuZGxlIHN0YXRlCgkJCWlmICggc3RhdGVTdHJpbmcgKSB7CgkJCQlsaXN0LmFkZChmdW5jdGlvbigpIHsKCQkJCQkvLyBzdGF0ZSA9IFsgcmVzb2x2ZWQgfCByZWplY3RlZCBdCgkJCQkJc3RhdGUgPSBzdGF0ZVN0cmluZzsKCgkJCQkvLyBbIHJlamVjdF9saXN0IHwgcmVzb2x2ZV9saXN0IF0uZGlzYWJsZTsgcHJvZ3Jlc3NfbGlzdC5sb2NrCgkJCQl9LCB0dXBsZXNbIGkgXiAxIF1bIDIgXS5kaXNhYmxlLCB0dXBsZXNbIDIgXVsgMiBdLmxvY2sgKTsKCQkJfQoKCQkJLy8gZGVmZXJyZWRbIHJlc29sdmUgfCByZWplY3QgfCBub3RpZnkgXQoJCQlkZWZlcnJlZFsgdHVwbGVbMF0gXSA9IGZ1bmN0aW9uKCkgewoJCQkJZGVmZXJyZWRbIHR1cGxlWzBdICsgIldpdGgiIF0oIHRoaXMgPT09IGRlZmVycmVkID8gcHJvbWlzZSA6IHRoaXMsIGFyZ3VtZW50cyApOwoJCQkJcmV0dXJuIHRoaXM7CgkJCX07CgkJCWRlZmVycmVkWyB0dXBsZVswXSArICJXaXRoIiBdID0gbGlzdC5maXJlV2l0aDsKCQl9KTsKCgkJLy8gTWFrZSB0aGUgZGVmZXJyZWQgYSBwcm9taXNlCgkJcHJvbWlzZS5wcm9taXNlKCBkZWZlcnJlZCApOwoKCQkvLyBDYWxsIGdpdmVuIGZ1bmMgaWYgYW55CgkJaWYgKCBmdW5jICkgewoJCQlmdW5jLmNhbGwoIGRlZmVycmVkLCBkZWZlcnJlZCApOwoJCX0KCgkJLy8gQWxsIGRvbmUhCgkJcmV0dXJuIGRlZmVycmVkOwoJfSwKCgkvLyBEZWZlcnJlZCBoZWxwZXIKCXdoZW46IGZ1bmN0aW9uKCBzdWJvcmRpbmF0ZSAvKiAsIC4uLiwgc3Vib3JkaW5hdGVOICovICkgewoJCXZhciBpID0gMCwKCQkJcmVzb2x2ZVZhbHVlcyA9IHNsaWNlLmNhbGwoIGFyZ3VtZW50cyApLAoJCQlsZW5ndGggPSByZXNvbHZlVmFsdWVzLmxlbmd0aCwKCgkJCS8vIHRoZSBjb3VudCBvZiB1bmNvbXBsZXRlZCBzdWJvcmRpbmF0ZXMKCQkJcmVtYWluaW5nID0gbGVuZ3RoICE9PSAxIHx8ICggc3Vib3JkaW5hdGUgJiYgalF1ZXJ5LmlzRnVuY3Rpb24oIHN1Ym9yZGluYXRlLnByb21pc2UgKSApID8gbGVuZ3RoIDogMCwKCgkJCS8vIHRoZSBtYXN0ZXIgRGVmZXJyZWQuIElmIHJlc29sdmVWYWx1ZXMgY29uc2lzdCBvZiBvbmx5IGEgc2luZ2xlIERlZmVycmVkLCBqdXN0IHVzZSB0aGF0LgoJCQlkZWZlcnJlZCA9IHJlbWFpbmluZyA9PT0gMSA/IHN1Ym9yZGluYXRlIDogalF1ZXJ5LkRlZmVycmVkKCksCgoJCQkvLyBVcGRhdGUgZnVuY3Rpb24gZm9yIGJvdGggcmVzb2x2ZSBhbmQgcHJvZ3Jlc3MgdmFsdWVzCgkJCXVwZGF0ZUZ1bmMgPSBmdW5jdGlvbiggaSwgY29udGV4dHMsIHZhbHVlcyApIHsKCQkJCXJldHVybiBmdW5jdGlvbiggdmFsdWUgKSB7CgkJCQkJY29udGV4dHNbIGkgXSA9IHRoaXM7CgkJCQkJdmFsdWVzWyBpIF0gPSBhcmd1bWVudHMubGVuZ3RoID4gMSA/IHNsaWNlLmNhbGwoIGFyZ3VtZW50cyApIDogdmFsdWU7CgkJCQkJaWYgKCB2YWx1ZXMgPT09IHByb2dyZXNzVmFsdWVzICkgewoJCQkJCQlkZWZlcnJlZC5ub3RpZnlXaXRoKCBjb250ZXh0cywgdmFsdWVzICk7CgkJCQkJfSBlbHNlIGlmICggISggLS1yZW1haW5pbmcgKSApIHsKCQkJCQkJZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGNvbnRleHRzLCB2YWx1ZXMgKTsKCQkJCQl9CgkJCQl9OwoJCQl9LAoKCQkJcHJvZ3Jlc3NWYWx1ZXMsIHByb2dyZXNzQ29udGV4dHMsIHJlc29sdmVDb250ZXh0czsKCgkJLy8gYWRkIGxpc3RlbmVycyB0byBEZWZlcnJlZCBzdWJvcmRpbmF0ZXM7IHRyZWF0IG90aGVycyBhcyByZXNvbHZlZAoJCWlmICggbGVuZ3RoID4gMSApIHsKCQkJcHJvZ3Jlc3NWYWx1ZXMgPSBuZXcgQXJyYXkoIGxlbmd0aCApOwoJCQlwcm9ncmVzc0NvbnRleHRzID0gbmV3IEFycmF5KCBsZW5ndGggKTsKCQkJcmVzb2x2ZUNvbnRleHRzID0gbmV3IEFycmF5KCBsZW5ndGggKTsKCQkJZm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7CgkJCQlpZiAoIHJlc29sdmVWYWx1ZXNbIGkgXSAmJiBqUXVlcnkuaXNGdW5jdGlvbiggcmVzb2x2ZVZhbHVlc1sgaSBdLnByb21pc2UgKSApIHsKCQkJCQlyZXNvbHZlVmFsdWVzWyBpIF0ucHJvbWlzZSgpCgkJCQkJCS5kb25lKCB1cGRhdGVGdW5jKCBpLCByZXNvbHZlQ29udGV4dHMsIHJlc29sdmVWYWx1ZXMgKSApCgkJCQkJCS5mYWlsKCBkZWZlcnJlZC5yZWplY3QgKQoJCQkJCQkucHJvZ3Jlc3MoIHVwZGF0ZUZ1bmMoIGksIHByb2dyZXNzQ29udGV4dHMsIHByb2dyZXNzVmFsdWVzICkgKTsKCQkJCX0gZWxzZSB7CgkJCQkJLS1yZW1haW5pbmc7CgkJCQl9CgkJCX0KCQl9CgoJCS8vIGlmIHdlJ3JlIG5vdCB3YWl0aW5nIG9uIGFueXRoaW5nLCByZXNvbHZlIHRoZSBtYXN0ZXIKCQlpZiAoICFyZW1haW5pbmcgKSB7CgkJCWRlZmVycmVkLnJlc29sdmVXaXRoKCByZXNvbHZlQ29udGV4dHMsIHJlc29sdmVWYWx1ZXMgKTsKCQl9CgoJCXJldHVybiBkZWZlcnJlZC5wcm9taXNlKCk7Cgl9Cn0pOwoKCi8vIFRoZSBkZWZlcnJlZCB1c2VkIG9uIERPTSByZWFkeQp2YXIgcmVhZHlMaXN0OwoKalF1ZXJ5LmZuLnJlYWR5ID0gZnVuY3Rpb24oIGZuICkgewoJLy8gQWRkIHRoZSBjYWxsYmFjawoJalF1ZXJ5LnJlYWR5LnByb21pc2UoKS5kb25lKCBmbiApOwoKCXJldHVybiB0aGlzOwp9OwoKalF1ZXJ5LmV4dGVuZCh7CgkvLyBJcyB0aGUgRE9NIHJlYWR5IHRvIGJlIHVzZWQ/IFNldCB0byB0cnVlIG9uY2UgaXQgb2NjdXJzLgoJaXNSZWFkeTogZmFsc2UsCgoJLy8gQSBjb3VudGVyIHRvIHRyYWNrIGhvdyBtYW55IGl0ZW1zIHRvIHdhaXQgZm9yIGJlZm9yZQoJLy8gdGhlIHJlYWR5IGV2ZW50IGZpcmVzLiBTZWUgIzY3ODEKCXJlYWR5V2FpdDogMSwKCgkvLyBIb2xkIChvciByZWxlYXNlKSB0aGUgcmVhZHkgZXZlbnQKCWhvbGRSZWFkeTogZnVuY3Rpb24oIGhvbGQgKSB7CgkJaWYgKCBob2xkICkgewoJCQlqUXVlcnkucmVhZHlXYWl0Kys7CgkJfSBlbHNlIHsKCQkJalF1ZXJ5LnJlYWR5KCB0cnVlICk7CgkJfQoJfSwKCgkvLyBIYW5kbGUgd2hlbiB0aGUgRE9NIGlzIHJlYWR5CglyZWFkeTogZnVuY3Rpb24oIHdhaXQgKSB7CgoJCS8vIEFib3J0IGlmIHRoZXJlIGFyZSBwZW5kaW5nIGhvbGRzIG9yIHdlJ3JlIGFscmVhZHkgcmVhZHkKCQlpZiAoIHdhaXQgPT09IHRydWUgPyAtLWpRdWVyeS5yZWFkeVdhaXQgOiBqUXVlcnkuaXNSZWFkeSApIHsKCQkJcmV0dXJuOwoJCX0KCgkJLy8gUmVtZW1iZXIgdGhhdCB0aGUgRE9NIGlzIHJlYWR5CgkJalF1ZXJ5LmlzUmVhZHkgPSB0cnVlOwoKCQkvLyBJZiBhIG5vcm1hbCBET00gUmVhZHkgZXZlbnQgZmlyZWQsIGRlY3JlbWVudCwgYW5kIHdhaXQgaWYgbmVlZCBiZQoJCWlmICggd2FpdCAhPT0gdHJ1ZSAmJiAtLWpRdWVyeS5yZWFkeVdhaXQgPiAwICkgewoJCQlyZXR1cm47CgkJfQoKCQkvLyBJZiB0aGVyZSBhcmUgZnVuY3Rpb25zIGJvdW5kLCB0byBleGVjdXRlCgkJcmVhZHlMaXN0LnJlc29sdmVXaXRoKCBkb2N1bWVudCwgWyBqUXVlcnkgXSApOwoKCQkvLyBUcmlnZ2VyIGFueSBib3VuZCByZWFkeSBldmVudHMKCQlpZiAoIGpRdWVyeS5mbi50cmlnZ2VySGFuZGxlciApIHsKCQkJalF1ZXJ5KCBkb2N1bWVudCApLnRyaWdnZXJIYW5kbGVyKCAicmVhZHkiICk7CgkJCWpRdWVyeSggZG9jdW1lbnQgKS5vZmYoICJyZWFkeSIgKTsKCQl9Cgl9Cn0pOwoKLyoqCiAqIFRoZSByZWFkeSBldmVudCBoYW5kbGVyIGFuZCBzZWxmIGNsZWFudXAgbWV0aG9kCiAqLwpmdW5jdGlvbiBjb21wbGV0ZWQoKSB7Cglkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCAiRE9NQ29udGVudExvYWRlZCIsIGNvbXBsZXRlZCwgZmFsc2UgKTsKCXdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCAibG9hZCIsIGNvbXBsZXRlZCwgZmFsc2UgKTsKCWpRdWVyeS5yZWFkeSgpOwp9CgpqUXVlcnkucmVhZHkucHJvbWlzZSA9IGZ1bmN0aW9uKCBvYmogKSB7CglpZiAoICFyZWFkeUxpc3QgKSB7CgoJCXJlYWR5TGlzdCA9IGpRdWVyeS5EZWZlcnJlZCgpOwoKCQkvLyBDYXRjaCBjYXNlcyB3aGVyZSAkKGRvY3VtZW50KS5yZWFkeSgpIGlzIGNhbGxlZCBhZnRlciB0aGUgYnJvd3NlciBldmVudCBoYXMgYWxyZWFkeSBvY2N1cnJlZC4KCQkvLyB3ZSBvbmNlIHRyaWVkIHRvIHVzZSByZWFkeVN0YXRlICJpbnRlcmFjdGl2ZSIgaGVyZSwgYnV0IGl0IGNhdXNlZCBpc3N1ZXMgbGlrZSB0aGUgb25lCgkJLy8gZGlzY292ZXJlZCBieSBDaHJpc1MgaGVyZTogaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTIyODIjY29tbWVudDoxNQoJCWlmICggZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gImNvbXBsZXRlIiApIHsKCQkJLy8gSGFuZGxlIGl0IGFzeW5jaHJvbm91c2x5IHRvIGFsbG93IHNjcmlwdHMgdGhlIG9wcG9ydHVuaXR5IHRvIGRlbGF5IHJlYWR5CgkJCXNldFRpbWVvdXQoIGpRdWVyeS5yZWFkeSApOwoKCQl9IGVsc2UgewoKCQkJLy8gVXNlIHRoZSBoYW5keSBldmVudCBjYWxsYmFjawoJCQlkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCAiRE9NQ29udGVudExvYWRlZCIsIGNvbXBsZXRlZCwgZmFsc2UgKTsKCgkJCS8vIEEgZmFsbGJhY2sgdG8gd2luZG93Lm9ubG9hZCwgdGhhdCB3aWxsIGFsd2F5cyB3b3JrCgkJCXdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCAibG9hZCIsIGNvbXBsZXRlZCwgZmFsc2UgKTsKCQl9Cgl9CglyZXR1cm4gcmVhZHlMaXN0LnByb21pc2UoIG9iaiApOwp9OwoKLy8gS2ljayBvZmYgdGhlIERPTSByZWFkeSBjaGVjayBldmVuIGlmIHRoZSB1c2VyIGRvZXMgbm90CmpRdWVyeS5yZWFkeS5wcm9taXNlKCk7CgoKCgovLyBNdWx0aWZ1bmN0aW9uYWwgbWV0aG9kIHRvIGdldCBhbmQgc2V0IHZhbHVlcyBvZiBhIGNvbGxlY3Rpb24KLy8gVGhlIHZhbHVlL3MgY2FuIG9wdGlvbmFsbHkgYmUgZXhlY3V0ZWQgaWYgaXQncyBhIGZ1bmN0aW9uCnZhciBhY2Nlc3MgPSBqUXVlcnkuYWNjZXNzID0gZnVuY3Rpb24oIGVsZW1zLCBmbiwga2V5LCB2YWx1ZSwgY2hhaW5hYmxlLCBlbXB0eUdldCwgcmF3ICkgewoJdmFyIGkgPSAwLAoJCWxlbiA9IGVsZW1zLmxlbmd0aCwKCQlidWxrID0ga2V5ID09IG51bGw7CgoJLy8gU2V0cyBtYW55IHZhbHVlcwoJaWYgKCBqUXVlcnkudHlwZSgga2V5ICkgPT09ICJvYmplY3QiICkgewoJCWNoYWluYWJsZSA9IHRydWU7CgkJZm9yICggaSBpbiBrZXkgKSB7CgkJCWpRdWVyeS5hY2Nlc3MoIGVsZW1zLCBmbiwgaSwga2V5W2ldLCB0cnVlLCBlbXB0eUdldCwgcmF3ICk7CgkJfQoKCS8vIFNldHMgb25lIHZhbHVlCgl9IGVsc2UgaWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkgewoJCWNoYWluYWJsZSA9IHRydWU7CgoJCWlmICggIWpRdWVyeS5pc0Z1bmN0aW9uKCB2YWx1ZSApICkgewoJCQlyYXcgPSB0cnVlOwoJCX0KCgkJaWYgKCBidWxrICkgewoJCQkvLyBCdWxrIG9wZXJhdGlvbnMgcnVuIGFnYWluc3QgdGhlIGVudGlyZSBzZXQKCQkJaWYgKCByYXcgKSB7CgkJCQlmbi5jYWxsKCBlbGVtcywgdmFsdWUgKTsKCQkJCWZuID0gbnVsbDsKCgkJCS8vIC4uLmV4Y2VwdCB3aGVuIGV4ZWN1dGluZyBmdW5jdGlvbiB2YWx1ZXMKCQkJfSBlbHNlIHsKCQkJCWJ1bGsgPSBmbjsKCQkJCWZuID0gZnVuY3Rpb24oIGVsZW0sIGtleSwgdmFsdWUgKSB7CgkJCQkJcmV0dXJuIGJ1bGsuY2FsbCggalF1ZXJ5KCBlbGVtICksIHZhbHVlICk7CgkJCQl9OwoJCQl9CgkJfQoKCQlpZiAoIGZuICkgewoJCQlmb3IgKCA7IGkgPCBsZW47IGkrKyApIHsKCQkJCWZuKCBlbGVtc1tpXSwga2V5LCByYXcgPyB2YWx1ZSA6IHZhbHVlLmNhbGwoIGVsZW1zW2ldLCBpLCBmbiggZWxlbXNbaV0sIGtleSApICkgKTsKCQkJfQoJCX0KCX0KCglyZXR1cm4gY2hhaW5hYmxlID8KCQllbGVtcyA6CgoJCS8vIEdldHMKCQlidWxrID8KCQkJZm4uY2FsbCggZWxlbXMgKSA6CgkJCWxlbiA/IGZuKCBlbGVtc1swXSwga2V5ICkgOiBlbXB0eUdldDsKfTsKCgovKioKICogRGV0ZXJtaW5lcyB3aGV0aGVyIGFuIG9iamVjdCBjYW4gaGF2ZSBkYXRhCiAqLwpqUXVlcnkuYWNjZXB0RGF0YSA9IGZ1bmN0aW9uKCBvd25lciApIHsKCS8vIEFjY2VwdHMgb25seToKCS8vICAtIE5vZGUKCS8vICAgIC0gTm9kZS5FTEVNRU5UX05PREUKCS8vICAgIC0gTm9kZS5ET0NVTUVOVF9OT0RFCgkvLyAgLSBPYmplY3QKCS8vICAgIC0gQW55CgkvKiBqc2hpbnQgLVcwMTggKi8KCXJldHVybiBvd25lci5ub2RlVHlwZSA9PT0gMSB8fCBvd25lci5ub2RlVHlwZSA9PT0gOSB8fCAhKCArb3duZXIubm9kZVR5cGUgKTsKfTsKCgpmdW5jdGlvbiBEYXRhKCkgewoJLy8gU3VwcG9ydDogQW5kcm9pZCA8IDQsCgkvLyBPbGQgV2ViS2l0IGRvZXMgbm90IGhhdmUgT2JqZWN0LnByZXZlbnRFeHRlbnNpb25zL2ZyZWV6ZSBtZXRob2QsCgkvLyByZXR1cm4gbmV3IGVtcHR5IG9iamVjdCBpbnN0ZWFkIHdpdGggbm8gW1tzZXRdXSBhY2Nlc3NvcgoJT2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLmNhY2hlID0ge30sIDAsIHsKCQlnZXQ6IGZ1bmN0aW9uKCkgewoJCQlyZXR1cm4ge307CgkJfQoJfSk7CgoJdGhpcy5leHBhbmRvID0galF1ZXJ5LmV4cGFuZG8gKyBNYXRoLnJhbmRvbSgpOwp9CgpEYXRhLnVpZCA9IDE7CkRhdGEuYWNjZXB0cyA9IGpRdWVyeS5hY2NlcHREYXRhOwoKRGF0YS5wcm90b3R5cGUgPSB7CglrZXk6IGZ1bmN0aW9uKCBvd25lciApIHsKCQkvLyBXZSBjYW4gYWNjZXB0IGRhdGEgZm9yIG5vbi1lbGVtZW50IG5vZGVzIGluIG1vZGVybiBicm93c2VycywKCQkvLyBidXQgd2Ugc2hvdWxkIG5vdCwgc2VlICM4MzM1LgoJCS8vIEFsd2F5cyByZXR1cm4gdGhlIGtleSBmb3IgYSBmcm96ZW4gb2JqZWN0LgoJCWlmICggIURhdGEuYWNjZXB0cyggb3duZXIgKSApIHsKCQkJcmV0dXJuIDA7CgkJfQoKCQl2YXIgZGVzY3JpcHRvciA9IHt9LAoJCQkvLyBDaGVjayBpZiB0aGUgb3duZXIgb2JqZWN0IGFscmVhZHkgaGFzIGEgY2FjaGUga2V5CgkJCXVubG9jayA9IG93bmVyWyB0aGlzLmV4cGFuZG8gXTsKCgkJLy8gSWYgbm90LCBjcmVhdGUgb25lCgkJaWYgKCAhdW5sb2NrICkgewoJCQl1bmxvY2sgPSBEYXRhLnVpZCsrOwoKCQkJLy8gU2VjdXJlIGl0IGluIGEgbm9uLWVudW1lcmFibGUsIG5vbi13cml0YWJsZSBwcm9wZXJ0eQoJCQl0cnkgewoJCQkJZGVzY3JpcHRvclsgdGhpcy5leHBhbmRvIF0gPSB7IHZhbHVlOiB1bmxvY2sgfTsKCQkJCU9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKCBvd25lciwgZGVzY3JpcHRvciApOwoKCQkJLy8gU3VwcG9ydDogQW5kcm9pZCA8IDQKCQkJLy8gRmFsbGJhY2sgdG8gYSBsZXNzIHNlY3VyZSBkZWZpbml0aW9uCgkJCX0gY2F0Y2ggKCBlICkgewoJCQkJZGVzY3JpcHRvclsgdGhpcy5leHBhbmRvIF0gPSB1bmxvY2s7CgkJCQlqUXVlcnkuZXh0ZW5kKCBvd25lciwgZGVzY3JpcHRvciApOwoJCQl9CgkJfQoKCQkvLyBFbnN1cmUgdGhlIGNhY2hlIG9iamVjdAoJCWlmICggIXRoaXMuY2FjaGVbIHVubG9jayBdICkgewoJCQl0aGlzLmNhY2hlWyB1bmxvY2sgXSA9IHt9OwoJCX0KCgkJcmV0dXJuIHVubG9jazsKCX0sCglzZXQ6IGZ1bmN0aW9uKCBvd25lciwgZGF0YSwgdmFsdWUgKSB7CgkJdmFyIHByb3AsCgkJCS8vIFRoZXJlIG1heSBiZSBhbiB1bmxvY2sgYXNzaWduZWQgdG8gdGhpcyBub2RlLAoJCQkvLyBpZiB0aGVyZSBpcyBubyBlbnRyeSBmb3IgdGhpcyAib3duZXIiLCBjcmVhdGUgb25lIGlubGluZQoJCQkvLyBhbmQgc2V0IHRoZSB1bmxvY2sgYXMgdGhvdWdoIGFuIG93bmVyIGVudHJ5IGhhZCBhbHdheXMgZXhpc3RlZAoJCQl1bmxvY2sgPSB0aGlzLmtleSggb3duZXIgKSwKCQkJY2FjaGUgPSB0aGlzLmNhY2hlWyB1bmxvY2sgXTsKCgkJLy8gSGFuZGxlOiBbIG93bmVyLCBrZXksIHZhbHVlIF0gYXJncwoJCWlmICggdHlwZW9mIGRhdGEgPT09ICJzdHJpbmciICkgewoJCQljYWNoZVsgZGF0YSBdID0gdmFsdWU7CgoJCS8vIEhhbmRsZTogWyBvd25lciwgeyBwcm9wZXJ0aWVzIH0gXSBhcmdzCgkJfSBlbHNlIHsKCQkJLy8gRnJlc2ggYXNzaWdubWVudHMgYnkgb2JqZWN0IGFyZSBzaGFsbG93IGNvcGllZAoJCQlpZiAoIGpRdWVyeS5pc0VtcHR5T2JqZWN0KCBjYWNoZSApICkgewoJCQkJalF1ZXJ5LmV4dGVuZCggdGhpcy5jYWNoZVsgdW5sb2NrIF0sIGRhdGEgKTsKCQkJLy8gT3RoZXJ3aXNlLCBjb3B5IHRoZSBwcm9wZXJ0aWVzIG9uZS1ieS1vbmUgdG8gdGhlIGNhY2hlIG9iamVjdAoJCQl9IGVsc2UgewoJCQkJZm9yICggcHJvcCBpbiBkYXRhICkgewoJCQkJCWNhY2hlWyBwcm9wIF0gPSBkYXRhWyBwcm9wIF07CgkJCQl9CgkJCX0KCQl9CgkJcmV0dXJuIGNhY2hlOwoJfSwKCWdldDogZnVuY3Rpb24oIG93bmVyLCBrZXkgKSB7CgkJLy8gRWl0aGVyIGEgdmFsaWQgY2FjaGUgaXMgZm91bmQsIG9yIHdpbGwgYmUgY3JlYXRlZC4KCQkvLyBOZXcgY2FjaGVzIHdpbGwgYmUgY3JlYXRlZCBhbmQgdGhlIHVubG9jayByZXR1cm5lZCwKCQkvLyBhbGxvd2luZyBkaXJlY3QgYWNjZXNzIHRvIHRoZSBuZXdseSBjcmVhdGVkCgkJLy8gZW1wdHkgZGF0YSBvYmplY3QuIEEgdmFsaWQgb3duZXIgb2JqZWN0IG11c3QgYmUgcHJvdmlkZWQuCgkJdmFyIGNhY2hlID0gdGhpcy5jYWNoZVsgdGhpcy5rZXkoIG93bmVyICkgXTsKCgkJcmV0dXJuIGtleSA9PT0gdW5kZWZpbmVkID8KCQkJY2FjaGUgOiBjYWNoZVsga2V5IF07Cgl9LAoJYWNjZXNzOiBmdW5jdGlvbiggb3duZXIsIGtleSwgdmFsdWUgKSB7CgkJdmFyIHN0b3JlZDsKCQkvLyBJbiBjYXNlcyB3aGVyZSBlaXRoZXI6CgkJLy8KCQkvLyAgIDEuIE5vIGtleSB3YXMgc3BlY2lmaWVkCgkJLy8gICAyLiBBIHN0cmluZyBrZXkgd2FzIHNwZWNpZmllZCwgYnV0IG5vIHZhbHVlIHByb3ZpZGVkCgkJLy8KCQkvLyBUYWtlIHRoZSAicmVhZCIgcGF0aCBhbmQgYWxsb3cgdGhlIGdldCBtZXRob2QgdG8gZGV0ZXJtaW5lCgkJLy8gd2hpY2ggdmFsdWUgdG8gcmV0dXJuLCByZXNwZWN0aXZlbHkgZWl0aGVyOgoJCS8vCgkJLy8gICAxLiBUaGUgZW50aXJlIGNhY2hlIG9iamVjdAoJCS8vICAgMi4gVGhlIGRhdGEgc3RvcmVkIGF0IHRoZSBrZXkKCQkvLwoJCWlmICgga2V5ID09PSB1bmRlZmluZWQgfHwKCQkJCSgoa2V5ICYmIHR5cGVvZiBrZXkgPT09ICJzdHJpbmciKSAmJiB2YWx1ZSA9PT0gdW5kZWZpbmVkKSApIHsKCgkJCXN0b3JlZCA9IHRoaXMuZ2V0KCBvd25lciwga2V5ICk7CgoJCQlyZXR1cm4gc3RvcmVkICE9PSB1bmRlZmluZWQgPwoJCQkJc3RvcmVkIDogdGhpcy5nZXQoIG93bmVyLCBqUXVlcnkuY2FtZWxDYXNlKGtleSkgKTsKCQl9CgoJCS8vIFsqXVdoZW4gdGhlIGtleSBpcyBub3QgYSBzdHJpbmcsIG9yIGJvdGggYSBrZXkgYW5kIHZhbHVlCgkJLy8gYXJlIHNwZWNpZmllZCwgc2V0IG9yIGV4dGVuZCAoZXhpc3Rpbmcgb2JqZWN0cykgd2l0aCBlaXRoZXI6CgkJLy8KCQkvLyAgIDEuIEFuIG9iamVjdCBvZiBwcm9wZXJ0aWVzCgkJLy8gICAyLiBBIGtleSBhbmQgdmFsdWUKCQkvLwoJCXRoaXMuc2V0KCBvd25lciwga2V5LCB2YWx1ZSApOwoKCQkvLyBTaW5jZSB0aGUgInNldCIgcGF0aCBjYW4gaGF2ZSB0d28gcG9zc2libGUgZW50cnkgcG9pbnRzCgkJLy8gcmV0dXJuIHRoZSBleHBlY3RlZCBkYXRhIGJhc2VkIG9uIHdoaWNoIHBhdGggd2FzIHRha2VuWypdCgkJcmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgPyB2YWx1ZSA6IGtleTsKCX0sCglyZW1vdmU6IGZ1bmN0aW9uKCBvd25lciwga2V5ICkgewoJCXZhciBpLCBuYW1lLCBjYW1lbCwKCQkJdW5sb2NrID0gdGhpcy5rZXkoIG93bmVyICksCgkJCWNhY2hlID0gdGhpcy5jYWNoZVsgdW5sb2NrIF07CgoJCWlmICgga2V5ID09PSB1bmRlZmluZWQgKSB7CgkJCXRoaXMuY2FjaGVbIHVubG9jayBdID0ge307CgoJCX0gZWxzZSB7CgkJCS8vIFN1cHBvcnQgYXJyYXkgb3Igc3BhY2Ugc2VwYXJhdGVkIHN0cmluZyBvZiBrZXlzCgkJCWlmICggalF1ZXJ5LmlzQXJyYXkoIGtleSApICkgewoJCQkJLy8gSWYgIm5hbWUiIGlzIGFuIGFycmF5IG9mIGtleXMuLi4KCQkJCS8vIFdoZW4gZGF0YSBpcyBpbml0aWFsbHkgY3JlYXRlZCwgdmlhICgia2V5IiwgInZhbCIpIHNpZ25hdHVyZSwKCQkJCS8vIGtleXMgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gY2FtZWxDYXNlLgoJCQkJLy8gU2luY2UgdGhlcmUgaXMgbm8gd2F5IHRvIHRlbGwgX2hvd18gYSBrZXkgd2FzIGFkZGVkLCByZW1vdmUKCQkJCS8vIGJvdGggcGxhaW4ga2V5IGFuZCBjYW1lbENhc2Uga2V5LiAjMTI3ODYKCQkJCS8vIFRoaXMgd2lsbCBvbmx5IHBlbmFsaXplIHRoZSBhcnJheSBhcmd1bWVudCBwYXRoLgoJCQkJbmFtZSA9IGtleS5jb25jYXQoIGtleS5tYXAoIGpRdWVyeS5jYW1lbENhc2UgKSApOwoJCQl9IGVsc2UgewoJCQkJY2FtZWwgPSBqUXVlcnkuY2FtZWxDYXNlKCBrZXkgKTsKCQkJCS8vIFRyeSB0aGUgc3RyaW5nIGFzIGEga2V5IGJlZm9yZSBhbnkgbWFuaXB1bGF0aW9uCgkJCQlpZiAoIGtleSBpbiBjYWNoZSApIHsKCQkJCQluYW1lID0gWyBrZXksIGNhbWVsIF07CgkJCQl9IGVsc2UgewoJCQkJCS8vIElmIGEga2V5IHdpdGggdGhlIHNwYWNlcyBleGlzdHMsIHVzZSBpdC4KCQkJCQkvLyBPdGhlcndpc2UsIGNyZWF0ZSBhbiBhcnJheSBieSBtYXRjaGluZyBub24td2hpdGVzcGFjZQoJCQkJCW5hbWUgPSBjYW1lbDsKCQkJCQluYW1lID0gbmFtZSBpbiBjYWNoZSA/CgkJCQkJCVsgbmFtZSBdIDogKCBuYW1lLm1hdGNoKCBybm90d2hpdGUgKSB8fCBbXSApOwoJCQkJfQoJCQl9CgoJCQlpID0gbmFtZS5sZW5ndGg7CgkJCXdoaWxlICggaS0tICkgewoJCQkJZGVsZXRlIGNhY2hlWyBuYW1lWyBpIF0gXTsKCQkJfQoJCX0KCX0sCgloYXNEYXRhOiBmdW5jdGlvbiggb3duZXIgKSB7CgkJcmV0dXJuICFqUXVlcnkuaXNFbXB0eU9iamVjdCgKCQkJdGhpcy5jYWNoZVsgb3duZXJbIHRoaXMuZXhwYW5kbyBdIF0gfHwge30KCQkpOwoJfSwKCWRpc2NhcmQ6IGZ1bmN0aW9uKCBvd25lciApIHsKCQlpZiAoIG93bmVyWyB0aGlzLmV4cGFuZG8gXSApIHsKCQkJZGVsZXRlIHRoaXMuY2FjaGVbIG93bmVyWyB0aGlzLmV4cGFuZG8gXSBdOwoJCX0KCX0KfTsKdmFyIGRhdGFfcHJpdiA9IG5ldyBEYXRhKCk7Cgp2YXIgZGF0YV91c2VyID0gbmV3IERhdGEoKTsKCgoKLyoKCUltcGxlbWVudGF0aW9uIFN1bW1hcnkKCgkxLiBFbmZvcmNlIEFQSSBzdXJmYWNlIGFuZCBzZW1hbnRpYyBjb21wYXRpYmlsaXR5IHdpdGggMS45LnggYnJhbmNoCgkyLiBJbXByb3ZlIHRoZSBtb2R1bGUncyBtYWludGFpbmFiaWxpdHkgYnkgcmVkdWNpbmcgdGhlIHN0b3JhZ2UKCQlwYXRocyB0byBhIHNpbmdsZSBtZWNoYW5pc20uCgkzLiBVc2UgdGhlIHNhbWUgc2luZ2xlIG1lY2hhbmlzbSB0byBzdXBwb3J0ICJwcml2YXRlIiBhbmQgInVzZXIiIGRhdGEuCgk0LiBfTmV2ZXJfIGV4cG9zZSAicHJpdmF0ZSIgZGF0YSB0byB1c2VyIGNvZGUgKFRPRE86IERyb3AgX2RhdGEsIF9yZW1vdmVEYXRhKQoJNS4gQXZvaWQgZXhwb3NpbmcgaW1wbGVtZW50YXRpb24gZGV0YWlscyBvbiB1c2VyIG9iamVjdHMgKGVnLiBleHBhbmRvIHByb3BlcnRpZXMpCgk2LiBQcm92aWRlIGEgY2xlYXIgcGF0aCBmb3IgaW1wbGVtZW50YXRpb24gdXBncmFkZSB0byBXZWFrTWFwIGluIDIwMTQKKi8KdmFyIHJicmFjZSA9IC9eKD86XHtbXHdcV10qXH18XFtbXHdcV10qXF0pJC8sCglybXVsdGlEYXNoID0gLyhbQS1aXSkvZzsKCmZ1bmN0aW9uIGRhdGFBdHRyKCBlbGVtLCBrZXksIGRhdGEgKSB7Cgl2YXIgbmFtZTsKCgkvLyBJZiBub3RoaW5nIHdhcyBmb3VuZCBpbnRlcm5hbGx5LCB0cnkgdG8gZmV0Y2ggYW55CgkvLyBkYXRhIGZyb20gdGhlIEhUTUw1IGRhdGEtKiBhdHRyaWJ1dGUKCWlmICggZGF0YSA9PT0gdW5kZWZpbmVkICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7CgkJbmFtZSA9ICJkYXRhLSIgKyBrZXkucmVwbGFjZSggcm11bHRpRGFzaCwgIi0kMSIgKS50b0xvd2VyQ2FzZSgpOwoJCWRhdGEgPSBlbGVtLmdldEF0dHJpYnV0ZSggbmFtZSApOwoKCQlpZiAoIHR5cGVvZiBkYXRhID09PSAic3RyaW5nIiApIHsKCQkJdHJ5IHsKCQkJCWRhdGEgPSBkYXRhID09PSAidHJ1ZSIgPyB0cnVlIDoKCQkJCQlkYXRhID09PSAiZmFsc2UiID8gZmFsc2UgOgoJCQkJCWRhdGEgPT09ICJudWxsIiA/IG51bGwgOgoJCQkJCS8vIE9ubHkgY29udmVydCB0byBhIG51bWJlciBpZiBpdCBkb2Vzbid0IGNoYW5nZSB0aGUgc3RyaW5nCgkJCQkJK2RhdGEgKyAiIiA9PT0gZGF0YSA/ICtkYXRhIDoKCQkJCQlyYnJhY2UudGVzdCggZGF0YSApID8galF1ZXJ5LnBhcnNlSlNPTiggZGF0YSApIDoKCQkJCQlkYXRhOwoJCQl9IGNhdGNoKCBlICkge30KCgkJCS8vIE1ha2Ugc3VyZSB3ZSBzZXQgdGhlIGRhdGEgc28gaXQgaXNuJ3QgY2hhbmdlZCBsYXRlcgoJCQlkYXRhX3VzZXIuc2V0KCBlbGVtLCBrZXksIGRhdGEgKTsKCQl9IGVsc2UgewoJCQlkYXRhID0gdW5kZWZpbmVkOwoJCX0KCX0KCXJldHVybiBkYXRhOwp9CgpqUXVlcnkuZXh0ZW5kKHsKCWhhc0RhdGE6IGZ1bmN0aW9uKCBlbGVtICkgewoJCXJldHVybiBkYXRhX3VzZXIuaGFzRGF0YSggZWxlbSApIHx8IGRhdGFfcHJpdi5oYXNEYXRhKCBlbGVtICk7Cgl9LAoKCWRhdGE6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCBkYXRhICkgewoJCXJldHVybiBkYXRhX3VzZXIuYWNjZXNzKCBlbGVtLCBuYW1lLCBkYXRhICk7Cgl9LAoKCXJlbW92ZURhdGE6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lICkgewoJCWRhdGFfdXNlci5yZW1vdmUoIGVsZW0sIG5hbWUgKTsKCX0sCgoJLy8gVE9ETzogTm93IHRoYXQgYWxsIGNhbGxzIHRvIF9kYXRhIGFuZCBfcmVtb3ZlRGF0YSBoYXZlIGJlZW4gcmVwbGFjZWQKCS8vIHdpdGggZGlyZWN0IGNhbGxzIHRvIGRhdGFfcHJpdiBtZXRob2RzLCB0aGVzZSBjYW4gYmUgZGVwcmVjYXRlZC4KCV9kYXRhOiBmdW5jdGlvbiggZWxlbSwgbmFtZSwgZGF0YSApIHsKCQlyZXR1cm4gZGF0YV9wcml2LmFjY2VzcyggZWxlbSwgbmFtZSwgZGF0YSApOwoJfSwKCglfcmVtb3ZlRGF0YTogZnVuY3Rpb24oIGVsZW0sIG5hbWUgKSB7CgkJZGF0YV9wcml2LnJlbW92ZSggZWxlbSwgbmFtZSApOwoJfQp9KTsKCmpRdWVyeS5mbi5leHRlbmQoewoJZGF0YTogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7CgkJdmFyIGksIG5hbWUsIGRhdGEsCgkJCWVsZW0gPSB0aGlzWyAwIF0sCgkJCWF0dHJzID0gZWxlbSAmJiBlbGVtLmF0dHJpYnV0ZXM7CgoJCS8vIEdldHMgYWxsIHZhbHVlcwoJCWlmICgga2V5ID09PSB1bmRlZmluZWQgKSB7CgkJCWlmICggdGhpcy5sZW5ndGggKSB7CgkJCQlkYXRhID0gZGF0YV91c2VyLmdldCggZWxlbSApOwoKCQkJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSAmJiAhZGF0YV9wcml2LmdldCggZWxlbSwgImhhc0RhdGFBdHRycyIgKSApIHsKCQkJCQlpID0gYXR0cnMubGVuZ3RoOwoJCQkJCXdoaWxlICggaS0tICkgewoKCQkJCQkJLy8gU3VwcG9ydDogSUUxMSsKCQkJCQkJLy8gVGhlIGF0dHJzIGVsZW1lbnRzIGNhbiBiZSBudWxsICgjMTQ4OTQpCgkJCQkJCWlmICggYXR0cnNbIGkgXSApIHsKCQkJCQkJCW5hbWUgPSBhdHRyc1sgaSBdLm5hbWU7CgkJCQkJCQlpZiAoIG5hbWUuaW5kZXhPZiggImRhdGEtIiApID09PSAwICkgewoJCQkJCQkJCW5hbWUgPSBqUXVlcnkuY2FtZWxDYXNlKCBuYW1lLnNsaWNlKDUpICk7CgkJCQkJCQkJZGF0YUF0dHIoIGVsZW0sIG5hbWUsIGRhdGFbIG5hbWUgXSApOwoJCQkJCQkJfQoJCQkJCQl9CgkJCQkJfQoJCQkJCWRhdGFfcHJpdi5zZXQoIGVsZW0sICJoYXNEYXRhQXR0cnMiLCB0cnVlICk7CgkJCQl9CgkJCX0KCgkJCXJldHVybiBkYXRhOwoJCX0KCgkJLy8gU2V0cyBtdWx0aXBsZSB2YWx1ZXMKCQlpZiAoIHR5cGVvZiBrZXkgPT09ICJvYmplY3QiICkgewoJCQlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkgewoJCQkJZGF0YV91c2VyLnNldCggdGhpcywga2V5ICk7CgkJCX0pOwoJCX0KCgkJcmV0dXJuIGFjY2VzcyggdGhpcywgZnVuY3Rpb24oIHZhbHVlICkgewoJCQl2YXIgZGF0YSwKCQkJCWNhbWVsS2V5ID0galF1ZXJ5LmNhbWVsQ2FzZSgga2V5ICk7CgoJCQkvLyBUaGUgY2FsbGluZyBqUXVlcnkgb2JqZWN0IChlbGVtZW50IG1hdGNoZXMpIGlzIG5vdCBlbXB0eQoJCQkvLyAoYW5kIHRoZXJlZm9yZSBoYXMgYW4gZWxlbWVudCBhcHBlYXJzIGF0IHRoaXNbIDAgXSkgYW5kIHRoZQoJCQkvLyBgdmFsdWVgIHBhcmFtZXRlciB3YXMgbm90IHVuZGVmaW5lZC4gQW4gZW1wdHkgalF1ZXJ5IG9iamVjdAoJCQkvLyB3aWxsIHJlc3VsdCBpbiBgdW5kZWZpbmVkYCBmb3IgZWxlbSA9IHRoaXNbIDAgXSB3aGljaCB3aWxsCgkJCS8vIHRocm93IGFuIGV4Y2VwdGlvbiBpZiBhbiBhdHRlbXB0IHRvIHJlYWQgYSBkYXRhIGNhY2hlIGlzIG1hZGUuCgkJCWlmICggZWxlbSAmJiB2YWx1ZSA9PT0gdW5kZWZpbmVkICkgewoJCQkJLy8gQXR0ZW1wdCB0byBnZXQgZGF0YSBmcm9tIHRoZSBjYWNoZQoJCQkJLy8gd2l0aCB0aGUga2V5IGFzLWlzCgkJCQlkYXRhID0gZGF0YV91c2VyLmdldCggZWxlbSwga2V5ICk7CgkJCQlpZiAoIGRhdGEgIT09IHVuZGVmaW5lZCApIHsKCQkJCQlyZXR1cm4gZGF0YTsKCQkJCX0KCgkJCQkvLyBBdHRlbXB0IHRvIGdldCBkYXRhIGZyb20gdGhlIGNhY2hlCgkJCQkvLyB3aXRoIHRoZSBrZXkgY2FtZWxpemVkCgkJCQlkYXRhID0gZGF0YV91c2VyLmdldCggZWxlbSwgY2FtZWxLZXkgKTsKCQkJCWlmICggZGF0YSAhPT0gdW5kZWZpbmVkICkgewoJCQkJCXJldHVybiBkYXRhOwoJCQkJfQoKCQkJCS8vIEF0dGVtcHQgdG8gImRpc2NvdmVyIiB0aGUgZGF0YSBpbgoJCQkJLy8gSFRNTDUgY3VzdG9tIGRhdGEtKiBhdHRycwoJCQkJZGF0YSA9IGRhdGFBdHRyKCBlbGVtLCBjYW1lbEtleSwgdW5kZWZpbmVkICk7CgkJCQlpZiAoIGRhdGEgIT09IHVuZGVmaW5lZCApIHsKCQkJCQlyZXR1cm4gZGF0YTsKCQkJCX0KCgkJCQkvLyBXZSB0cmllZCByZWFsbHkgaGFyZCwgYnV0IHRoZSBkYXRhIGRvZXNuJ3QgZXhpc3QuCgkJCQlyZXR1cm47CgkJCX0KCgkJCS8vIFNldCB0aGUgZGF0YS4uLgoJCQl0aGlzLmVhY2goZnVuY3Rpb24oKSB7CgkJCQkvLyBGaXJzdCwgYXR0ZW1wdCB0byBzdG9yZSBhIGNvcHkgb3IgcmVmZXJlbmNlIG9mIGFueQoJCQkJLy8gZGF0YSB0aGF0IG1pZ2h0J3ZlIGJlZW4gc3RvcmUgd2l0aCBhIGNhbWVsQ2FzZWQga2V5LgoJCQkJdmFyIGRhdGEgPSBkYXRhX3VzZXIuZ2V0KCB0aGlzLCBjYW1lbEtleSApOwoKCQkJCS8vIEZvciBIVE1MNSBkYXRhLSogYXR0cmlidXRlIGludGVyb3AsIHdlIGhhdmUgdG8KCQkJCS8vIHN0b3JlIHByb3BlcnR5IG5hbWVzIHdpdGggZGFzaGVzIGluIGEgY2FtZWxDYXNlIGZvcm0uCgkJCQkvLyBUaGlzIG1pZ2h0IG5vdCBhcHBseSB0byBhbGwgcHJvcGVydGllcy4uLioKCQkJCWRhdGFfdXNlci5zZXQoIHRoaXMsIGNhbWVsS2V5LCB2YWx1ZSApOwoKCQkJCS8vICouLi4gSW4gdGhlIGNhc2Ugb2YgcHJvcGVydGllcyB0aGF0IG1pZ2h0IF9hY3R1YWxseV8KCQkJCS8vIGhhdmUgZGFzaGVzLCB3ZSBuZWVkIHRvIGFsc28gc3RvcmUgYSBjb3B5IG9mIHRoYXQKCQkJCS8vIHVuY2hhbmdlZCBwcm9wZXJ0eS4KCQkJCWlmICgga2V5LmluZGV4T2YoIi0iKSAhPT0gLTEgJiYgZGF0YSAhPT0gdW5kZWZpbmVkICkgewoJCQkJCWRhdGFfdXNlci5zZXQoIHRoaXMsIGtleSwgdmFsdWUgKTsKCQkJCX0KCQkJfSk7CgkJfSwgbnVsbCwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggPiAxLCBudWxsLCB0cnVlICk7Cgl9LAoKCXJlbW92ZURhdGE6IGZ1bmN0aW9uKCBrZXkgKSB7CgkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHsKCQkJZGF0YV91c2VyLnJlbW92ZSggdGhpcywga2V5ICk7CgkJfSk7Cgl9Cn0pOwoKCmpRdWVyeS5leHRlbmQoewoJcXVldWU6IGZ1bmN0aW9uKCBlbGVtLCB0eXBlLCBkYXRhICkgewoJCXZhciBxdWV1ZTsKCgkJaWYgKCBlbGVtICkgewoJCQl0eXBlID0gKCB0eXBlIHx8ICJmeCIgKSArICJxdWV1ZSI7CgkJCXF1ZXVlID0gZGF0YV9wcml2LmdldCggZWxlbSwgdHlwZSApOwoKCQkJLy8gU3BlZWQgdXAgZGVxdWV1ZSBieSBnZXR0aW5nIG91dCBxdWlja2x5IGlmIHRoaXMgaXMganVzdCBhIGxvb2t1cAoJCQlpZiAoIGRhdGEgKSB7CgkJCQlpZiAoICFxdWV1ZSB8fCBqUXVlcnkuaXNBcnJheSggZGF0YSApICkgewoJCQkJCXF1ZXVlID0gZGF0YV9wcml2LmFjY2VzcyggZWxlbSwgdHlwZSwgalF1ZXJ5Lm1ha2VBcnJheShkYXRhKSApOwoJCQkJfSBlbHNlIHsKCQkJCQlxdWV1ZS5wdXNoKCBkYXRhICk7CgkJCQl9CgkJCX0KCQkJcmV0dXJuIHF1ZXVlIHx8IFtdOwoJCX0KCX0sCgoJZGVxdWV1ZTogZnVuY3Rpb24oIGVsZW0sIHR5cGUgKSB7CgkJdHlwZSA9IHR5cGUgfHwgImZ4IjsKCgkJdmFyIHF1ZXVlID0galF1ZXJ5LnF1ZXVlKCBlbGVtLCB0eXBlICksCgkJCXN0YXJ0TGVuZ3RoID0gcXVldWUubGVuZ3RoLAoJCQlmbiA9IHF1ZXVlLnNoaWZ0KCksCgkJCWhvb2tzID0galF1ZXJ5Ll9xdWV1ZUhvb2tzKCBlbGVtLCB0eXBlICksCgkJCW5leHQgPSBmdW5jdGlvbigpIHsKCQkJCWpRdWVyeS5kZXF1ZXVlKCBlbGVtLCB0eXBlICk7CgkJCX07CgoJCS8vIElmIHRoZSBmeCBxdWV1ZSBpcyBkZXF1ZXVlZCwgYWx3YXlzIHJlbW92ZSB0aGUgcHJvZ3Jlc3Mgc2VudGluZWwKCQlpZiAoIGZuID09PSAiaW5wcm9ncmVzcyIgKSB7CgkJCWZuID0gcXVldWUuc2hpZnQoKTsKCQkJc3RhcnRMZW5ndGgtLTsKCQl9CgoJCWlmICggZm4gKSB7CgoJCQkvLyBBZGQgYSBwcm9ncmVzcyBzZW50aW5lbCB0byBwcmV2ZW50IHRoZSBmeCBxdWV1ZSBmcm9tIGJlaW5nCgkJCS8vIGF1dG9tYXRpY2FsbHkgZGVxdWV1ZWQKCQkJaWYgKCB0eXBlID09PSAiZngiICkgewoJCQkJcXVldWUudW5zaGlmdCggImlucHJvZ3Jlc3MiICk7CgkJCX0KCgkJCS8vIGNsZWFyIHVwIHRoZSBsYXN0IHF1ZXVlIHN0b3AgZnVuY3Rpb24KCQkJZGVsZXRlIGhvb2tzLnN0b3A7CgkJCWZuLmNhbGwoIGVsZW0sIG5leHQsIGhvb2tzICk7CgkJfQoKCQlpZiAoICFzdGFydExlbmd0aCAmJiBob29rcyApIHsKCQkJaG9va3MuZW1wdHkuZmlyZSgpOwoJCX0KCX0sCgoJLy8gbm90IGludGVuZGVkIGZvciBwdWJsaWMgY29uc3VtcHRpb24gLSBnZW5lcmF0ZXMgYSBxdWV1ZUhvb2tzIG9iamVjdCwgb3IgcmV0dXJucyB0aGUgY3VycmVudCBvbmUKCV9xdWV1ZUhvb2tzOiBmdW5jdGlvbiggZWxlbSwgdHlwZSApIHsKCQl2YXIga2V5ID0gdHlwZSArICJxdWV1ZUhvb2tzIjsKCQlyZXR1cm4gZGF0YV9wcml2LmdldCggZWxlbSwga2V5ICkgfHwgZGF0YV9wcml2LmFjY2VzcyggZWxlbSwga2V5LCB7CgkJCWVtcHR5OiBqUXVlcnkuQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLmFkZChmdW5jdGlvbigpIHsKCQkJCWRhdGFfcHJpdi5yZW1vdmUoIGVsZW0sIFsgdHlwZSArICJxdWV1ZSIsIGtleSBdICk7CgkJCX0pCgkJfSk7Cgl9Cn0pOwoKalF1ZXJ5LmZuLmV4dGVuZCh7CglxdWV1ZTogZnVuY3Rpb24oIHR5cGUsIGRhdGEgKSB7CgkJdmFyIHNldHRlciA9IDI7CgoJCWlmICggdHlwZW9mIHR5cGUgIT09ICJzdHJpbmciICkgewoJCQlkYXRhID0gdHlwZTsKCQkJdHlwZSA9ICJmeCI7CgkJCXNldHRlci0tOwoJCX0KCgkJaWYgKCBhcmd1bWVudHMubGVuZ3RoIDwgc2V0dGVyICkgewoJCQlyZXR1cm4galF1ZXJ5LnF1ZXVlKCB0aGlzWzBdLCB0eXBlICk7CgkJfQoKCQlyZXR1cm4gZGF0YSA9PT0gdW5kZWZpbmVkID8KCQkJdGhpcyA6CgkJCXRoaXMuZWFjaChmdW5jdGlvbigpIHsKCQkJCXZhciBxdWV1ZSA9IGpRdWVyeS5xdWV1ZSggdGhpcywgdHlwZSwgZGF0YSApOwoKCQkJCS8vIGVuc3VyZSBhIGhvb2tzIGZvciB0aGlzIHF1ZXVlCgkJCQlqUXVlcnkuX3F1ZXVlSG9va3MoIHRoaXMsIHR5cGUgKTsKCgkJCQlpZiAoIHR5cGUgPT09ICJmeCIgJiYgcXVldWVbMF0gIT09ICJpbnByb2dyZXNzIiApIHsKCQkJCQlqUXVlcnkuZGVxdWV1ZSggdGhpcywgdHlwZSApOwoJCQkJfQoJCQl9KTsKCX0sCglkZXF1ZXVlOiBmdW5jdGlvbiggdHlwZSApIHsKCQlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkgewoJCQlqUXVlcnkuZGVxdWV1ZSggdGhpcywgdHlwZSApOwoJCX0pOwoJfSwKCWNsZWFyUXVldWU6IGZ1bmN0aW9uKCB0eXBlICkgewoJCXJldHVybiB0aGlzLnF1ZXVlKCB0eXBlIHx8ICJmeCIsIFtdICk7Cgl9LAoJLy8gR2V0IGEgcHJvbWlzZSByZXNvbHZlZCB3aGVuIHF1ZXVlcyBvZiBhIGNlcnRhaW4gdHlwZQoJLy8gYXJlIGVtcHRpZWQgKGZ4IGlzIHRoZSB0eXBlIGJ5IGRlZmF1bHQpCglwcm9taXNlOiBmdW5jdGlvbiggdHlwZSwgb2JqICkgewoJCXZhciB0bXAsCgkJCWNvdW50ID0gMSwKCQkJZGVmZXIgPSBqUXVlcnkuRGVmZXJyZWQoKSwKCQkJZWxlbWVudHMgPSB0aGlzLAoJCQlpID0gdGhpcy5sZW5ndGgsCgkJCXJlc29sdmUgPSBmdW5jdGlvbigpIHsKCQkJCWlmICggISggLS1jb3VudCApICkgewoJCQkJCWRlZmVyLnJlc29sdmVXaXRoKCBlbGVtZW50cywgWyBlbGVtZW50cyBdICk7CgkJCQl9CgkJCX07CgoJCWlmICggdHlwZW9mIHR5cGUgIT09ICJzdHJpbmciICkgewoJCQlvYmogPSB0eXBlOwoJCQl0eXBlID0gdW5kZWZpbmVkOwoJCX0KCQl0eXBlID0gdHlwZSB8fCAiZngiOwoKCQl3aGlsZSAoIGktLSApIHsKCQkJdG1wID0gZGF0YV9wcml2LmdldCggZWxlbWVudHNbIGkgXSwgdHlwZSArICJxdWV1ZUhvb2tzIiApOwoJCQlpZiAoIHRtcCAmJiB0bXAuZW1wdHkgKSB7CgkJCQljb3VudCsrOwoJCQkJdG1wLmVtcHR5LmFkZCggcmVzb2x2ZSApOwoJCQl9CgkJfQoJCXJlc29sdmUoKTsKCQlyZXR1cm4gZGVmZXIucHJvbWlzZSggb2JqICk7Cgl9Cn0pOwp2YXIgcG51bSA9ICgvWystXT8oPzpcZCpcLnwpXGQrKD86W2VFXVsrLV0/XGQrfCkvKS5zb3VyY2U7Cgp2YXIgY3NzRXhwYW5kID0gWyAiVG9wIiwgIlJpZ2h0IiwgIkJvdHRvbSIsICJMZWZ0IiBdOwoKdmFyIGlzSGlkZGVuID0gZnVuY3Rpb24oIGVsZW0sIGVsICkgewoJCS8vIGlzSGlkZGVuIG1pZ2h0IGJlIGNhbGxlZCBmcm9tIGpRdWVyeSNmaWx0ZXIgZnVuY3Rpb247CgkJLy8gaW4gdGhhdCBjYXNlLCBlbGVtZW50IHdpbGwgYmUgc2Vjb25kIGFyZ3VtZW50CgkJZWxlbSA9IGVsIHx8IGVsZW07CgkJcmV0dXJuIGpRdWVyeS5jc3MoIGVsZW0sICJkaXNwbGF5IiApID09PSAibm9uZSIgfHwgIWpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICk7Cgl9OwoKdmFyIHJjaGVja2FibGVUeXBlID0gKC9eKD86Y2hlY2tib3h8cmFkaW8pJC9pKTsKCgoKKGZ1bmN0aW9uKCkgewoJdmFyIGZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLAoJCWRpdiA9IGZyYWdtZW50LmFwcGVuZENoaWxkKCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAiZGl2IiApICksCgkJaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAiaW5wdXQiICk7CgoJLy8gIzExMjE3IC0gV2ViS2l0IGxvc2VzIGNoZWNrIHdoZW4gdGhlIG5hbWUgaXMgYWZ0ZXIgdGhlIGNoZWNrZWQgYXR0cmlidXRlCgkvLyBTdXBwb3J0OiBXaW5kb3dzIFdlYiBBcHBzIChXV0EpCgkvLyBgbmFtZWAgYW5kIGB0eXBlYCBuZWVkIC5zZXRBdHRyaWJ1dGUgZm9yIFdXQQoJaW5wdXQuc2V0QXR0cmlidXRlKCAidHlwZSIsICJyYWRpbyIgKTsKCWlucHV0LnNldEF0dHJpYnV0ZSggImNoZWNrZWQiLCAiY2hlY2tlZCIgKTsKCWlucHV0LnNldEF0dHJpYnV0ZSggIm5hbWUiLCAidCIgKTsKCglkaXYuYXBwZW5kQ2hpbGQoIGlucHV0ICk7CgoJLy8gU3VwcG9ydDogU2FmYXJpIDUuMSwgaU9TIDUuMSwgQW5kcm9pZCA0LngsIEFuZHJvaWQgMi4zCgkvLyBvbGQgV2ViS2l0IGRvZXNuJ3QgY2xvbmUgY2hlY2tlZCBzdGF0ZSBjb3JyZWN0bHkgaW4gZnJhZ21lbnRzCglzdXBwb3J0LmNoZWNrQ2xvbmUgPSBkaXYuY2xvbmVOb2RlKCB0cnVlICkuY2xvbmVOb2RlKCB0cnVlICkubGFzdENoaWxkLmNoZWNrZWQ7CgoJLy8gTWFrZSBzdXJlIHRleHRhcmVhIChhbmQgY2hlY2tib3gpIGRlZmF1bHRWYWx1ZSBpcyBwcm9wZXJseSBjbG9uZWQKCS8vIFN1cHBvcnQ6IElFOS1JRTExKwoJZGl2LmlubmVySFRNTCA9ICI8dGV4dGFyZWE+eDwvdGV4dGFyZWE+IjsKCXN1cHBvcnQubm9DbG9uZUNoZWNrZWQgPSAhIWRpdi5jbG9uZU5vZGUoIHRydWUgKS5sYXN0Q2hpbGQuZGVmYXVsdFZhbHVlOwp9KSgpOwp2YXIgc3RydW5kZWZpbmVkID0gdHlwZW9mIHVuZGVmaW5lZDsKCgoKc3VwcG9ydC5mb2N1c2luQnViYmxlcyA9ICJvbmZvY3VzaW4iIGluIHdpbmRvdzsKCgp2YXIKCXJrZXlFdmVudCA9IC9ea2V5LywKCXJtb3VzZUV2ZW50ID0gL14oPzptb3VzZXxwb2ludGVyfGNvbnRleHRtZW51KXxjbGljay8sCglyZm9jdXNNb3JwaCA9IC9eKD86Zm9jdXNpbmZvY3VzfGZvY3Vzb3V0Ymx1cikkLywKCXJ0eXBlbmFtZXNwYWNlID0gL14oW14uXSopKD86XC4oLispfCkkLzsKCmZ1bmN0aW9uIHJldHVyblRydWUoKSB7CglyZXR1cm4gdHJ1ZTsKfQoKZnVuY3Rpb24gcmV0dXJuRmFsc2UoKSB7CglyZXR1cm4gZmFsc2U7Cn0KCmZ1bmN0aW9uIHNhZmVBY3RpdmVFbGVtZW50KCkgewoJdHJ5IHsKCQlyZXR1cm4gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDsKCX0gY2F0Y2ggKCBlcnIgKSB7IH0KfQoKLyoKICogSGVscGVyIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgZXZlbnRzIC0tIG5vdCBwYXJ0IG9mIHRoZSBwdWJsaWMgaW50ZXJmYWNlLgogKiBQcm9wcyB0byBEZWFuIEVkd2FyZHMnIGFkZEV2ZW50IGxpYnJhcnkgZm9yIG1hbnkgb2YgdGhlIGlkZWFzLgogKi8KalF1ZXJ5LmV2ZW50ID0gewoKCWdsb2JhbDoge30sCgoJYWRkOiBmdW5jdGlvbiggZWxlbSwgdHlwZXMsIGhhbmRsZXIsIGRhdGEsIHNlbGVjdG9yICkgewoKCQl2YXIgaGFuZGxlT2JqSW4sIGV2ZW50SGFuZGxlLCB0bXAsCgkJCWV2ZW50cywgdCwgaGFuZGxlT2JqLAoJCQlzcGVjaWFsLCBoYW5kbGVycywgdHlwZSwgbmFtZXNwYWNlcywgb3JpZ1R5cGUsCgkJCWVsZW1EYXRhID0gZGF0YV9wcml2LmdldCggZWxlbSApOwoKCQkvLyBEb24ndCBhdHRhY2ggZXZlbnRzIHRvIG5vRGF0YSBvciB0ZXh0L2NvbW1lbnQgbm9kZXMgKGJ1dCBhbGxvdyBwbGFpbiBvYmplY3RzKQoJCWlmICggIWVsZW1EYXRhICkgewoJCQlyZXR1cm47CgkJfQoKCQkvLyBDYWxsZXIgY2FuIHBhc3MgaW4gYW4gb2JqZWN0IG9mIGN1c3RvbSBkYXRhIGluIGxpZXUgb2YgdGhlIGhhbmRsZXIKCQlpZiAoIGhhbmRsZXIuaGFuZGxlciApIHsKCQkJaGFuZGxlT2JqSW4gPSBoYW5kbGVyOwoJCQloYW5kbGVyID0gaGFuZGxlT2JqSW4uaGFuZGxlcjsKCQkJc2VsZWN0b3IgPSBoYW5kbGVPYmpJbi5zZWxlY3RvcjsKCQl9CgoJCS8vIE1ha2Ugc3VyZSB0aGF0IHRoZSBoYW5kbGVyIGhhcyBhIHVuaXF1ZSBJRCwgdXNlZCB0byBmaW5kL3JlbW92ZSBpdCBsYXRlcgoJCWlmICggIWhhbmRsZXIuZ3VpZCApIHsKCQkJaGFuZGxlci5ndWlkID0galF1ZXJ5Lmd1aWQrKzsKCQl9CgoJCS8vIEluaXQgdGhlIGVsZW1lbnQncyBldmVudCBzdHJ1Y3R1cmUgYW5kIG1haW4gaGFuZGxlciwgaWYgdGhpcyBpcyB0aGUgZmlyc3QKCQlpZiAoICEoZXZlbnRzID0gZWxlbURhdGEuZXZlbnRzKSApIHsKCQkJZXZlbnRzID0gZWxlbURhdGEuZXZlbnRzID0ge307CgkJfQoJCWlmICggIShldmVudEhhbmRsZSA9IGVsZW1EYXRhLmhhbmRsZSkgKSB7CgkJCWV2ZW50SGFuZGxlID0gZWxlbURhdGEuaGFuZGxlID0gZnVuY3Rpb24oIGUgKSB7CgkJCQkvLyBEaXNjYXJkIHRoZSBzZWNvbmQgZXZlbnQgb2YgYSBqUXVlcnkuZXZlbnQudHJpZ2dlcigpIGFuZAoJCQkJLy8gd2hlbiBhbiBldmVudCBpcyBjYWxsZWQgYWZ0ZXIgYSBwYWdlIGhhcyB1bmxvYWRlZAoJCQkJcmV0dXJuIHR5cGVvZiBqUXVlcnkgIT09IHN0cnVuZGVmaW5lZCAmJiBqUXVlcnkuZXZlbnQudHJpZ2dlcmVkICE9PSBlLnR5cGUgPwoJCQkJCWpRdWVyeS5ldmVudC5kaXNwYXRjaC5hcHBseSggZWxlbSwgYXJndW1lbnRzICkgOiB1bmRlZmluZWQ7CgkJCX07CgkJfQoKCQkvLyBIYW5kbGUgbXVsdGlwbGUgZXZlbnRzIHNlcGFyYXRlZCBieSBhIHNwYWNlCgkJdHlwZXMgPSAoIHR5cGVzIHx8ICIiICkubWF0Y2goIHJub3R3aGl0ZSApIHx8IFsgIiIgXTsKCQl0ID0gdHlwZXMubGVuZ3RoOwoJCXdoaWxlICggdC0tICkgewoJCQl0bXAgPSBydHlwZW5hbWVzcGFjZS5leGVjKCB0eXBlc1t0XSApIHx8IFtdOwoJCQl0eXBlID0gb3JpZ1R5cGUgPSB0bXBbMV07CgkJCW5hbWVzcGFjZXMgPSAoIHRtcFsyXSB8fCAiIiApLnNwbGl0KCAiLiIgKS5zb3J0KCk7CgoJCQkvLyBUaGVyZSAqbXVzdCogYmUgYSB0eXBlLCBubyBhdHRhY2hpbmcgbmFtZXNwYWNlLW9ubHkgaGFuZGxlcnMKCQkJaWYgKCAhdHlwZSApIHsKCQkJCWNvbnRpbnVlOwoJCQl9CgoJCQkvLyBJZiBldmVudCBjaGFuZ2VzIGl0cyB0eXBlLCB1c2UgdGhlIHNwZWNpYWwgZXZlbnQgaGFuZGxlcnMgZm9yIHRoZSBjaGFuZ2VkIHR5cGUKCQkJc3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsWyB0eXBlIF0gfHwge307CgoJCQkvLyBJZiBzZWxlY3RvciBkZWZpbmVkLCBkZXRlcm1pbmUgc3BlY2lhbCBldmVudCBhcGkgdHlwZSwgb3RoZXJ3aXNlIGdpdmVuIHR5cGUKCQkJdHlwZSA9ICggc2VsZWN0b3IgPyBzcGVjaWFsLmRlbGVnYXRlVHlwZSA6IHNwZWNpYWwuYmluZFR5cGUgKSB8fCB0eXBlOwoKCQkJLy8gVXBkYXRlIHNwZWNpYWwgYmFzZWQgb24gbmV3bHkgcmVzZXQgdHlwZQoJCQlzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIHR5cGUgXSB8fCB7fTsKCgkJCS8vIGhhbmRsZU9iaiBpcyBwYXNzZWQgdG8gYWxsIGV2ZW50IGhhbmRsZXJzCgkJCWhhbmRsZU9iaiA9IGpRdWVyeS5leHRlbmQoewoJCQkJdHlwZTogdHlwZSwKCQkJCW9yaWdUeXBlOiBvcmlnVHlwZSwKCQkJCWRhdGE6IGRhdGEsCgkJCQloYW5kbGVyOiBoYW5kbGVyLAoJCQkJZ3VpZDogaGFuZGxlci5ndWlkLAoJCQkJc2VsZWN0b3I6IHNlbGVjdG9yLAoJCQkJbmVlZHNDb250ZXh0OiBzZWxlY3RvciAmJiBqUXVlcnkuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQudGVzdCggc2VsZWN0b3IgKSwKCQkJCW5hbWVzcGFjZTogbmFtZXNwYWNlcy5qb2luKCIuIikKCQkJfSwgaGFuZGxlT2JqSW4gKTsKCgkJCS8vIEluaXQgdGhlIGV2ZW50IGhhbmRsZXIgcXVldWUgaWYgd2UncmUgdGhlIGZpcnN0CgkJCWlmICggIShoYW5kbGVycyA9IGV2ZW50c1sgdHlwZSBdKSApIHsKCQkJCWhhbmRsZXJzID0gZXZlbnRzWyB0eXBlIF0gPSBbXTsKCQkJCWhhbmRsZXJzLmRlbGVnYXRlQ291bnQgPSAwOwoKCQkJCS8vIE9ubHkgdXNlIGFkZEV2ZW50TGlzdGVuZXIgaWYgdGhlIHNwZWNpYWwgZXZlbnRzIGhhbmRsZXIgcmV0dXJucyBmYWxzZQoJCQkJaWYgKCAhc3BlY2lhbC5zZXR1cCB8fCBzcGVjaWFsLnNldHVwLmNhbGwoIGVsZW0sIGRhdGEsIG5hbWVzcGFjZXMsIGV2ZW50SGFuZGxlICkgPT09IGZhbHNlICkgewoJCQkJCWlmICggZWxlbS5hZGRFdmVudExpc3RlbmVyICkgewoJCQkJCQllbGVtLmFkZEV2ZW50TGlzdGVuZXIoIHR5cGUsIGV2ZW50SGFuZGxlLCBmYWxzZSApOwoJCQkJCX0KCQkJCX0KCQkJfQoKCQkJaWYgKCBzcGVjaWFsLmFkZCApIHsKCQkJCXNwZWNpYWwuYWRkLmNhbGwoIGVsZW0sIGhhbmRsZU9iaiApOwoKCQkJCWlmICggIWhhbmRsZU9iai5oYW5kbGVyLmd1aWQgKSB7CgkJCQkJaGFuZGxlT2JqLmhhbmRsZXIuZ3VpZCA9IGhhbmRsZXIuZ3VpZDsKCQkJCX0KCQkJfQoKCQkJLy8gQWRkIHRvIHRoZSBlbGVtZW50J3MgaGFuZGxlciBsaXN0LCBkZWxlZ2F0ZXMgaW4gZnJvbnQKCQkJaWYgKCBzZWxlY3RvciApIHsKCQkJCWhhbmRsZXJzLnNwbGljZSggaGFuZGxlcnMuZGVsZWdhdGVDb3VudCsrLCAwLCBoYW5kbGVPYmogKTsKCQkJfSBlbHNlIHsKCQkJCWhhbmRsZXJzLnB1c2goIGhhbmRsZU9iaiApOwoJCQl9CgoJCQkvLyBLZWVwIHRyYWNrIG9mIHdoaWNoIGV2ZW50cyBoYXZlIGV2ZXIgYmVlbiB1c2VkLCBmb3IgZXZlbnQgb3B0aW1pemF0aW9uCgkJCWpRdWVyeS5ldmVudC5nbG9iYWxbIHR5cGUgXSA9IHRydWU7CgkJfQoKCX0sCgoJLy8gRGV0YWNoIGFuIGV2ZW50IG9yIHNldCBvZiBldmVudHMgZnJvbSBhbiBlbGVtZW50CglyZW1vdmU6IGZ1bmN0aW9uKCBlbGVtLCB0eXBlcywgaGFuZGxlciwgc2VsZWN0b3IsIG1hcHBlZFR5cGVzICkgewoKCQl2YXIgaiwgb3JpZ0NvdW50LCB0bXAsCgkJCWV2ZW50cywgdCwgaGFuZGxlT2JqLAoJCQlzcGVjaWFsLCBoYW5kbGVycywgdHlwZSwgbmFtZXNwYWNlcywgb3JpZ1R5cGUsCgkJCWVsZW1EYXRhID0gZGF0YV9wcml2Lmhhc0RhdGEoIGVsZW0gKSAmJiBkYXRhX3ByaXYuZ2V0KCBlbGVtICk7CgoJCWlmICggIWVsZW1EYXRhIHx8ICEoZXZlbnRzID0gZWxlbURhdGEuZXZlbnRzKSApIHsKCQkJcmV0dXJuOwoJCX0KCgkJLy8gT25jZSBmb3IgZWFjaCB0eXBlLm5hbWVzcGFjZSBpbiB0eXBlczsgdHlwZSBtYXkgYmUgb21pdHRlZAoJCXR5cGVzID0gKCB0eXBlcyB8fCAiIiApLm1hdGNoKCBybm90d2hpdGUgKSB8fCBbICIiIF07CgkJdCA9IHR5cGVzLmxlbmd0aDsKCQl3aGlsZSAoIHQtLSApIHsKCQkJdG1wID0gcnR5cGVuYW1lc3BhY2UuZXhlYyggdHlwZXNbdF0gKSB8fCBbXTsKCQkJdHlwZSA9IG9yaWdUeXBlID0gdG1wWzFdOwoJCQluYW1lc3BhY2VzID0gKCB0bXBbMl0gfHwgIiIgKS5zcGxpdCggIi4iICkuc29ydCgpOwoKCQkJLy8gVW5iaW5kIGFsbCBldmVudHMgKG9uIHRoaXMgbmFtZXNwYWNlLCBpZiBwcm92aWRlZCkgZm9yIHRoZSBlbGVtZW50CgkJCWlmICggIXR5cGUgKSB7CgkJCQlmb3IgKCB0eXBlIGluIGV2ZW50cyApIHsKCQkJCQlqUXVlcnkuZXZlbnQucmVtb3ZlKCBlbGVtLCB0eXBlICsgdHlwZXNbIHQgXSwgaGFuZGxlciwgc2VsZWN0b3IsIHRydWUgKTsKCQkJCX0KCQkJCWNvbnRpbnVlOwoJCQl9CgoJCQlzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIHR5cGUgXSB8fCB7fTsKCQkJdHlwZSA9ICggc2VsZWN0b3IgPyBzcGVjaWFsLmRlbGVnYXRlVHlwZSA6IHNwZWNpYWwuYmluZFR5cGUgKSB8fCB0eXBlOwoJCQloYW5kbGVycyA9IGV2ZW50c1sgdHlwZSBdIHx8IFtdOwoJCQl0bXAgPSB0bXBbMl0gJiYgbmV3IFJlZ0V4cCggIihefFxcLikiICsgbmFtZXNwYWNlcy5qb2luKCJcXC4oPzouKlxcLnwpIikgKyAiKFxcLnwkKSIgKTsKCgkJCS8vIFJlbW92ZSBtYXRjaGluZyBldmVudHMKCQkJb3JpZ0NvdW50ID0gaiA9IGhhbmRsZXJzLmxlbmd0aDsKCQkJd2hpbGUgKCBqLS0gKSB7CgkJCQloYW5kbGVPYmogPSBoYW5kbGVyc1sgaiBdOwoKCQkJCWlmICggKCBtYXBwZWRUeXBlcyB8fCBvcmlnVHlwZSA9PT0gaGFuZGxlT2JqLm9yaWdUeXBlICkgJiYKCQkJCQkoICFoYW5kbGVyIHx8IGhhbmRsZXIuZ3VpZCA9PT0gaGFuZGxlT2JqLmd1aWQgKSAmJgoJCQkJCSggIXRtcCB8fCB0bXAudGVzdCggaGFuZGxlT2JqLm5hbWVzcGFjZSApICkgJiYKCQkJCQkoICFzZWxlY3RvciB8fCBzZWxlY3RvciA9PT0gaGFuZGxlT2JqLnNlbGVjdG9yIHx8IHNlbGVjdG9yID09PSAiKioiICYmIGhhbmRsZU9iai5zZWxlY3RvciApICkgewoJCQkJCWhhbmRsZXJzLnNwbGljZSggaiwgMSApOwoKCQkJCQlpZiAoIGhhbmRsZU9iai5zZWxlY3RvciApIHsKCQkJCQkJaGFuZGxlcnMuZGVsZWdhdGVDb3VudC0tOwoJCQkJCX0KCQkJCQlpZiAoIHNwZWNpYWwucmVtb3ZlICkgewoJCQkJCQlzcGVjaWFsLnJlbW92ZS5jYWxsKCBlbGVtLCBoYW5kbGVPYmogKTsKCQkJCQl9CgkJCQl9CgkJCX0KCgkJCS8vIFJlbW92ZSBnZW5lcmljIGV2ZW50IGhhbmRsZXIgaWYgd2UgcmVtb3ZlZCBzb21ldGhpbmcgYW5kIG5vIG1vcmUgaGFuZGxlcnMgZXhpc3QKCQkJLy8gKGF2b2lkcyBwb3RlbnRpYWwgZm9yIGVuZGxlc3MgcmVjdXJzaW9uIGR1cmluZyByZW1vdmFsIG9mIHNwZWNpYWwgZXZlbnQgaGFuZGxlcnMpCgkJCWlmICggb3JpZ0NvdW50ICYmICFoYW5kbGVycy5sZW5ndGggKSB7CgkJCQlpZiAoICFzcGVjaWFsLnRlYXJkb3duIHx8IHNwZWNpYWwudGVhcmRvd24uY2FsbCggZWxlbSwgbmFtZXNwYWNlcywgZWxlbURhdGEuaGFuZGxlICkgPT09IGZhbHNlICkgewoJCQkJCWpRdWVyeS5yZW1vdmVFdmVudCggZWxlbSwgdHlwZSwgZWxlbURhdGEuaGFuZGxlICk7CgkJCQl9CgoJCQkJZGVsZXRlIGV2ZW50c1sgdHlwZSBdOwoJCQl9CgkJfQoKCQkvLyBSZW1vdmUgdGhlIGV4cGFuZG8gaWYgaXQncyBubyBsb25nZXIgdXNlZAoJCWlmICggalF1ZXJ5LmlzRW1wdHlPYmplY3QoIGV2ZW50cyApICkgewoJCQlkZWxldGUgZWxlbURhdGEuaGFuZGxlOwoJCQlkYXRhX3ByaXYucmVtb3ZlKCBlbGVtLCAiZXZlbnRzIiApOwoJCX0KCX0sCgoJdHJpZ2dlcjogZnVuY3Rpb24oIGV2ZW50LCBkYXRhLCBlbGVtLCBvbmx5SGFuZGxlcnMgKSB7CgoJCXZhciBpLCBjdXIsIHRtcCwgYnViYmxlVHlwZSwgb250eXBlLCBoYW5kbGUsIHNwZWNpYWwsCgkJCWV2ZW50UGF0aCA9IFsgZWxlbSB8fCBkb2N1bWVudCBdLAoJCQl0eXBlID0gaGFzT3duLmNhbGwoIGV2ZW50LCAidHlwZSIgKSA/IGV2ZW50LnR5cGUgOiBldmVudCwKCQkJbmFtZXNwYWNlcyA9IGhhc093bi5jYWxsKCBldmVudCwgIm5hbWVzcGFjZSIgKSA/IGV2ZW50Lm5hbWVzcGFjZS5zcGxpdCgiLiIpIDogW107CgoJCWN1ciA9IHRtcCA9IGVsZW0gPSBlbGVtIHx8IGRvY3VtZW50OwoKCQkvLyBEb24ndCBkbyBldmVudHMgb24gdGV4dCBhbmQgY29tbWVudCBub2RlcwoJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMyB8fCBlbGVtLm5vZGVUeXBlID09PSA4ICkgewoJCQlyZXR1cm47CgkJfQoKCQkvLyBmb2N1cy9ibHVyIG1vcnBocyB0byBmb2N1c2luL291dDsgZW5zdXJlIHdlJ3JlIG5vdCBmaXJpbmcgdGhlbSByaWdodCBub3cKCQlpZiAoIHJmb2N1c01vcnBoLnRlc3QoIHR5cGUgKyBqUXVlcnkuZXZlbnQudHJpZ2dlcmVkICkgKSB7CgkJCXJldHVybjsKCQl9CgoJCWlmICggdHlwZS5pbmRleE9mKCIuIikgPj0gMCApIHsKCQkJLy8gTmFtZXNwYWNlZCB0cmlnZ2VyOyBjcmVhdGUgYSByZWdleHAgdG8gbWF0Y2ggZXZlbnQgdHlwZSBpbiBoYW5kbGUoKQoJCQluYW1lc3BhY2VzID0gdHlwZS5zcGxpdCgiLiIpOwoJCQl0eXBlID0gbmFtZXNwYWNlcy5zaGlmdCgpOwoJCQluYW1lc3BhY2VzLnNvcnQoKTsKCQl9CgkJb250eXBlID0gdHlwZS5pbmRleE9mKCI6IikgPCAwICYmICJvbiIgKyB0eXBlOwoKCQkvLyBDYWxsZXIgY2FuIHBhc3MgaW4gYSBqUXVlcnkuRXZlbnQgb2JqZWN0LCBPYmplY3QsIG9yIGp1c3QgYW4gZXZlbnQgdHlwZSBzdHJpbmcKCQlldmVudCA9IGV2ZW50WyBqUXVlcnkuZXhwYW5kbyBdID8KCQkJZXZlbnQgOgoJCQluZXcgalF1ZXJ5LkV2ZW50KCB0eXBlLCB0eXBlb2YgZXZlbnQgPT09ICJvYmplY3QiICYmIGV2ZW50ICk7CgoJCS8vIFRyaWdnZXIgYml0bWFzazogJiAxIGZvciBuYXRpdmUgaGFuZGxlcnM7ICYgMiBmb3IgalF1ZXJ5IChhbHdheXMgdHJ1ZSkKCQlldmVudC5pc1RyaWdnZXIgPSBvbmx5SGFuZGxlcnMgPyAyIDogMzsKCQlldmVudC5uYW1lc3BhY2UgPSBuYW1lc3BhY2VzLmpvaW4oIi4iKTsKCQlldmVudC5uYW1lc3BhY2VfcmUgPSBldmVudC5uYW1lc3BhY2UgPwoJCQluZXcgUmVnRXhwKCAiKF58XFwuKSIgKyBuYW1lc3BhY2VzLmpvaW4oIlxcLig/Oi4qXFwufCkiKSArICIoXFwufCQpIiApIDoKCQkJbnVsbDsKCgkJLy8gQ2xlYW4gdXAgdGhlIGV2ZW50IGluIGNhc2UgaXQgaXMgYmVpbmcgcmV1c2VkCgkJZXZlbnQucmVzdWx0ID0gdW5kZWZpbmVkOwoJCWlmICggIWV2ZW50LnRhcmdldCApIHsKCQkJZXZlbnQudGFyZ2V0ID0gZWxlbTsKCQl9CgoJCS8vIENsb25lIGFueSBpbmNvbWluZyBkYXRhIGFuZCBwcmVwZW5kIHRoZSBldmVudCwgY3JlYXRpbmcgdGhlIGhhbmRsZXIgYXJnIGxpc3QKCQlkYXRhID0gZGF0YSA9PSBudWxsID8KCQkJWyBldmVudCBdIDoKCQkJalF1ZXJ5Lm1ha2VBcnJheSggZGF0YSwgWyBldmVudCBdICk7CgoJCS8vIEFsbG93IHNwZWNpYWwgZXZlbnRzIHRvIGRyYXcgb3V0c2lkZSB0aGUgbGluZXMKCQlzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIHR5cGUgXSB8fCB7fTsKCQlpZiAoICFvbmx5SGFuZGxlcnMgJiYgc3BlY2lhbC50cmlnZ2VyICYmIHNwZWNpYWwudHJpZ2dlci5hcHBseSggZWxlbSwgZGF0YSApID09PSBmYWxzZSApIHsKCQkJcmV0dXJuOwoJCX0KCgkJLy8gRGV0ZXJtaW5lIGV2ZW50IHByb3BhZ2F0aW9uIHBhdGggaW4gYWR2YW5jZSwgcGVyIFczQyBldmVudHMgc3BlYyAoIzk5NTEpCgkJLy8gQnViYmxlIHVwIHRvIGRvY3VtZW50LCB0aGVuIHRvIHdpbmRvdzsgd2F0Y2ggZm9yIGEgZ2xvYmFsIG93bmVyRG9jdW1lbnQgdmFyICgjOTcyNCkKCQlpZiAoICFvbmx5SGFuZGxlcnMgJiYgIXNwZWNpYWwubm9CdWJibGUgJiYgIWpRdWVyeS5pc1dpbmRvdyggZWxlbSApICkgewoKCQkJYnViYmxlVHlwZSA9IHNwZWNpYWwuZGVsZWdhdGVUeXBlIHx8IHR5cGU7CgkJCWlmICggIXJmb2N1c01vcnBoLnRlc3QoIGJ1YmJsZVR5cGUgKyB0eXBlICkgKSB7CgkJCQljdXIgPSBjdXIucGFyZW50Tm9kZTsKCQkJfQoJCQlmb3IgKCA7IGN1cjsgY3VyID0gY3VyLnBhcmVudE5vZGUgKSB7CgkJCQlldmVudFBhdGgucHVzaCggY3VyICk7CgkJCQl0bXAgPSBjdXI7CgkJCX0KCgkJCS8vIE9ubHkgYWRkIHdpbmRvdyBpZiB3ZSBnb3QgdG8gZG9jdW1lbnQgKGUuZy4sIG5vdCBwbGFpbiBvYmogb3IgZGV0YWNoZWQgRE9NKQoJCQlpZiAoIHRtcCA9PT0gKGVsZW0ub3duZXJEb2N1bWVudCB8fCBkb2N1bWVudCkgKSB7CgkJCQlldmVudFBhdGgucHVzaCggdG1wLmRlZmF1bHRWaWV3IHx8IHRtcC5wYXJlbnRXaW5kb3cgfHwgd2luZG93ICk7CgkJCX0KCQl9CgoJCS8vIEZpcmUgaGFuZGxlcnMgb24gdGhlIGV2ZW50IHBhdGgKCQlpID0gMDsKCQl3aGlsZSAoIChjdXIgPSBldmVudFBhdGhbaSsrXSkgJiYgIWV2ZW50LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkgKSB7CgoJCQlldmVudC50eXBlID0gaSA+IDEgPwoJCQkJYnViYmxlVHlwZSA6CgkJCQlzcGVjaWFsLmJpbmRUeXBlIHx8IHR5cGU7CgoJCQkvLyBqUXVlcnkgaGFuZGxlcgoJCQloYW5kbGUgPSAoIGRhdGFfcHJpdi5nZXQoIGN1ciwgImV2ZW50cyIgKSB8fCB7fSApWyBldmVudC50eXBlIF0gJiYgZGF0YV9wcml2LmdldCggY3VyLCAiaGFuZGxlIiApOwoJCQlpZiAoIGhhbmRsZSApIHsKCQkJCWhhbmRsZS5hcHBseSggY3VyLCBkYXRhICk7CgkJCX0KCgkJCS8vIE5hdGl2ZSBoYW5kbGVyCgkJCWhhbmRsZSA9IG9udHlwZSAmJiBjdXJbIG9udHlwZSBdOwoJCQlpZiAoIGhhbmRsZSAmJiBoYW5kbGUuYXBwbHkgJiYgalF1ZXJ5LmFjY2VwdERhdGEoIGN1ciApICkgewoJCQkJZXZlbnQucmVzdWx0ID0gaGFuZGxlLmFwcGx5KCBjdXIsIGRhdGEgKTsKCQkJCWlmICggZXZlbnQucmVzdWx0ID09PSBmYWxzZSApIHsKCQkJCQlldmVudC5wcmV2ZW50RGVmYXVsdCgpOwoJCQkJfQoJCQl9CgkJfQoJCWV2ZW50LnR5cGUgPSB0eXBlOwoKCQkvLyBJZiBub2JvZHkgcHJldmVudGVkIHRoZSBkZWZhdWx0IGFjdGlvbiwgZG8gaXQgbm93CgkJaWYgKCAhb25seUhhbmRsZXJzICYmICFldmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSApIHsKCgkJCWlmICggKCFzcGVjaWFsLl9kZWZhdWx0IHx8IHNwZWNpYWwuX2RlZmF1bHQuYXBwbHkoIGV2ZW50UGF0aC5wb3AoKSwgZGF0YSApID09PSBmYWxzZSkgJiYKCQkJCWpRdWVyeS5hY2NlcHREYXRhKCBlbGVtICkgKSB7CgoJCQkJLy8gQ2FsbCBhIG5hdGl2ZSBET00gbWV0aG9kIG9uIHRoZSB0YXJnZXQgd2l0aCB0aGUgc2FtZSBuYW1lIG5hbWUgYXMgdGhlIGV2ZW50LgoJCQkJLy8gRG9uJ3QgZG8gZGVmYXVsdCBhY3Rpb25zIG9uIHdpbmRvdywgdGhhdCdzIHdoZXJlIGdsb2JhbCB2YXJpYWJsZXMgYmUgKCM2MTcwKQoJCQkJaWYgKCBvbnR5cGUgJiYgalF1ZXJ5LmlzRnVuY3Rpb24oIGVsZW1bIHR5cGUgXSApICYmICFqUXVlcnkuaXNXaW5kb3coIGVsZW0gKSApIHsKCgkJCQkJLy8gRG9uJ3QgcmUtdHJpZ2dlciBhbiBvbkZPTyBldmVudCB3aGVuIHdlIGNhbGwgaXRzIEZPTygpIG1ldGhvZAoJCQkJCXRtcCA9IGVsZW1bIG9udHlwZSBdOwoKCQkJCQlpZiAoIHRtcCApIHsKCQkJCQkJZWxlbVsgb250eXBlIF0gPSBudWxsOwoJCQkJCX0KCgkJCQkJLy8gUHJldmVudCByZS10cmlnZ2VyaW5nIG9mIHRoZSBzYW1lIGV2ZW50LCBzaW5jZSB3ZSBhbHJlYWR5IGJ1YmJsZWQgaXQgYWJvdmUKCQkJCQlqUXVlcnkuZXZlbnQudHJpZ2dlcmVkID0gdHlwZTsKCQkJCQllbGVtWyB0eXBlIF0oKTsKCQkJCQlqUXVlcnkuZXZlbnQudHJpZ2dlcmVkID0gdW5kZWZpbmVkOwoKCQkJCQlpZiAoIHRtcCApIHsKCQkJCQkJZWxlbVsgb250eXBlIF0gPSB0bXA7CgkJCQkJfQoJCQkJfQoJCQl9CgkJfQoKCQlyZXR1cm4gZXZlbnQucmVzdWx0OwoJfSwKCglkaXNwYXRjaDogZnVuY3Rpb24oIGV2ZW50ICkgewoKCQkvLyBNYWtlIGEgd3JpdGFibGUgalF1ZXJ5LkV2ZW50IGZyb20gdGhlIG5hdGl2ZSBldmVudCBvYmplY3QKCQlldmVudCA9IGpRdWVyeS5ldmVudC5maXgoIGV2ZW50ICk7CgoJCXZhciBpLCBqLCByZXQsIG1hdGNoZWQsIGhhbmRsZU9iaiwKCQkJaGFuZGxlclF1ZXVlID0gW10sCgkJCWFyZ3MgPSBzbGljZS5jYWxsKCBhcmd1bWVudHMgKSwKCQkJaGFuZGxlcnMgPSAoIGRhdGFfcHJpdi5nZXQoIHRoaXMsICJldmVudHMiICkgfHwge30gKVsgZXZlbnQudHlwZSBdIHx8IFtdLAoJCQlzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIGV2ZW50LnR5cGUgXSB8fCB7fTsKCgkJLy8gVXNlIHRoZSBmaXgtZWQgalF1ZXJ5LkV2ZW50IHJhdGhlciB0aGFuIHRoZSAocmVhZC1vbmx5KSBuYXRpdmUgZXZlbnQKCQlhcmdzWzBdID0gZXZlbnQ7CgkJZXZlbnQuZGVsZWdhdGVUYXJnZXQgPSB0aGlzOwoKCQkvLyBDYWxsIHRoZSBwcmVEaXNwYXRjaCBob29rIGZvciB0aGUgbWFwcGVkIHR5cGUsIGFuZCBsZXQgaXQgYmFpbCBpZiBkZXNpcmVkCgkJaWYgKCBzcGVjaWFsLnByZURpc3BhdGNoICYmIHNwZWNpYWwucHJlRGlzcGF0Y2guY2FsbCggdGhpcywgZXZlbnQgKSA9PT0gZmFsc2UgKSB7CgkJCXJldHVybjsKCQl9CgoJCS8vIERldGVybWluZSBoYW5kbGVycwoJCWhhbmRsZXJRdWV1ZSA9IGpRdWVyeS5ldmVudC5oYW5kbGVycy5jYWxsKCB0aGlzLCBldmVudCwgaGFuZGxlcnMgKTsKCgkJLy8gUnVuIGRlbGVnYXRlcyBmaXJzdDsgdGhleSBtYXkgd2FudCB0byBzdG9wIHByb3BhZ2F0aW9uIGJlbmVhdGggdXMKCQlpID0gMDsKCQl3aGlsZSAoIChtYXRjaGVkID0gaGFuZGxlclF1ZXVlWyBpKysgXSkgJiYgIWV2ZW50LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkgKSB7CgkJCWV2ZW50LmN1cnJlbnRUYXJnZXQgPSBtYXRjaGVkLmVsZW07CgoJCQlqID0gMDsKCQkJd2hpbGUgKCAoaGFuZGxlT2JqID0gbWF0Y2hlZC5oYW5kbGVyc1sgaisrIF0pICYmICFldmVudC5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCgpICkgewoKCQkJCS8vIFRyaWdnZXJlZCBldmVudCBtdXN0IGVpdGhlciAxKSBoYXZlIG5vIG5hbWVzcGFjZSwgb3IKCQkJCS8vIDIpIGhhdmUgbmFtZXNwYWNlKHMpIGEgc3Vic2V0IG9yIGVxdWFsIHRvIHRob3NlIGluIHRoZSBib3VuZCBldmVudCAoYm90aCBjYW4gaGF2ZSBubyBuYW1lc3BhY2UpLgoJCQkJaWYgKCAhZXZlbnQubmFtZXNwYWNlX3JlIHx8IGV2ZW50Lm5hbWVzcGFjZV9yZS50ZXN0KCBoYW5kbGVPYmoubmFtZXNwYWNlICkgKSB7CgoJCQkJCWV2ZW50LmhhbmRsZU9iaiA9IGhhbmRsZU9iajsKCQkJCQlldmVudC5kYXRhID0gaGFuZGxlT2JqLmRhdGE7CgoJCQkJCXJldCA9ICggKGpRdWVyeS5ldmVudC5zcGVjaWFsWyBoYW5kbGVPYmoub3JpZ1R5cGUgXSB8fCB7fSkuaGFuZGxlIHx8IGhhbmRsZU9iai5oYW5kbGVyICkKCQkJCQkJCS5hcHBseSggbWF0Y2hlZC5lbGVtLCBhcmdzICk7CgoJCQkJCWlmICggcmV0ICE9PSB1bmRlZmluZWQgKSB7CgkJCQkJCWlmICggKGV2ZW50LnJlc3VsdCA9IHJldCkgPT09IGZhbHNlICkgewoJCQkJCQkJZXZlbnQucHJldmVudERlZmF1bHQoKTsKCQkJCQkJCWV2ZW50LnN0b3BQcm9wYWdhdGlvbigpOwoJCQkJCQl9CgkJCQkJfQoJCQkJfQoJCQl9CgkJfQoKCQkvLyBDYWxsIHRoZSBwb3N0RGlzcGF0Y2ggaG9vayBmb3IgdGhlIG1hcHBlZCB0eXBlCgkJaWYgKCBzcGVjaWFsLnBvc3REaXNwYXRjaCApIHsKCQkJc3BlY2lhbC5wb3N0RGlzcGF0Y2guY2FsbCggdGhpcywgZXZlbnQgKTsKCQl9CgoJCXJldHVybiBldmVudC5yZXN1bHQ7Cgl9LAoKCWhhbmRsZXJzOiBmdW5jdGlvbiggZXZlbnQsIGhhbmRsZXJzICkgewoJCXZhciBpLCBtYXRjaGVzLCBzZWwsIGhhbmRsZU9iaiwKCQkJaGFuZGxlclF1ZXVlID0gW10sCgkJCWRlbGVnYXRlQ291bnQgPSBoYW5kbGVycy5kZWxlZ2F0ZUNvdW50LAoJCQljdXIgPSBldmVudC50YXJnZXQ7CgoJCS8vIEZpbmQgZGVsZWdhdGUgaGFuZGxlcnMKCQkvLyBCbGFjay1ob2xlIFNWRyA8dXNlPiBpbnN0YW5jZSB0cmVlcyAoIzEzMTgwKQoJCS8vIEF2b2lkIG5vbi1sZWZ0LWNsaWNrIGJ1YmJsaW5nIGluIEZpcmVmb3ggKCMzODYxKQoJCWlmICggZGVsZWdhdGVDb3VudCAmJiBjdXIubm9kZVR5cGUgJiYgKCFldmVudC5idXR0b24gfHwgZXZlbnQudHlwZSAhPT0gImNsaWNrIikgKSB7CgoJCQlmb3IgKCA7IGN1ciAhPT0gdGhpczsgY3VyID0gY3VyLnBhcmVudE5vZGUgfHwgdGhpcyApIHsKCgkJCQkvLyBEb24ndCBwcm9jZXNzIGNsaWNrcyBvbiBkaXNhYmxlZCBlbGVtZW50cyAoIzY5MTEsICM4MTY1LCAjMTEzODIsICMxMTc2NCkKCQkJCWlmICggY3VyLmRpc2FibGVkICE9PSB0cnVlIHx8IGV2ZW50LnR5cGUgIT09ICJjbGljayIgKSB7CgkJCQkJbWF0Y2hlcyA9IFtdOwoJCQkJCWZvciAoIGkgPSAwOyBpIDwgZGVsZWdhdGVDb3VudDsgaSsrICkgewoJCQkJCQloYW5kbGVPYmogPSBoYW5kbGVyc1sgaSBdOwoKCQkJCQkJLy8gRG9uJ3QgY29uZmxpY3Qgd2l0aCBPYmplY3QucHJvdG90eXBlIHByb3BlcnRpZXMgKCMxMzIwMykKCQkJCQkJc2VsID0gaGFuZGxlT2JqLnNlbGVjdG9yICsgIiAiOwoKCQkJCQkJaWYgKCBtYXRjaGVzWyBzZWwgXSA9PT0gdW5kZWZpbmVkICkgewoJCQkJCQkJbWF0Y2hlc1sgc2VsIF0gPSBoYW5kbGVPYmoubmVlZHNDb250ZXh0ID8KCQkJCQkJCQlqUXVlcnkoIHNlbCwgdGhpcyApLmluZGV4KCBjdXIgKSA+PSAwIDoKCQkJCQkJCQlqUXVlcnkuZmluZCggc2VsLCB0aGlzLCBudWxsLCBbIGN1ciBdICkubGVuZ3RoOwoJCQkJCQl9CgkJCQkJCWlmICggbWF0Y2hlc1sgc2VsIF0gKSB7CgkJCQkJCQltYXRjaGVzLnB1c2goIGhhbmRsZU9iaiApOwoJCQkJCQl9CgkJCQkJfQoJCQkJCWlmICggbWF0Y2hlcy5sZW5ndGggKSB7CgkJCQkJCWhhbmRsZXJRdWV1ZS5wdXNoKHsgZWxlbTogY3VyLCBoYW5kbGVyczogbWF0Y2hlcyB9KTsKCQkJCQl9CgkJCQl9CgkJCX0KCQl9CgoJCS8vIEFkZCB0aGUgcmVtYWluaW5nIChkaXJlY3RseS1ib3VuZCkgaGFuZGxlcnMKCQlpZiAoIGRlbGVnYXRlQ291bnQgPCBoYW5kbGVycy5sZW5ndGggKSB7CgkJCWhhbmRsZXJRdWV1ZS5wdXNoKHsgZWxlbTogdGhpcywgaGFuZGxlcnM6IGhhbmRsZXJzLnNsaWNlKCBkZWxlZ2F0ZUNvdW50ICkgfSk7CgkJfQoKCQlyZXR1cm4gaGFuZGxlclF1ZXVlOwoJfSwKCgkvLyBJbmNsdWRlcyBzb21lIGV2ZW50IHByb3BzIHNoYXJlZCBieSBLZXlFdmVudCBhbmQgTW91c2VFdmVudAoJcHJvcHM6ICJhbHRLZXkgYnViYmxlcyBjYW5jZWxhYmxlIGN0cmxLZXkgY3VycmVudFRhcmdldCBldmVudFBoYXNlIG1ldGFLZXkgcmVsYXRlZFRhcmdldCBzaGlmdEtleSB0YXJnZXQgdGltZVN0YW1wIHZpZXcgd2hpY2giLnNwbGl0KCIgIiksCgoJZml4SG9va3M6IHt9LAoKCWtleUhvb2tzOiB7CgkJcHJvcHM6ICJjaGFyIGNoYXJDb2RlIGtleSBrZXlDb2RlIi5zcGxpdCgiICIpLAoJCWZpbHRlcjogZnVuY3Rpb24oIGV2ZW50LCBvcmlnaW5hbCApIHsKCgkJCS8vIEFkZCB3aGljaCBmb3Iga2V5IGV2ZW50cwoJCQlpZiAoIGV2ZW50LndoaWNoID09IG51bGwgKSB7CgkJCQlldmVudC53aGljaCA9IG9yaWdpbmFsLmNoYXJDb2RlICE9IG51bGwgPyBvcmlnaW5hbC5jaGFyQ29kZSA6IG9yaWdpbmFsLmtleUNvZGU7CgkJCX0KCgkJCXJldHVybiBldmVudDsKCQl9Cgl9LAoKCW1vdXNlSG9va3M6IHsKCQlwcm9wczogImJ1dHRvbiBidXR0b25zIGNsaWVudFggY2xpZW50WSBvZmZzZXRYIG9mZnNldFkgcGFnZVggcGFnZVkgc2NyZWVuWCBzY3JlZW5ZIHRvRWxlbWVudCIuc3BsaXQoIiAiKSwKCQlmaWx0ZXI6IGZ1bmN0aW9uKCBldmVudCwgb3JpZ2luYWwgKSB7CgkJCXZhciBldmVudERvYywgZG9jLCBib2R5LAoJCQkJYnV0dG9uID0gb3JpZ2luYWwuYnV0dG9uOwoKCQkJLy8gQ2FsY3VsYXRlIHBhZ2VYL1kgaWYgbWlzc2luZyBhbmQgY2xpZW50WC9ZIGF2YWlsYWJsZQoJCQlpZiAoIGV2ZW50LnBhZ2VYID09IG51bGwgJiYgb3JpZ2luYWwuY2xpZW50WCAhPSBudWxsICkgewoJCQkJZXZlbnREb2MgPSBldmVudC50YXJnZXQub3duZXJEb2N1bWVudCB8fCBkb2N1bWVudDsKCQkJCWRvYyA9IGV2ZW50RG9jLmRvY3VtZW50RWxlbWVudDsKCQkJCWJvZHkgPSBldmVudERvYy5ib2R5OwoKCQkJCWV2ZW50LnBhZ2VYID0gb3JpZ2luYWwuY2xpZW50WCArICggZG9jICYmIGRvYy5zY3JvbGxMZWZ0IHx8IGJvZHkgJiYgYm9keS5zY3JvbGxMZWZ0IHx8IDAgKSAtICggZG9jICYmIGRvYy5jbGllbnRMZWZ0IHx8IGJvZHkgJiYgYm9keS5jbGllbnRMZWZ0IHx8IDAgKTsKCQkJCWV2ZW50LnBhZ2VZID0gb3JpZ2luYWwuY2xpZW50WSArICggZG9jICYmIGRvYy5zY3JvbGxUb3AgIHx8IGJvZHkgJiYgYm9keS5zY3JvbGxUb3AgIHx8IDAgKSAtICggZG9jICYmIGRvYy5jbGllbnRUb3AgIHx8IGJvZHkgJiYgYm9keS5jbGllbnRUb3AgIHx8IDAgKTsKCQkJfQoKCQkJLy8gQWRkIHdoaWNoIGZvciBjbGljazogMSA9PT0gbGVmdDsgMiA9PT0gbWlkZGxlOyAzID09PSByaWdodAoJCQkvLyBOb3RlOiBidXR0b24gaXMgbm90IG5vcm1hbGl6ZWQsIHNvIGRvbid0IHVzZSBpdAoJCQlpZiAoICFldmVudC53aGljaCAmJiBidXR0b24gIT09IHVuZGVmaW5lZCApIHsKCQkJCWV2ZW50LndoaWNoID0gKCBidXR0b24gJiAxID8gMSA6ICggYnV0dG9uICYgMiA/IDMgOiAoIGJ1dHRvbiAmIDQgPyAyIDogMCApICkgKTsKCQkJfQoKCQkJcmV0dXJuIGV2ZW50OwoJCX0KCX0sCgoJZml4OiBmdW5jdGlvbiggZXZlbnQgKSB7CgkJaWYgKCBldmVudFsgalF1ZXJ5LmV4cGFuZG8gXSApIHsKCQkJcmV0dXJuIGV2ZW50OwoJCX0KCgkJLy8gQ3JlYXRlIGEgd3JpdGFibGUgY29weSBvZiB0aGUgZXZlbnQgb2JqZWN0IGFuZCBub3JtYWxpemUgc29tZSBwcm9wZXJ0aWVzCgkJdmFyIGksIHByb3AsIGNvcHksCgkJCXR5cGUgPSBldmVudC50eXBlLAoJCQlvcmlnaW5hbEV2ZW50ID0gZXZlbnQsCgkJCWZpeEhvb2sgPSB0aGlzLmZpeEhvb2tzWyB0eXBlIF07CgoJCWlmICggIWZpeEhvb2sgKSB7CgkJCXRoaXMuZml4SG9va3NbIHR5cGUgXSA9IGZpeEhvb2sgPQoJCQkJcm1vdXNlRXZlbnQudGVzdCggdHlwZSApID8gdGhpcy5tb3VzZUhvb2tzIDoKCQkJCXJrZXlFdmVudC50ZXN0KCB0eXBlICkgPyB0aGlzLmtleUhvb2tzIDoKCQkJCXt9OwoJCX0KCQljb3B5ID0gZml4SG9vay5wcm9wcyA/IHRoaXMucHJvcHMuY29uY2F0KCBmaXhIb29rLnByb3BzICkgOiB0aGlzLnByb3BzOwoKCQlldmVudCA9IG5ldyBqUXVlcnkuRXZlbnQoIG9yaWdpbmFsRXZlbnQgKTsKCgkJaSA9IGNvcHkubGVuZ3RoOwoJCXdoaWxlICggaS0tICkgewoJCQlwcm9wID0gY29weVsgaSBdOwoJCQlldmVudFsgcHJvcCBdID0gb3JpZ2luYWxFdmVudFsgcHJvcCBdOwoJCX0KCgkJLy8gU3VwcG9ydDogQ29yZG92YSAyLjUgKFdlYktpdCkgKCMxMzI1NSkKCQkvLyBBbGwgZXZlbnRzIHNob3VsZCBoYXZlIGEgdGFyZ2V0OyBDb3Jkb3ZhIGRldmljZXJlYWR5IGRvZXNuJ3QKCQlpZiAoICFldmVudC50YXJnZXQgKSB7CgkJCWV2ZW50LnRhcmdldCA9IGRvY3VtZW50OwoJCX0KCgkJLy8gU3VwcG9ydDogU2FmYXJpIDYuMCssIENocm9tZSA8IDI4CgkJLy8gVGFyZ2V0IHNob3VsZCBub3QgYmUgYSB0ZXh0IG5vZGUgKCM1MDQsICMxMzE0MykKCQlpZiAoIGV2ZW50LnRhcmdldC5ub2RlVHlwZSA9PT0gMyApIHsKCQkJZXZlbnQudGFyZ2V0ID0gZXZlbnQudGFyZ2V0LnBhcmVudE5vZGU7CgkJfQoKCQlyZXR1cm4gZml4SG9vay5maWx0ZXIgPyBmaXhIb29rLmZpbHRlciggZXZlbnQsIG9yaWdpbmFsRXZlbnQgKSA6IGV2ZW50OwoJfSwKCglzcGVjaWFsOiB7CgkJbG9hZDogewoJCQkvLyBQcmV2ZW50IHRyaWdnZXJlZCBpbWFnZS5sb2FkIGV2ZW50cyBmcm9tIGJ1YmJsaW5nIHRvIHdpbmRvdy5sb2FkCgkJCW5vQnViYmxlOiB0cnVlCgkJfSwKCQlmb2N1czogewoJCQkvLyBGaXJlIG5hdGl2ZSBldmVudCBpZiBwb3NzaWJsZSBzbyBibHVyL2ZvY3VzIHNlcXVlbmNlIGlzIGNvcnJlY3QKCQkJdHJpZ2dlcjogZnVuY3Rpb24oKSB7CgkJCQlpZiAoIHRoaXMgIT09IHNhZmVBY3RpdmVFbGVtZW50KCkgJiYgdGhpcy5mb2N1cyApIHsKCQkJCQl0aGlzLmZvY3VzKCk7CgkJCQkJcmV0dXJuIGZhbHNlOwoJCQkJfQoJCQl9LAoJCQlkZWxlZ2F0ZVR5cGU6ICJmb2N1c2luIgoJCX0sCgkJYmx1cjogewoJCQl0cmlnZ2VyOiBmdW5jdGlvbigpIHsKCQkJCWlmICggdGhpcyA9PT0gc2FmZUFjdGl2ZUVsZW1lbnQoKSAmJiB0aGlzLmJsdXIgKSB7CgkJCQkJdGhpcy5ibHVyKCk7CgkJCQkJcmV0dXJuIGZhbHNlOwoJCQkJfQoJCQl9LAoJCQlkZWxlZ2F0ZVR5cGU6ICJmb2N1c291dCIKCQl9LAoJCWNsaWNrOiB7CgkJCS8vIEZvciBjaGVja2JveCwgZmlyZSBuYXRpdmUgZXZlbnQgc28gY2hlY2tlZCBzdGF0ZSB3aWxsIGJlIHJpZ2h0CgkJCXRyaWdnZXI6IGZ1bmN0aW9uKCkgewoJCQkJaWYgKCB0aGlzLnR5cGUgPT09ICJjaGVja2JveCIgJiYgdGhpcy5jbGljayAmJiBqUXVlcnkubm9kZU5hbWUoIHRoaXMsICJpbnB1dCIgKSApIHsKCQkJCQl0aGlzLmNsaWNrKCk7CgkJCQkJcmV0dXJuIGZhbHNlOwoJCQkJfQoJCQl9LAoKCQkJLy8gRm9yIGNyb3NzLWJyb3dzZXIgY29uc2lzdGVuY3ksIGRvbid0IGZpcmUgbmF0aXZlIC5jbGljaygpIG9uIGxpbmtzCgkJCV9kZWZhdWx0OiBmdW5jdGlvbiggZXZlbnQgKSB7CgkJCQlyZXR1cm4galF1ZXJ5Lm5vZGVOYW1lKCBldmVudC50YXJnZXQsICJhIiApOwoJCQl9CgkJfSwKCgkJYmVmb3JldW5sb2FkOiB7CgkJCXBvc3REaXNwYXRjaDogZnVuY3Rpb24oIGV2ZW50ICkgewoKCQkJCS8vIFN1cHBvcnQ6IEZpcmVmb3ggMjArCgkJCQkvLyBGaXJlZm94IGRvZXNuJ3QgYWxlcnQgaWYgdGhlIHJldHVyblZhbHVlIGZpZWxkIGlzIG5vdCBzZXQuCgkJCQlpZiAoIGV2ZW50LnJlc3VsdCAhPT0gdW5kZWZpbmVkICYmIGV2ZW50Lm9yaWdpbmFsRXZlbnQgKSB7CgkJCQkJZXZlbnQub3JpZ2luYWxFdmVudC5yZXR1cm5WYWx1ZSA9IGV2ZW50LnJlc3VsdDsKCQkJCX0KCQkJfQoJCX0KCX0sCgoJc2ltdWxhdGU6IGZ1bmN0aW9uKCB0eXBlLCBlbGVtLCBldmVudCwgYnViYmxlICkgewoJCS8vIFBpZ2d5YmFjayBvbiBhIGRvbm9yIGV2ZW50IHRvIHNpbXVsYXRlIGEgZGlmZmVyZW50IG9uZS4KCQkvLyBGYWtlIG9yaWdpbmFsRXZlbnQgdG8gYXZvaWQgZG9ub3IncyBzdG9wUHJvcGFnYXRpb24sIGJ1dCBpZiB0aGUKCQkvLyBzaW11bGF0ZWQgZXZlbnQgcHJldmVudHMgZGVmYXVsdCB0aGVuIHdlIGRvIHRoZSBzYW1lIG9uIHRoZSBkb25vci4KCQl2YXIgZSA9IGpRdWVyeS5leHRlbmQoCgkJCW5ldyBqUXVlcnkuRXZlbnQoKSwKCQkJZXZlbnQsCgkJCXsKCQkJCXR5cGU6IHR5cGUsCgkJCQlpc1NpbXVsYXRlZDogdHJ1ZSwKCQkJCW9yaWdpbmFsRXZlbnQ6IHt9CgkJCX0KCQkpOwoJCWlmICggYnViYmxlICkgewoJCQlqUXVlcnkuZXZlbnQudHJpZ2dlciggZSwgbnVsbCwgZWxlbSApOwoJCX0gZWxzZSB7CgkJCWpRdWVyeS5ldmVudC5kaXNwYXRjaC5jYWxsKCBlbGVtLCBlICk7CgkJfQoJCWlmICggZS5pc0RlZmF1bHRQcmV2ZW50ZWQoKSApIHsKCQkJZXZlbnQucHJldmVudERlZmF1bHQoKTsKCQl9Cgl9Cn07CgpqUXVlcnkucmVtb3ZlRXZlbnQgPSBmdW5jdGlvbiggZWxlbSwgdHlwZSwgaGFuZGxlICkgewoJaWYgKCBlbGVtLnJlbW92ZUV2ZW50TGlzdGVuZXIgKSB7CgkJZWxlbS5yZW1vdmVFdmVudExpc3RlbmVyKCB0eXBlLCBoYW5kbGUsIGZhbHNlICk7Cgl9Cn07CgpqUXVlcnkuRXZlbnQgPSBmdW5jdGlvbiggc3JjLCBwcm9wcyApIHsKCS8vIEFsbG93IGluc3RhbnRpYXRpb24gd2l0aG91dCB0aGUgJ25ldycga2V5d29yZAoJaWYgKCAhKHRoaXMgaW5zdGFuY2VvZiBqUXVlcnkuRXZlbnQpICkgewoJCXJldHVybiBuZXcgalF1ZXJ5LkV2ZW50KCBzcmMsIHByb3BzICk7Cgl9CgoJLy8gRXZlbnQgb2JqZWN0CglpZiAoIHNyYyAmJiBzcmMudHlwZSApIHsKCQl0aGlzLm9yaWdpbmFsRXZlbnQgPSBzcmM7CgkJdGhpcy50eXBlID0gc3JjLnR5cGU7CgoJCS8vIEV2ZW50cyBidWJibGluZyB1cCB0aGUgZG9jdW1lbnQgbWF5IGhhdmUgYmVlbiBtYXJrZWQgYXMgcHJldmVudGVkCgkJLy8gYnkgYSBoYW5kbGVyIGxvd2VyIGRvd24gdGhlIHRyZWU7IHJlZmxlY3QgdGhlIGNvcnJlY3QgdmFsdWUuCgkJdGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQgPSBzcmMuZGVmYXVsdFByZXZlbnRlZCB8fAoJCQkJc3JjLmRlZmF1bHRQcmV2ZW50ZWQgPT09IHVuZGVmaW5lZCAmJgoJCQkJLy8gU3VwcG9ydDogQW5kcm9pZCA8IDQuMAoJCQkJc3JjLnJldHVyblZhbHVlID09PSBmYWxzZSA/CgkJCXJldHVyblRydWUgOgoJCQlyZXR1cm5GYWxzZTsKCgkvLyBFdmVudCB0eXBlCgl9IGVsc2UgewoJCXRoaXMudHlwZSA9IHNyYzsKCX0KCgkvLyBQdXQgZXhwbGljaXRseSBwcm92aWRlZCBwcm9wZXJ0aWVzIG9udG8gdGhlIGV2ZW50IG9iamVjdAoJaWYgKCBwcm9wcyApIHsKCQlqUXVlcnkuZXh0ZW5kKCB0aGlzLCBwcm9wcyApOwoJfQoKCS8vIENyZWF0ZSBhIHRpbWVzdGFtcCBpZiBpbmNvbWluZyBldmVudCBkb2Vzbid0IGhhdmUgb25lCgl0aGlzLnRpbWVTdGFtcCA9IHNyYyAmJiBzcmMudGltZVN0YW1wIHx8IGpRdWVyeS5ub3coKTsKCgkvLyBNYXJrIGl0IGFzIGZpeGVkCgl0aGlzWyBqUXVlcnkuZXhwYW5kbyBdID0gdHJ1ZTsKfTsKCi8vIGpRdWVyeS5FdmVudCBpcyBiYXNlZCBvbiBET00zIEV2ZW50cyBhcyBzcGVjaWZpZWQgYnkgdGhlIEVDTUFTY3JpcHQgTGFuZ3VhZ2UgQmluZGluZwovLyBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAzL1dELURPTS1MZXZlbC0zLUV2ZW50cy0yMDAzMDMzMS9lY21hLXNjcmlwdC1iaW5kaW5nLmh0bWwKalF1ZXJ5LkV2ZW50LnByb3RvdHlwZSA9IHsKCWlzRGVmYXVsdFByZXZlbnRlZDogcmV0dXJuRmFsc2UsCglpc1Byb3BhZ2F0aW9uU3RvcHBlZDogcmV0dXJuRmFsc2UsCglpc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZDogcmV0dXJuRmFsc2UsCgoJcHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uKCkgewoJCXZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50OwoKCQl0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IHJldHVyblRydWU7CgoJCWlmICggZSAmJiBlLnByZXZlbnREZWZhdWx0ICkgewoJCQllLnByZXZlbnREZWZhdWx0KCk7CgkJfQoJfSwKCXN0b3BQcm9wYWdhdGlvbjogZnVuY3Rpb24oKSB7CgkJdmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7CgoJCXRoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQgPSByZXR1cm5UcnVlOwoKCQlpZiAoIGUgJiYgZS5zdG9wUHJvcGFnYXRpb24gKSB7CgkJCWUuc3RvcFByb3BhZ2F0aW9uKCk7CgkJfQoJfSwKCXN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbjogZnVuY3Rpb24oKSB7CgkJdmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7CgoJCXRoaXMuaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQgPSByZXR1cm5UcnVlOwoKCQlpZiAoIGUgJiYgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24gKSB7CgkJCWUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7CgkJfQoKCQl0aGlzLnN0b3BQcm9wYWdhdGlvbigpOwoJfQp9OwoKLy8gQ3JlYXRlIG1vdXNlZW50ZXIvbGVhdmUgZXZlbnRzIHVzaW5nIG1vdXNlb3Zlci9vdXQgYW5kIGV2ZW50LXRpbWUgY2hlY2tzCi8vIFN1cHBvcnQ6IENocm9tZSAxNSsKalF1ZXJ5LmVhY2goewoJbW91c2VlbnRlcjogIm1vdXNlb3ZlciIsCgltb3VzZWxlYXZlOiAibW91c2VvdXQiLAoJcG9pbnRlcmVudGVyOiAicG9pbnRlcm92ZXIiLAoJcG9pbnRlcmxlYXZlOiAicG9pbnRlcm91dCIKfSwgZnVuY3Rpb24oIG9yaWcsIGZpeCApIHsKCWpRdWVyeS5ldmVudC5zcGVjaWFsWyBvcmlnIF0gPSB7CgkJZGVsZWdhdGVUeXBlOiBmaXgsCgkJYmluZFR5cGU6IGZpeCwKCgkJaGFuZGxlOiBmdW5jdGlvbiggZXZlbnQgKSB7CgkJCXZhciByZXQsCgkJCQl0YXJnZXQgPSB0aGlzLAoJCQkJcmVsYXRlZCA9IGV2ZW50LnJlbGF0ZWRUYXJnZXQsCgkJCQloYW5kbGVPYmogPSBldmVudC5oYW5kbGVPYmo7CgoJCQkvLyBGb3IgbW91c2VudGVyL2xlYXZlIGNhbGwgdGhlIGhhbmRsZXIgaWYgcmVsYXRlZCBpcyBvdXRzaWRlIHRoZSB0YXJnZXQuCgkJCS8vIE5COiBObyByZWxhdGVkVGFyZ2V0IGlmIHRoZSBtb3VzZSBsZWZ0L2VudGVyZWQgdGhlIGJyb3dzZXIgd2luZG93CgkJCWlmICggIXJlbGF0ZWQgfHwgKHJlbGF0ZWQgIT09IHRhcmdldCAmJiAhalF1ZXJ5LmNvbnRhaW5zKCB0YXJnZXQsIHJlbGF0ZWQgKSkgKSB7CgkJCQlldmVudC50eXBlID0gaGFuZGxlT2JqLm9yaWdUeXBlOwoJCQkJcmV0ID0gaGFuZGxlT2JqLmhhbmRsZXIuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApOwoJCQkJZXZlbnQudHlwZSA9IGZpeDsKCQkJfQoJCQlyZXR1cm4gcmV0OwoJCX0KCX07Cn0pOwoKLy8gQ3JlYXRlICJidWJibGluZyIgZm9jdXMgYW5kIGJsdXIgZXZlbnRzCi8vIFN1cHBvcnQ6IEZpcmVmb3gsIENocm9tZSwgU2FmYXJpCmlmICggIXN1cHBvcnQuZm9jdXNpbkJ1YmJsZXMgKSB7CglqUXVlcnkuZWFjaCh7IGZvY3VzOiAiZm9jdXNpbiIsIGJsdXI6ICJmb2N1c291dCIgfSwgZnVuY3Rpb24oIG9yaWcsIGZpeCApIHsKCgkJLy8gQXR0YWNoIGEgc2luZ2xlIGNhcHR1cmluZyBoYW5kbGVyIG9uIHRoZSBkb2N1bWVudCB3aGlsZSBzb21lb25lIHdhbnRzIGZvY3VzaW4vZm9jdXNvdXQKCQl2YXIgaGFuZGxlciA9IGZ1bmN0aW9uKCBldmVudCApIHsKCQkJCWpRdWVyeS5ldmVudC5zaW11bGF0ZSggZml4LCBldmVudC50YXJnZXQsIGpRdWVyeS5ldmVudC5maXgoIGV2ZW50ICksIHRydWUgKTsKCQkJfTsKCgkJalF1ZXJ5LmV2ZW50LnNwZWNpYWxbIGZpeCBdID0gewoJCQlzZXR1cDogZnVuY3Rpb24oKSB7CgkJCQl2YXIgZG9jID0gdGhpcy5vd25lckRvY3VtZW50IHx8IHRoaXMsCgkJCQkJYXR0YWNoZXMgPSBkYXRhX3ByaXYuYWNjZXNzKCBkb2MsIGZpeCApOwoKCQkJCWlmICggIWF0dGFjaGVzICkgewoJCQkJCWRvYy5hZGRFdmVudExpc3RlbmVyKCBvcmlnLCBoYW5kbGVyLCB0cnVlICk7CgkJCQl9CgkJCQlkYXRhX3ByaXYuYWNjZXNzKCBkb2MsIGZpeCwgKCBhdHRhY2hlcyB8fCAwICkgKyAxICk7CgkJCX0sCgkJCXRlYXJkb3duOiBmdW5jdGlvbigpIHsKCQkJCXZhciBkb2MgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcywKCQkJCQlhdHRhY2hlcyA9IGRhdGFfcHJpdi5hY2Nlc3MoIGRvYywgZml4ICkgLSAxOwoKCQkJCWlmICggIWF0dGFjaGVzICkgewoJCQkJCWRvYy5yZW1vdmVFdmVudExpc3RlbmVyKCBvcmlnLCBoYW5kbGVyLCB0cnVlICk7CgkJCQkJZGF0YV9wcml2LnJlbW92ZSggZG9jLCBmaXggKTsKCgkJCQl9IGVsc2UgewoJCQkJCWRhdGFfcHJpdi5hY2Nlc3MoIGRvYywgZml4LCBhdHRhY2hlcyApOwoJCQkJfQoJCQl9CgkJfTsKCX0pOwp9CgpqUXVlcnkuZm4uZXh0ZW5kKHsKCglvbjogZnVuY3Rpb24oIHR5cGVzLCBzZWxlY3RvciwgZGF0YSwgZm4sIC8qSU5URVJOQUwqLyBvbmUgKSB7CgkJdmFyIG9yaWdGbiwgdHlwZTsKCgkJLy8gVHlwZXMgY2FuIGJlIGEgbWFwIG9mIHR5cGVzL2hhbmRsZXJzCgkJaWYgKCB0eXBlb2YgdHlwZXMgPT09ICJvYmplY3QiICkgewoJCQkvLyAoIHR5cGVzLU9iamVjdCwgc2VsZWN0b3IsIGRhdGEgKQoJCQlpZiAoIHR5cGVvZiBzZWxlY3RvciAhPT0gInN0cmluZyIgKSB7CgkJCQkvLyAoIHR5cGVzLU9iamVjdCwgZGF0YSApCgkJCQlkYXRhID0gZGF0YSB8fCBzZWxlY3RvcjsKCQkJCXNlbGVjdG9yID0gdW5kZWZpbmVkOwoJCQl9CgkJCWZvciAoIHR5cGUgaW4gdHlwZXMgKSB7CgkJCQl0aGlzLm9uKCB0eXBlLCBzZWxlY3RvciwgZGF0YSwgdHlwZXNbIHR5cGUgXSwgb25lICk7CgkJCX0KCQkJcmV0dXJuIHRoaXM7CgkJfQoKCQlpZiAoIGRhdGEgPT0gbnVsbCAmJiBmbiA9PSBudWxsICkgewoJCQkvLyAoIHR5cGVzLCBmbiApCgkJCWZuID0gc2VsZWN0b3I7CgkJCWRhdGEgPSBzZWxlY3RvciA9IHVuZGVmaW5lZDsKCQl9IGVsc2UgaWYgKCBmbiA9PSBudWxsICkgewoJCQlpZiAoIHR5cGVvZiBzZWxlY3RvciA9PT0gInN0cmluZyIgKSB7CgkJCQkvLyAoIHR5cGVzLCBzZWxlY3RvciwgZm4gKQoJCQkJZm4gPSBkYXRhOwoJCQkJZGF0YSA9IHVuZGVmaW5lZDsKCQkJfSBlbHNlIHsKCQkJCS8vICggdHlwZXMsIGRhdGEsIGZuICkKCQkJCWZuID0gZGF0YTsKCQkJCWRhdGEgPSBzZWxlY3RvcjsKCQkJCXNlbGVjdG9yID0gdW5kZWZpbmVkOwoJCQl9CgkJfQoJCWlmICggZm4gPT09IGZhbHNlICkgewoJCQlmbiA9IHJldHVybkZhbHNlOwoJCX0gZWxzZSBpZiAoICFmbiApIHsKCQkJcmV0dXJuIHRoaXM7CgkJfQoKCQlpZiAoIG9uZSA9PT0gMSApIHsKCQkJb3JpZ0ZuID0gZm47CgkJCWZuID0gZnVuY3Rpb24oIGV2ZW50ICkgewoJCQkJLy8gQ2FuIHVzZSBhbiBlbXB0eSBzZXQsIHNpbmNlIGV2ZW50IGNvbnRhaW5zIHRoZSBpbmZvCgkJCQlqUXVlcnkoKS5vZmYoIGV2ZW50ICk7CgkJCQlyZXR1cm4gb3JpZ0ZuLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTsKCQkJfTsKCQkJLy8gVXNlIHNhbWUgZ3VpZCBzbyBjYWxsZXIgY2FuIHJlbW92ZSB1c2luZyBvcmlnRm4KCQkJZm4uZ3VpZCA9IG9yaWdGbi5ndWlkIHx8ICggb3JpZ0ZuLmd1aWQgPSBqUXVlcnkuZ3VpZCsrICk7CgkJfQoJCXJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkgewoJCQlqUXVlcnkuZXZlbnQuYWRkKCB0aGlzLCB0eXBlcywgZm4sIGRhdGEsIHNlbGVjdG9yICk7CgkJfSk7Cgl9LAoJb25lOiBmdW5jdGlvbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApIHsKCQlyZXR1cm4gdGhpcy5vbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiwgMSApOwoJfSwKCW9mZjogZnVuY3Rpb24oIHR5cGVzLCBzZWxlY3RvciwgZm4gKSB7CgkJdmFyIGhhbmRsZU9iaiwgdHlwZTsKCQlpZiAoIHR5cGVzICYmIHR5cGVzLnByZXZlbnREZWZhdWx0ICYmIHR5cGVzLmhhbmRsZU9iaiApIHsKCQkJLy8gKCBldmVudCApICBkaXNwYXRjaGVkIGpRdWVyeS5FdmVudAoJCQloYW5kbGVPYmogPSB0eXBlcy5oYW5kbGVPYmo7CgkJCWpRdWVyeSggdHlwZXMuZGVsZWdhdGVUYXJnZXQgKS5vZmYoCgkJCQloYW5kbGVPYmoubmFtZXNwYWNlID8gaGFuZGxlT2JqLm9yaWdUeXBlICsgIi4iICsgaGFuZGxlT2JqLm5hbWVzcGFjZSA6IGhhbmRsZU9iai5vcmlnVHlwZSwKCQkJCWhhbmRsZU9iai5zZWxlY3RvciwKCQkJCWhhbmRsZU9iai5oYW5kbGVyCgkJCSk7CgkJCXJldHVybiB0aGlzOwoJCX0KCQlpZiAoIHR5cGVvZiB0eXBlcyA9PT0gIm9iamVjdCIgKSB7CgkJCS8vICggdHlwZXMtb2JqZWN0IFssIHNlbGVjdG9yXSApCgkJCWZvciAoIHR5cGUgaW4gdHlwZXMgKSB7CgkJCQl0aGlzLm9mZiggdHlwZSwgc2VsZWN0b3IsIHR5cGVzWyB0eXBlIF0gKTsKCQkJfQoJCQlyZXR1cm4gdGhpczsKCQl9CgkJaWYgKCBzZWxlY3RvciA9PT0gZmFsc2UgfHwgdHlwZW9mIHNlbGVjdG9yID09PSAiZnVuY3Rpb24iICkgewoJCQkvLyAoIHR5cGVzIFssIGZuXSApCgkJCWZuID0gc2VsZWN0b3I7CgkJCXNlbGVjdG9yID0gdW5kZWZpbmVkOwoJCX0KCQlpZiAoIGZuID09PSBmYWxzZSApIHsKCQkJZm4gPSByZXR1cm5GYWxzZTsKCQl9CgkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHsKCQkJalF1ZXJ5LmV2ZW50LnJlbW92ZSggdGhpcywgdHlwZXMsIGZuLCBzZWxlY3RvciApOwoJCX0pOwoJfSwKCgl0cmlnZ2VyOiBmdW5jdGlvbiggdHlwZSwgZGF0YSApIHsKCQlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkgewoJCQlqUXVlcnkuZXZlbnQudHJpZ2dlciggdHlwZSwgZGF0YSwgdGhpcyApOwoJCX0pOwoJfSwKCXRyaWdnZXJIYW5kbGVyOiBmdW5jdGlvbiggdHlwZSwgZGF0YSApIHsKCQl2YXIgZWxlbSA9IHRoaXNbMF07CgkJaWYgKCBlbGVtICkgewoJCQlyZXR1cm4galF1ZXJ5LmV2ZW50LnRyaWdnZXIoIHR5cGUsIGRhdGEsIGVsZW0sIHRydWUgKTsKCQl9Cgl9Cn0pOwoKCnZhcgoJcnhodG1sVGFnID0gLzwoPyFhcmVhfGJyfGNvbHxlbWJlZHxocnxpbWd8aW5wdXR8bGlua3xtZXRhfHBhcmFtKSgoW1x3Ol0rKVtePl0qKVwvPi9naSwKCXJ0YWdOYW1lID0gLzwoW1x3Ol0rKS8sCglyaHRtbCA9IC88fCYjP1x3KzsvLAoJcm5vSW5uZXJodG1sID0gLzwoPzpzY3JpcHR8c3R5bGV8bGluaykvaSwKCS8vIGNoZWNrZWQ9ImNoZWNrZWQiIG9yIGNoZWNrZWQKCXJjaGVja2VkID0gL2NoZWNrZWRccyooPzpbXj1dfD1ccyouY2hlY2tlZC4pL2ksCglyc2NyaXB0VHlwZSA9IC9eJHxcLyg/OmphdmF8ZWNtYSlzY3JpcHQvaSwKCXJzY3JpcHRUeXBlTWFza2VkID0gL150cnVlXC8oLiopLywKCXJjbGVhblNjcmlwdCA9IC9eXHMqPCEoPzpcW0NEQVRBXFt8LS0pfCg/OlxdXF18LS0pPlxzKiQvZywKCgkvLyBXZSBoYXZlIHRvIGNsb3NlIHRoZXNlIHRhZ3MgdG8gc3VwcG9ydCBYSFRNTCAoIzEzMjAwKQoJd3JhcE1hcCA9IHsKCgkJLy8gU3VwcG9ydDogSUUgOQoJCW9wdGlvbjogWyAxLCAiPHNlbGVjdCBtdWx0aXBsZT0nbXVsdGlwbGUnPiIsICI8L3NlbGVjdD4iIF0sCgoJCXRoZWFkOiBbIDEsICI8dGFibGU+IiwgIjwvdGFibGU+IiBdLAoJCWNvbDogWyAyLCAiPHRhYmxlPjxjb2xncm91cD4iLCAiPC9jb2xncm91cD48L3RhYmxlPiIgXSwKCQl0cjogWyAyLCAiPHRhYmxlPjx0Ym9keT4iLCAiPC90Ym9keT48L3RhYmxlPiIgXSwKCQl0ZDogWyAzLCAiPHRhYmxlPjx0Ym9keT48dHI+IiwgIjwvdHI+PC90Ym9keT48L3RhYmxlPiIgXSwKCgkJX2RlZmF1bHQ6IFsgMCwgIiIsICIiIF0KCX07CgovLyBTdXBwb3J0OiBJRSA5CndyYXBNYXAub3B0Z3JvdXAgPSB3cmFwTWFwLm9wdGlvbjsKCndyYXBNYXAudGJvZHkgPSB3cmFwTWFwLnRmb290ID0gd3JhcE1hcC5jb2xncm91cCA9IHdyYXBNYXAuY2FwdGlvbiA9IHdyYXBNYXAudGhlYWQ7CndyYXBNYXAudGggPSB3cmFwTWFwLnRkOwoKLy8gU3VwcG9ydDogMS54IGNvbXBhdGliaWxpdHkKLy8gTWFuaXB1bGF0aW5nIHRhYmxlcyByZXF1aXJlcyBhIHRib2R5CmZ1bmN0aW9uIG1hbmlwdWxhdGlvblRhcmdldCggZWxlbSwgY29udGVudCApIHsKCXJldHVybiBqUXVlcnkubm9kZU5hbWUoIGVsZW0sICJ0YWJsZSIgKSAmJgoJCWpRdWVyeS5ub2RlTmFtZSggY29udGVudC5ub2RlVHlwZSAhPT0gMTEgPyBjb250ZW50IDogY29udGVudC5maXJzdENoaWxkLCAidHIiICkgPwoKCQllbGVtLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJ0Ym9keSIpWzBdIHx8CgkJCWVsZW0uYXBwZW5kQ2hpbGQoIGVsZW0ub3duZXJEb2N1bWVudC5jcmVhdGVFbGVtZW50KCJ0Ym9keSIpICkgOgoJCWVsZW07Cn0KCi8vIFJlcGxhY2UvcmVzdG9yZSB0aGUgdHlwZSBhdHRyaWJ1dGUgb2Ygc2NyaXB0IGVsZW1lbnRzIGZvciBzYWZlIERPTSBtYW5pcHVsYXRpb24KZnVuY3Rpb24gZGlzYWJsZVNjcmlwdCggZWxlbSApIHsKCWVsZW0udHlwZSA9IChlbGVtLmdldEF0dHJpYnV0ZSgidHlwZSIpICE9PSBudWxsKSArICIvIiArIGVsZW0udHlwZTsKCXJldHVybiBlbGVtOwp9CmZ1bmN0aW9uIHJlc3RvcmVTY3JpcHQoIGVsZW0gKSB7Cgl2YXIgbWF0Y2ggPSByc2NyaXB0VHlwZU1hc2tlZC5leGVjKCBlbGVtLnR5cGUgKTsKCglpZiAoIG1hdGNoICkgewoJCWVsZW0udHlwZSA9IG1hdGNoWyAxIF07Cgl9IGVsc2UgewoJCWVsZW0ucmVtb3ZlQXR0cmlidXRlKCJ0eXBlIik7Cgl9CgoJcmV0dXJuIGVsZW07Cn0KCi8vIE1hcmsgc2NyaXB0cyBhcyBoYXZpbmcgYWxyZWFkeSBiZWVuIGV2YWx1YXRlZApmdW5jdGlvbiBzZXRHbG9iYWxFdmFsKCBlbGVtcywgcmVmRWxlbWVudHMgKSB7Cgl2YXIgaSA9IDAsCgkJbCA9IGVsZW1zLmxlbmd0aDsKCglmb3IgKCA7IGkgPCBsOyBpKysgKSB7CgkJZGF0YV9wcml2LnNldCgKCQkJZWxlbXNbIGkgXSwgImdsb2JhbEV2YWwiLCAhcmVmRWxlbWVudHMgfHwgZGF0YV9wcml2LmdldCggcmVmRWxlbWVudHNbIGkgXSwgImdsb2JhbEV2YWwiICkKCQkpOwoJfQp9CgpmdW5jdGlvbiBjbG9uZUNvcHlFdmVudCggc3JjLCBkZXN0ICkgewoJdmFyIGksIGwsIHR5cGUsIHBkYXRhT2xkLCBwZGF0YUN1ciwgdWRhdGFPbGQsIHVkYXRhQ3VyLCBldmVudHM7CgoJaWYgKCBkZXN0Lm5vZGVUeXBlICE9PSAxICkgewoJCXJldHVybjsKCX0KCgkvLyAxLiBDb3B5IHByaXZhdGUgZGF0YTogZXZlbnRzLCBoYW5kbGVycywgZXRjLgoJaWYgKCBkYXRhX3ByaXYuaGFzRGF0YSggc3JjICkgKSB7CgkJcGRhdGFPbGQgPSBkYXRhX3ByaXYuYWNjZXNzKCBzcmMgKTsKCQlwZGF0YUN1ciA9IGRhdGFfcHJpdi5zZXQoIGRlc3QsIHBkYXRhT2xkICk7CgkJZXZlbnRzID0gcGRhdGFPbGQuZXZlbnRzOwoKCQlpZiAoIGV2ZW50cyApIHsKCQkJZGVsZXRlIHBkYXRhQ3VyLmhhbmRsZTsKCQkJcGRhdGFDdXIuZXZlbnRzID0ge307CgoJCQlmb3IgKCB0eXBlIGluIGV2ZW50cyApIHsKCQkJCWZvciAoIGkgPSAwLCBsID0gZXZlbnRzWyB0eXBlIF0ubGVuZ3RoOyBpIDwgbDsgaSsrICkgewoJCQkJCWpRdWVyeS5ldmVudC5hZGQoIGRlc3QsIHR5cGUsIGV2ZW50c1sgdHlwZSBdWyBpIF0gKTsKCQkJCX0KCQkJfQoJCX0KCX0KCgkvLyAyLiBDb3B5IHVzZXIgZGF0YQoJaWYgKCBkYXRhX3VzZXIuaGFzRGF0YSggc3JjICkgKSB7CgkJdWRhdGFPbGQgPSBkYXRhX3VzZXIuYWNjZXNzKCBzcmMgKTsKCQl1ZGF0YUN1ciA9IGpRdWVyeS5leHRlbmQoIHt9LCB1ZGF0YU9sZCApOwoKCQlkYXRhX3VzZXIuc2V0KCBkZXN0LCB1ZGF0YUN1ciApOwoJfQp9CgpmdW5jdGlvbiBnZXRBbGwoIGNvbnRleHQsIHRhZyApIHsKCXZhciByZXQgPSBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lID8gY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSggdGFnIHx8ICIqIiApIDoKCQkJY29udGV4dC5xdWVyeVNlbGVjdG9yQWxsID8gY29udGV4dC5xdWVyeVNlbGVjdG9yQWxsKCB0YWcgfHwgIioiICkgOgoJCQlbXTsKCglyZXR1cm4gdGFnID09PSB1bmRlZmluZWQgfHwgdGFnICYmIGpRdWVyeS5ub2RlTmFtZSggY29udGV4dCwgdGFnICkgPwoJCWpRdWVyeS5tZXJnZSggWyBjb250ZXh0IF0sIHJldCApIDoKCQlyZXQ7Cn0KCi8vIFN1cHBvcnQ6IElFID49IDkKZnVuY3Rpb24gZml4SW5wdXQoIHNyYywgZGVzdCApIHsKCXZhciBub2RlTmFtZSA9IGRlc3Qubm9kZU5hbWUudG9Mb3dlckNhc2UoKTsKCgkvLyBGYWlscyB0byBwZXJzaXN0IHRoZSBjaGVja2VkIHN0YXRlIG9mIGEgY2xvbmVkIGNoZWNrYm94IG9yIHJhZGlvIGJ1dHRvbi4KCWlmICggbm9kZU5hbWUgPT09ICJpbnB1dCIgJiYgcmNoZWNrYWJsZVR5cGUudGVzdCggc3JjLnR5cGUgKSApIHsKCQlkZXN0LmNoZWNrZWQgPSBzcmMuY2hlY2tlZDsKCgkvLyBGYWlscyB0byByZXR1cm4gdGhlIHNlbGVjdGVkIG9wdGlvbiB0byB0aGUgZGVmYXVsdCBzZWxlY3RlZCBzdGF0ZSB3aGVuIGNsb25pbmcgb3B0aW9ucwoJfSBlbHNlIGlmICggbm9kZU5hbWUgPT09ICJpbnB1dCIgfHwgbm9kZU5hbWUgPT09ICJ0ZXh0YXJlYSIgKSB7CgkJZGVzdC5kZWZhdWx0VmFsdWUgPSBzcmMuZGVmYXVsdFZhbHVlOwoJfQp9CgpqUXVlcnkuZXh0ZW5kKHsKCWNsb25lOiBmdW5jdGlvbiggZWxlbSwgZGF0YUFuZEV2ZW50cywgZGVlcERhdGFBbmRFdmVudHMgKSB7CgkJdmFyIGksIGwsIHNyY0VsZW1lbnRzLCBkZXN0RWxlbWVudHMsCgkJCWNsb25lID0gZWxlbS5jbG9uZU5vZGUoIHRydWUgKSwKCQkJaW5QYWdlID0galF1ZXJ5LmNvbnRhaW5zKCBlbGVtLm93bmVyRG9jdW1lbnQsIGVsZW0gKTsKCgkJLy8gU3VwcG9ydDogSUUgPj0gOQoJCS8vIEZpeCBDbG9uaW5nIGlzc3VlcwoJCWlmICggIXN1cHBvcnQubm9DbG9uZUNoZWNrZWQgJiYgKCBlbGVtLm5vZGVUeXBlID09PSAxIHx8IGVsZW0ubm9kZVR5cGUgPT09IDExICkgJiYKCQkJCSFqUXVlcnkuaXNYTUxEb2MoIGVsZW0gKSApIHsKCgkJCS8vIFdlIGVzY2hldyBTaXp6bGUgaGVyZSBmb3IgcGVyZm9ybWFuY2UgcmVhc29uczogaHR0cDovL2pzcGVyZi5jb20vZ2V0YWxsLXZzLXNpenpsZS8yCgkJCWRlc3RFbGVtZW50cyA9IGdldEFsbCggY2xvbmUgKTsKCQkJc3JjRWxlbWVudHMgPSBnZXRBbGwoIGVsZW0gKTsKCgkJCWZvciAoIGkgPSAwLCBsID0gc3JjRWxlbWVudHMubGVuZ3RoOyBpIDwgbDsgaSsrICkgewoJCQkJZml4SW5wdXQoIHNyY0VsZW1lbnRzWyBpIF0sIGRlc3RFbGVtZW50c1sgaSBdICk7CgkJCX0KCQl9CgoJCS8vIENvcHkgdGhlIGV2ZW50cyBmcm9tIHRoZSBvcmlnaW5hbCB0byB0aGUgY2xvbmUKCQlpZiAoIGRhdGFBbmRFdmVudHMgKSB7CgkJCWlmICggZGVlcERhdGFBbmRFdmVudHMgKSB7CgkJCQlzcmNFbGVtZW50cyA9IHNyY0VsZW1lbnRzIHx8IGdldEFsbCggZWxlbSApOwoJCQkJZGVzdEVsZW1lbnRzID0gZGVzdEVsZW1lbnRzIHx8IGdldEFsbCggY2xvbmUgKTsKCgkJCQlmb3IgKCBpID0gMCwgbCA9IHNyY0VsZW1lbnRzLmxlbmd0aDsgaSA8IGw7IGkrKyApIHsKCQkJCQljbG9uZUNvcHlFdmVudCggc3JjRWxlbWVudHNbIGkgXSwgZGVzdEVsZW1lbnRzWyBpIF0gKTsKCQkJCX0KCQkJfSBlbHNlIHsKCQkJCWNsb25lQ29weUV2ZW50KCBlbGVtLCBjbG9uZSApOwoJCQl9CgkJfQoKCQkvLyBQcmVzZXJ2ZSBzY3JpcHQgZXZhbHVhdGlvbiBoaXN0b3J5CgkJZGVzdEVsZW1lbnRzID0gZ2V0QWxsKCBjbG9uZSwgInNjcmlwdCIgKTsKCQlpZiAoIGRlc3RFbGVtZW50cy5sZW5ndGggPiAwICkgewoJCQlzZXRHbG9iYWxFdmFsKCBkZXN0RWxlbWVudHMsICFpblBhZ2UgJiYgZ2V0QWxsKCBlbGVtLCAic2NyaXB0IiApICk7CgkJfQoKCQkvLyBSZXR1cm4gdGhlIGNsb25lZCBzZXQKCQlyZXR1cm4gY2xvbmU7Cgl9LAoKCWJ1aWxkRnJhZ21lbnQ6IGZ1bmN0aW9uKCBlbGVtcywgY29udGV4dCwgc2NyaXB0cywgc2VsZWN0aW9uICkgewoJCXZhciBlbGVtLCB0bXAsIHRhZywgd3JhcCwgY29udGFpbnMsIGosCgkJCWZyYWdtZW50ID0gY29udGV4dC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksCgkJCW5vZGVzID0gW10sCgkJCWkgPSAwLAoJCQlsID0gZWxlbXMubGVuZ3RoOwoKCQlmb3IgKCA7IGkgPCBsOyBpKysgKSB7CgkJCWVsZW0gPSBlbGVtc1sgaSBdOwoKCQkJaWYgKCBlbGVtIHx8IGVsZW0gPT09IDAgKSB7CgoJCQkJLy8gQWRkIG5vZGVzIGRpcmVjdGx5CgkJCQlpZiAoIGpRdWVyeS50eXBlKCBlbGVtICkgPT09ICJvYmplY3QiICkgewoJCQkJCS8vIFN1cHBvcnQ6IFF0V2ViS2l0CgkJCQkJLy8galF1ZXJ5Lm1lcmdlIGJlY2F1c2UgcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cwoJCQkJCWpRdWVyeS5tZXJnZSggbm9kZXMsIGVsZW0ubm9kZVR5cGUgPyBbIGVsZW0gXSA6IGVsZW0gKTsKCgkJCQkvLyBDb252ZXJ0IG5vbi1odG1sIGludG8gYSB0ZXh0IG5vZGUKCQkJCX0gZWxzZSBpZiAoICFyaHRtbC50ZXN0KCBlbGVtICkgKSB7CgkJCQkJbm9kZXMucHVzaCggY29udGV4dC5jcmVhdGVUZXh0Tm9kZSggZWxlbSApICk7CgoJCQkJLy8gQ29udmVydCBodG1sIGludG8gRE9NIG5vZGVzCgkJCQl9IGVsc2UgewoJCQkJCXRtcCA9IHRtcCB8fCBmcmFnbWVudC5hcHBlbmRDaGlsZCggY29udGV4dC5jcmVhdGVFbGVtZW50KCJkaXYiKSApOwoKCQkJCQkvLyBEZXNlcmlhbGl6ZSBhIHN0YW5kYXJkIHJlcHJlc2VudGF0aW9uCgkJCQkJdGFnID0gKCBydGFnTmFtZS5leGVjKCBlbGVtICkgfHwgWyAiIiwgIiIgXSApWyAxIF0udG9Mb3dlckNhc2UoKTsKCQkJCQl3cmFwID0gd3JhcE1hcFsgdGFnIF0gfHwgd3JhcE1hcC5fZGVmYXVsdDsKCQkJCQl0bXAuaW5uZXJIVE1MID0gd3JhcFsgMSBdICsgZWxlbS5yZXBsYWNlKCByeGh0bWxUYWcsICI8JDE+PC8kMj4iICkgKyB3cmFwWyAyIF07CgoJCQkJCS8vIERlc2NlbmQgdGhyb3VnaCB3cmFwcGVycyB0byB0aGUgcmlnaHQgY29udGVudAoJCQkJCWogPSB3cmFwWyAwIF07CgkJCQkJd2hpbGUgKCBqLS0gKSB7CgkJCQkJCXRtcCA9IHRtcC5sYXN0Q2hpbGQ7CgkJCQkJfQoKCQkJCQkvLyBTdXBwb3J0OiBRdFdlYktpdAoJCQkJCS8vIGpRdWVyeS5tZXJnZSBiZWNhdXNlIHB1c2guYXBwbHkoXywgYXJyYXlsaWtlKSB0aHJvd3MKCQkJCQlqUXVlcnkubWVyZ2UoIG5vZGVzLCB0bXAuY2hpbGROb2RlcyApOwoKCQkJCQkvLyBSZW1lbWJlciB0aGUgdG9wLWxldmVsIGNvbnRhaW5lcgoJCQkJCXRtcCA9IGZyYWdtZW50LmZpcnN0Q2hpbGQ7CgoJCQkJCS8vIEZpeGVzICMxMjM0NgoJCQkJCS8vIFN1cHBvcnQ6IFdlYmtpdCwgSUUKCQkJCQl0bXAudGV4dENvbnRlbnQgPSAiIjsKCQkJCX0KCQkJfQoJCX0KCgkJLy8gUmVtb3ZlIHdyYXBwZXIgZnJvbSBmcmFnbWVudAoJCWZyYWdtZW50LnRleHRDb250ZW50ID0gIiI7CgoJCWkgPSAwOwoJCXdoaWxlICggKGVsZW0gPSBub2Rlc1sgaSsrIF0pICkgewoKCQkJLy8gIzQwODcgLSBJZiBvcmlnaW4gYW5kIGRlc3RpbmF0aW9uIGVsZW1lbnRzIGFyZSB0aGUgc2FtZSwgYW5kIHRoaXMgaXMKCQkJLy8gdGhhdCBlbGVtZW50LCBkbyBub3QgZG8gYW55dGhpbmcKCQkJaWYgKCBzZWxlY3Rpb24gJiYgalF1ZXJ5LmluQXJyYXkoIGVsZW0sIHNlbGVjdGlvbiApICE9PSAtMSApIHsKCQkJCWNvbnRpbnVlOwoJCQl9CgoJCQljb250YWlucyA9IGpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICk7CgoJCQkvLyBBcHBlbmQgdG8gZnJhZ21lbnQKCQkJdG1wID0gZ2V0QWxsKCBmcmFnbWVudC5hcHBlbmRDaGlsZCggZWxlbSApLCAic2NyaXB0IiApOwoKCQkJLy8gUHJlc2VydmUgc2NyaXB0IGV2YWx1YXRpb24gaGlzdG9yeQoJCQlpZiAoIGNvbnRhaW5zICkgewoJCQkJc2V0R2xvYmFsRXZhbCggdG1wICk7CgkJCX0KCgkJCS8vIENhcHR1cmUgZXhlY3V0YWJsZXMKCQkJaWYgKCBzY3JpcHRzICkgewoJCQkJaiA9IDA7CgkJCQl3aGlsZSAoIChlbGVtID0gdG1wWyBqKysgXSkgKSB7CgkJCQkJaWYgKCByc2NyaXB0VHlwZS50ZXN0KCBlbGVtLnR5cGUgfHwgIiIgKSApIHsKCQkJCQkJc2NyaXB0cy5wdXNoKCBlbGVtICk7CgkJCQkJfQoJCQkJfQoJCQl9CgkJfQoKCQlyZXR1cm4gZnJhZ21lbnQ7Cgl9LAoKCWNsZWFuRGF0YTogZnVuY3Rpb24oIGVsZW1zICkgewoJCXZhciBkYXRhLCBlbGVtLCB0eXBlLCBrZXksCgkJCXNwZWNpYWwgPSBqUXVlcnkuZXZlbnQuc3BlY2lhbCwKCQkJaSA9IDA7CgoJCWZvciAoIDsgKGVsZW0gPSBlbGVtc1sgaSBdKSAhPT0gdW5kZWZpbmVkOyBpKysgKSB7CgkJCWlmICggalF1ZXJ5LmFjY2VwdERhdGEoIGVsZW0gKSApIHsKCQkJCWtleSA9IGVsZW1bIGRhdGFfcHJpdi5leHBhbmRvIF07CgoJCQkJaWYgKCBrZXkgJiYgKGRhdGEgPSBkYXRhX3ByaXYuY2FjaGVbIGtleSBdKSApIHsKCQkJCQlpZiAoIGRhdGEuZXZlbnRzICkgewoJCQkJCQlmb3IgKCB0eXBlIGluIGRhdGEuZXZlbnRzICkgewoJCQkJCQkJaWYgKCBzcGVjaWFsWyB0eXBlIF0gKSB7CgkJCQkJCQkJalF1ZXJ5LmV2ZW50LnJlbW92ZSggZWxlbSwgdHlwZSApOwoKCQkJCQkJCS8vIFRoaXMgaXMgYSBzaG9ydGN1dCB0byBhdm9pZCBqUXVlcnkuZXZlbnQucmVtb3ZlJ3Mgb3ZlcmhlYWQKCQkJCQkJCX0gZWxzZSB7CgkJCQkJCQkJalF1ZXJ5LnJlbW92ZUV2ZW50KCBlbGVtLCB0eXBlLCBkYXRhLmhhbmRsZSApOwoJCQkJCQkJfQoJCQkJCQl9CgkJCQkJfQoJCQkJCWlmICggZGF0YV9wcml2LmNhY2hlWyBrZXkgXSApIHsKCQkJCQkJLy8gRGlzY2FyZCBhbnkgcmVtYWluaW5nIGBwcml2YXRlYCBkYXRhCgkJCQkJCWRlbGV0ZSBkYXRhX3ByaXYuY2FjaGVbIGtleSBdOwoJCQkJCX0KCQkJCX0KCQkJfQoJCQkvLyBEaXNjYXJkIGFueSByZW1haW5pbmcgYHVzZXJgIGRhdGEKCQkJZGVsZXRlIGRhdGFfdXNlci5jYWNoZVsgZWxlbVsgZGF0YV91c2VyLmV4cGFuZG8gXSBdOwoJCX0KCX0KfSk7CgpqUXVlcnkuZm4uZXh0ZW5kKHsKCXRleHQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHsKCQlyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggdmFsdWUgKSB7CgkJCXJldHVybiB2YWx1ZSA9PT0gdW5kZWZpbmVkID8KCQkJCWpRdWVyeS50ZXh0KCB0aGlzICkgOgoJCQkJdGhpcy5lbXB0eSgpLmVhY2goZnVuY3Rpb24oKSB7CgkJCQkJaWYgKCB0aGlzLm5vZGVUeXBlID09PSAxIHx8IHRoaXMubm9kZVR5cGUgPT09IDExIHx8IHRoaXMubm9kZVR5cGUgPT09IDkgKSB7CgkJCQkJCXRoaXMudGV4dENvbnRlbnQgPSB2YWx1ZTsKCQkJCQl9CgkJCQl9KTsKCQl9LCBudWxsLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCApOwoJfSwKCglhcHBlbmQ6IGZ1bmN0aW9uKCkgewoJCXJldHVybiB0aGlzLmRvbU1hbmlwKCBhcmd1bWVudHMsIGZ1bmN0aW9uKCBlbGVtICkgewoJCQlpZiAoIHRoaXMubm9kZVR5cGUgPT09IDEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gMTEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gOSApIHsKCQkJCXZhciB0YXJnZXQgPSBtYW5pcHVsYXRpb25UYXJnZXQoIHRoaXMsIGVsZW0gKTsKCQkJCXRhcmdldC5hcHBlbmRDaGlsZCggZWxlbSApOwoJCQl9CgkJfSk7Cgl9LAoKCXByZXBlbmQ6IGZ1bmN0aW9uKCkgewoJCXJldHVybiB0aGlzLmRvbU1hbmlwKCBhcmd1bWVudHMsIGZ1bmN0aW9uKCBlbGVtICkgewoJCQlpZiAoIHRoaXMubm9kZVR5cGUgPT09IDEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gMTEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gOSApIHsKCQkJCXZhciB0YXJnZXQgPSBtYW5pcHVsYXRpb25UYXJnZXQoIHRoaXMsIGVsZW0gKTsKCQkJCXRhcmdldC5pbnNlcnRCZWZvcmUoIGVsZW0sIHRhcmdldC5maXJzdENoaWxkICk7CgkJCX0KCQl9KTsKCX0sCgoJYmVmb3JlOiBmdW5jdGlvbigpIHsKCQlyZXR1cm4gdGhpcy5kb21NYW5pcCggYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHsKCQkJaWYgKCB0aGlzLnBhcmVudE5vZGUgKSB7CgkJCQl0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKCBlbGVtLCB0aGlzICk7CgkJCX0KCQl9KTsKCX0sCgoJYWZ0ZXI6IGZ1bmN0aW9uKCkgewoJCXJldHVybiB0aGlzLmRvbU1hbmlwKCBhcmd1bWVudHMsIGZ1bmN0aW9uKCBlbGVtICkgewoJCQlpZiAoIHRoaXMucGFyZW50Tm9kZSApIHsKCQkJCXRoaXMucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoIGVsZW0sIHRoaXMubmV4dFNpYmxpbmcgKTsKCQkJfQoJCX0pOwoJfSwKCglyZW1vdmU6IGZ1bmN0aW9uKCBzZWxlY3Rvciwga2VlcERhdGEgLyogSW50ZXJuYWwgVXNlIE9ubHkgKi8gKSB7CgkJdmFyIGVsZW0sCgkJCWVsZW1zID0gc2VsZWN0b3IgPyBqUXVlcnkuZmlsdGVyKCBzZWxlY3RvciwgdGhpcyApIDogdGhpcywKCQkJaSA9IDA7CgoJCWZvciAoIDsgKGVsZW0gPSBlbGVtc1tpXSkgIT0gbnVsbDsgaSsrICkgewoJCQlpZiAoICFrZWVwRGF0YSAmJiBlbGVtLm5vZGVUeXBlID09PSAxICkgewoJCQkJalF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCBlbGVtICkgKTsKCQkJfQoKCQkJaWYgKCBlbGVtLnBhcmVudE5vZGUgKSB7CgkJCQlpZiAoIGtlZXBEYXRhICYmIGpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICkgKSB7CgkJCQkJc2V0R2xvYmFsRXZhbCggZ2V0QWxsKCBlbGVtLCAic2NyaXB0IiApICk7CgkJCQl9CgkJCQllbGVtLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIGVsZW0gKTsKCQkJfQoJCX0KCgkJcmV0dXJuIHRoaXM7Cgl9LAoKCWVtcHR5OiBmdW5jdGlvbigpIHsKCQl2YXIgZWxlbSwKCQkJaSA9IDA7CgoJCWZvciAoIDsgKGVsZW0gPSB0aGlzW2ldKSAhPSBudWxsOyBpKysgKSB7CgkJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHsKCgkJCQkvLyBQcmV2ZW50IG1lbW9yeSBsZWFrcwoJCQkJalF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCBlbGVtLCBmYWxzZSApICk7CgoJCQkJLy8gUmVtb3ZlIGFueSByZW1haW5pbmcgbm9kZXMKCQkJCWVsZW0udGV4dENvbnRlbnQgPSAiIjsKCQkJfQoJCX0KCgkJcmV0dXJuIHRoaXM7Cgl9LAoKCWNsb25lOiBmdW5jdGlvbiggZGF0YUFuZEV2ZW50cywgZGVlcERhdGFBbmRFdmVudHMgKSB7CgkJZGF0YUFuZEV2ZW50cyA9IGRhdGFBbmRFdmVudHMgPT0gbnVsbCA/IGZhbHNlIDogZGF0YUFuZEV2ZW50czsKCQlkZWVwRGF0YUFuZEV2ZW50cyA9IGRlZXBEYXRhQW5kRXZlbnRzID09IG51bGwgPyBkYXRhQW5kRXZlbnRzIDogZGVlcERhdGFBbmRFdmVudHM7CgoJCXJldHVybiB0aGlzLm1hcChmdW5jdGlvbigpIHsKCQkJcmV0dXJuIGpRdWVyeS5jbG9uZSggdGhpcywgZGF0YUFuZEV2ZW50cywgZGVlcERhdGFBbmRFdmVudHMgKTsKCQl9KTsKCX0sCgoJaHRtbDogZnVuY3Rpb24oIHZhbHVlICkgewoJCXJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCB2YWx1ZSApIHsKCQkJdmFyIGVsZW0gPSB0aGlzWyAwIF0gfHwge30sCgkJCQlpID0gMCwKCQkJCWwgPSB0aGlzLmxlbmd0aDsKCgkJCWlmICggdmFsdWUgPT09IHVuZGVmaW5lZCAmJiBlbGVtLm5vZGVUeXBlID09PSAxICkgewoJCQkJcmV0dXJuIGVsZW0uaW5uZXJIVE1MOwoJCQl9CgoJCQkvLyBTZWUgaWYgd2UgY2FuIHRha2UgYSBzaG9ydGN1dCBhbmQganVzdCB1c2UgaW5uZXJIVE1MCgkJCWlmICggdHlwZW9mIHZhbHVlID09PSAic3RyaW5nIiAmJiAhcm5vSW5uZXJodG1sLnRlc3QoIHZhbHVlICkgJiYKCQkJCSF3cmFwTWFwWyAoIHJ0YWdOYW1lLmV4ZWMoIHZhbHVlICkgfHwgWyAiIiwgIiIgXSApWyAxIF0udG9Mb3dlckNhc2UoKSBdICkgewoKCQkJCXZhbHVlID0gdmFsdWUucmVwbGFjZSggcnhodG1sVGFnLCAiPCQxPjwvJDI+IiApOwoKCQkJCXRyeSB7CgkJCQkJZm9yICggOyBpIDwgbDsgaSsrICkgewoJCQkJCQllbGVtID0gdGhpc1sgaSBdIHx8IHt9OwoKCQkJCQkJLy8gUmVtb3ZlIGVsZW1lbnQgbm9kZXMgYW5kIHByZXZlbnQgbWVtb3J5IGxlYWtzCgkJCQkJCWlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHsKCQkJCQkJCWpRdWVyeS5jbGVhbkRhdGEoIGdldEFsbCggZWxlbSwgZmFsc2UgKSApOwoJCQkJCQkJZWxlbS5pbm5lckhUTUwgPSB2YWx1ZTsKCQkJCQkJfQoJCQkJCX0KCgkJCQkJZWxlbSA9IDA7CgoJCQkJLy8gSWYgdXNpbmcgaW5uZXJIVE1MIHRocm93cyBhbiBleGNlcHRpb24sIHVzZSB0aGUgZmFsbGJhY2sgbWV0aG9kCgkJCQl9IGNhdGNoKCBlICkge30KCQkJfQoKCQkJaWYgKCBlbGVtICkgewoJCQkJdGhpcy5lbXB0eSgpLmFwcGVuZCggdmFsdWUgKTsKCQkJfQoJCX0sIG51bGwsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoICk7Cgl9LAoKCXJlcGxhY2VXaXRoOiBmdW5jdGlvbigpIHsKCQl2YXIgYXJnID0gYXJndW1lbnRzWyAwIF07CgoJCS8vIE1ha2UgdGhlIGNoYW5nZXMsIHJlcGxhY2luZyBlYWNoIGNvbnRleHQgZWxlbWVudCB3aXRoIHRoZSBuZXcgY29udGVudAoJCXRoaXMuZG9tTWFuaXAoIGFyZ3VtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7CgkJCWFyZyA9IHRoaXMucGFyZW50Tm9kZTsKCgkJCWpRdWVyeS5jbGVhbkRhdGEoIGdldEFsbCggdGhpcyApICk7CgoJCQlpZiAoIGFyZyApIHsKCQkJCWFyZy5yZXBsYWNlQ2hpbGQoIGVsZW0sIHRoaXMgKTsKCQkJfQoJCX0pOwoKCQkvLyBGb3JjZSByZW1vdmFsIGlmIHRoZXJlIHdhcyBubyBuZXcgY29udGVudCAoZS5nLiwgZnJvbSBlbXB0eSBhcmd1bWVudHMpCgkJcmV0dXJuIGFyZyAmJiAoYXJnLmxlbmd0aCB8fCBhcmcubm9kZVR5cGUpID8gdGhpcyA6IHRoaXMucmVtb3ZlKCk7Cgl9LAoKCWRldGFjaDogZnVuY3Rpb24oIHNlbGVjdG9yICkgewoJCXJldHVybiB0aGlzLnJlbW92ZSggc2VsZWN0b3IsIHRydWUgKTsKCX0sCgoJZG9tTWFuaXA6IGZ1bmN0aW9uKCBhcmdzLCBjYWxsYmFjayApIHsKCgkJLy8gRmxhdHRlbiBhbnkgbmVzdGVkIGFycmF5cwoJCWFyZ3MgPSBjb25jYXQuYXBwbHkoIFtdLCBhcmdzICk7CgoJCXZhciBmcmFnbWVudCwgZmlyc3QsIHNjcmlwdHMsIGhhc1NjcmlwdHMsIG5vZGUsIGRvYywKCQkJaSA9IDAsCgkJCWwgPSB0aGlzLmxlbmd0aCwKCQkJc2V0ID0gdGhpcywKCQkJaU5vQ2xvbmUgPSBsIC0gMSwKCQkJdmFsdWUgPSBhcmdzWyAwIF0sCgkJCWlzRnVuY3Rpb24gPSBqUXVlcnkuaXNGdW5jdGlvbiggdmFsdWUgKTsKCgkJLy8gV2UgY2FuJ3QgY2xvbmVOb2RlIGZyYWdtZW50cyB0aGF0IGNvbnRhaW4gY2hlY2tlZCwgaW4gV2ViS2l0CgkJaWYgKCBpc0Z1bmN0aW9uIHx8CgkJCQkoIGwgPiAxICYmIHR5cGVvZiB2YWx1ZSA9PT0gInN0cmluZyIgJiYKCQkJCQkhc3VwcG9ydC5jaGVja0Nsb25lICYmIHJjaGVja2VkLnRlc3QoIHZhbHVlICkgKSApIHsKCQkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiggaW5kZXggKSB7CgkJCQl2YXIgc2VsZiA9IHNldC5lcSggaW5kZXggKTsKCQkJCWlmICggaXNGdW5jdGlvbiApIHsKCQkJCQlhcmdzWyAwIF0gPSB2YWx1ZS5jYWxsKCB0aGlzLCBpbmRleCwgc2VsZi5odG1sKCkgKTsKCQkJCX0KCQkJCXNlbGYuZG9tTWFuaXAoIGFyZ3MsIGNhbGxiYWNrICk7CgkJCX0pOwoJCX0KCgkJaWYgKCBsICkgewoJCQlmcmFnbWVudCA9IGpRdWVyeS5idWlsZEZyYWdtZW50KCBhcmdzLCB0aGlzWyAwIF0ub3duZXJEb2N1bWVudCwgZmFsc2UsIHRoaXMgKTsKCQkJZmlyc3QgPSBmcmFnbWVudC5maXJzdENoaWxkOwoKCQkJaWYgKCBmcmFnbWVudC5jaGlsZE5vZGVzLmxlbmd0aCA9PT0gMSApIHsKCQkJCWZyYWdtZW50ID0gZmlyc3Q7CgkJCX0KCgkJCWlmICggZmlyc3QgKSB7CgkJCQlzY3JpcHRzID0galF1ZXJ5Lm1hcCggZ2V0QWxsKCBmcmFnbWVudCwgInNjcmlwdCIgKSwgZGlzYWJsZVNjcmlwdCApOwoJCQkJaGFzU2NyaXB0cyA9IHNjcmlwdHMubGVuZ3RoOwoKCQkJCS8vIFVzZSB0aGUgb3JpZ2luYWwgZnJhZ21lbnQgZm9yIHRoZSBsYXN0IGl0ZW0gaW5zdGVhZCBvZiB0aGUgZmlyc3QgYmVjYXVzZSBpdCBjYW4gZW5kIHVwCgkJCQkvLyBiZWluZyBlbXB0aWVkIGluY29ycmVjdGx5IGluIGNlcnRhaW4gc2l0dWF0aW9ucyAoIzgwNzApLgoJCQkJZm9yICggOyBpIDwgbDsgaSsrICkgewoJCQkJCW5vZGUgPSBmcmFnbWVudDsKCgkJCQkJaWYgKCBpICE9PSBpTm9DbG9uZSApIHsKCQkJCQkJbm9kZSA9IGpRdWVyeS5jbG9uZSggbm9kZSwgdHJ1ZSwgdHJ1ZSApOwoKCQkJCQkJLy8gS2VlcCByZWZlcmVuY2VzIHRvIGNsb25lZCBzY3JpcHRzIGZvciBsYXRlciByZXN0b3JhdGlvbgoJCQkJCQlpZiAoIGhhc1NjcmlwdHMgKSB7CgkJCQkJCQkvLyBTdXBwb3J0OiBRdFdlYktpdAoJCQkJCQkJLy8galF1ZXJ5Lm1lcmdlIGJlY2F1c2UgcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cwoJCQkJCQkJalF1ZXJ5Lm1lcmdlKCBzY3JpcHRzLCBnZXRBbGwoIG5vZGUsICJzY3JpcHQiICkgKTsKCQkJCQkJfQoJCQkJCX0KCgkJCQkJY2FsbGJhY2suY2FsbCggdGhpc1sgaSBdLCBub2RlLCBpICk7CgkJCQl9CgoJCQkJaWYgKCBoYXNTY3JpcHRzICkgewoJCQkJCWRvYyA9IHNjcmlwdHNbIHNjcmlwdHMubGVuZ3RoIC0gMSBdLm93bmVyRG9jdW1lbnQ7CgoJCQkJCS8vIFJlZW5hYmxlIHNjcmlwdHMKCQkJCQlqUXVlcnkubWFwKCBzY3JpcHRzLCByZXN0b3JlU2NyaXB0ICk7CgoJCQkJCS8vIEV2YWx1YXRlIGV4ZWN1dGFibGUgc2NyaXB0cyBvbiBmaXJzdCBkb2N1bWVudCBpbnNlcnRpb24KCQkJCQlmb3IgKCBpID0gMDsgaSA8IGhhc1NjcmlwdHM7IGkrKyApIHsKCQkJCQkJbm9kZSA9IHNjcmlwdHNbIGkgXTsKCQkJCQkJaWYgKCByc2NyaXB0VHlwZS50ZXN0KCBub2RlLnR5cGUgfHwgIiIgKSAmJgoJCQkJCQkJIWRhdGFfcHJpdi5hY2Nlc3MoIG5vZGUsICJnbG9iYWxFdmFsIiApICYmIGpRdWVyeS5jb250YWlucyggZG9jLCBub2RlICkgKSB7CgoJCQkJCQkJaWYgKCBub2RlLnNyYyApIHsKCQkJCQkJCQkvLyBPcHRpb25hbCBBSkFYIGRlcGVuZGVuY3ksIGJ1dCB3b24ndCBydW4gc2NyaXB0cyBpZiBub3QgcHJlc2VudAoJCQkJCQkJCWlmICggalF1ZXJ5Ll9ldmFsVXJsICkgewoJCQkJCQkJCQlqUXVlcnkuX2V2YWxVcmwoIG5vZGUuc3JjICk7CgkJCQkJCQkJfQoJCQkJCQkJfSBlbHNlIHsKCQkJCQkJCQlqUXVlcnkuZ2xvYmFsRXZhbCggbm9kZS50ZXh0Q29udGVudC5yZXBsYWNlKCByY2xlYW5TY3JpcHQsICIiICkgKTsKCQkJCQkJCX0KCQkJCQkJfQoJCQkJCX0KCQkJCX0KCQkJfQoJCX0KCgkJcmV0dXJuIHRoaXM7Cgl9Cn0pOwoKalF1ZXJ5LmVhY2goewoJYXBwZW5kVG86ICJhcHBlbmQiLAoJcHJlcGVuZFRvOiAicHJlcGVuZCIsCglpbnNlcnRCZWZvcmU6ICJiZWZvcmUiLAoJaW5zZXJ0QWZ0ZXI6ICJhZnRlciIsCglyZXBsYWNlQWxsOiAicmVwbGFjZVdpdGgiCn0sIGZ1bmN0aW9uKCBuYW1lLCBvcmlnaW5hbCApIHsKCWpRdWVyeS5mblsgbmFtZSBdID0gZnVuY3Rpb24oIHNlbGVjdG9yICkgewoJCXZhciBlbGVtcywKCQkJcmV0ID0gW10sCgkJCWluc2VydCA9IGpRdWVyeSggc2VsZWN0b3IgKSwKCQkJbGFzdCA9IGluc2VydC5sZW5ndGggLSAxLAoJCQlpID0gMDsKCgkJZm9yICggOyBpIDw9IGxhc3Q7IGkrKyApIHsKCQkJZWxlbXMgPSBpID09PSBsYXN0ID8gdGhpcyA6IHRoaXMuY2xvbmUoIHRydWUgKTsKCQkJalF1ZXJ5KCBpbnNlcnRbIGkgXSApWyBvcmlnaW5hbCBdKCBlbGVtcyApOwoKCQkJLy8gU3VwcG9ydDogUXRXZWJLaXQKCQkJLy8gLmdldCgpIGJlY2F1c2UgcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cwoJCQlwdXNoLmFwcGx5KCByZXQsIGVsZW1zLmdldCgpICk7CgkJfQoKCQlyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHJldCApOwoJfTsKfSk7CgoKdmFyIGlmcmFtZSwKCWVsZW1kaXNwbGF5ID0ge307CgovKioKICogUmV0cmlldmUgdGhlIGFjdHVhbCBkaXNwbGF5IG9mIGEgZWxlbWVudAogKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBub2RlTmFtZSBvZiB0aGUgZWxlbWVudAogKiBAcGFyYW0ge09iamVjdH0gZG9jIERvY3VtZW50IG9iamVjdAogKi8KLy8gQ2FsbGVkIG9ubHkgZnJvbSB3aXRoaW4gZGVmYXVsdERpc3BsYXkKZnVuY3Rpb24gYWN0dWFsRGlzcGxheSggbmFtZSwgZG9jICkgewoJdmFyIHN0eWxlLAoJCWVsZW0gPSBqUXVlcnkoIGRvYy5jcmVhdGVFbGVtZW50KCBuYW1lICkgKS5hcHBlbmRUbyggZG9jLmJvZHkgKSwKCgkJLy8gZ2V0RGVmYXVsdENvbXB1dGVkU3R5bGUgbWlnaHQgYmUgcmVsaWFibHkgdXNlZCBvbmx5IG9uIGF0dGFjaGVkIGVsZW1lbnQKCQlkaXNwbGF5ID0gd2luZG93LmdldERlZmF1bHRDb21wdXRlZFN0eWxlICYmICggc3R5bGUgPSB3aW5kb3cuZ2V0RGVmYXVsdENvbXB1dGVkU3R5bGUoIGVsZW1bIDAgXSApICkgPwoKCQkJLy8gVXNlIG9mIHRoaXMgbWV0aG9kIGlzIGEgdGVtcG9yYXJ5IGZpeCAobW9yZSBsaWtlIG9wdG1pemF0aW9uKSB1bnRpbCBzb21ldGhpbmcgYmV0dGVyIGNvbWVzIGFsb25nLAoJCQkvLyBzaW5jZSBpdCB3YXMgcmVtb3ZlZCBmcm9tIHNwZWNpZmljYXRpb24gYW5kIHN1cHBvcnRlZCBvbmx5IGluIEZGCgkJCXN0eWxlLmRpc3BsYXkgOiBqUXVlcnkuY3NzKCBlbGVtWyAwIF0sICJkaXNwbGF5IiApOwoKCS8vIFdlIGRvbid0IGhhdmUgYW55IGRhdGEgc3RvcmVkIG9uIHRoZSBlbGVtZW50LAoJLy8gc28gdXNlICJkZXRhY2giIG1ldGhvZCBhcyBmYXN0IHdheSB0byBnZXQgcmlkIG9mIHRoZSBlbGVtZW50CgllbGVtLmRldGFjaCgpOwoKCXJldHVybiBkaXNwbGF5Owp9CgovKioKICogVHJ5IHRvIGRldGVybWluZSB0aGUgZGVmYXVsdCBkaXNwbGF5IHZhbHVlIG9mIGFuIGVsZW1lbnQKICogQHBhcmFtIHtTdHJpbmd9IG5vZGVOYW1lCiAqLwpmdW5jdGlvbiBkZWZhdWx0RGlzcGxheSggbm9kZU5hbWUgKSB7Cgl2YXIgZG9jID0gZG9jdW1lbnQsCgkJZGlzcGxheSA9IGVsZW1kaXNwbGF5WyBub2RlTmFtZSBdOwoKCWlmICggIWRpc3BsYXkgKSB7CgkJZGlzcGxheSA9IGFjdHVhbERpc3BsYXkoIG5vZGVOYW1lLCBkb2MgKTsKCgkJLy8gSWYgdGhlIHNpbXBsZSB3YXkgZmFpbHMsIHJlYWQgZnJvbSBpbnNpZGUgYW4gaWZyYW1lCgkJaWYgKCBkaXNwbGF5ID09PSAibm9uZSIgfHwgIWRpc3BsYXkgKSB7CgoJCQkvLyBVc2UgdGhlIGFscmVhZHktY3JlYXRlZCBpZnJhbWUgaWYgcG9zc2libGUKCQkJaWZyYW1lID0gKGlmcmFtZSB8fCBqUXVlcnkoICI8aWZyYW1lIGZyYW1lYm9yZGVyPScwJyB3aWR0aD0nMCcgaGVpZ2h0PScwJy8+IiApKS5hcHBlbmRUbyggZG9jLmRvY3VtZW50RWxlbWVudCApOwoKCQkJLy8gQWx3YXlzIHdyaXRlIGEgbmV3IEhUTUwgc2tlbGV0b24gc28gV2Via2l0IGFuZCBGaXJlZm94IGRvbid0IGNob2tlIG9uIHJldXNlCgkJCWRvYyA9IGlmcmFtZVsgMCBdLmNvbnRlbnREb2N1bWVudDsKCgkJCS8vIFN1cHBvcnQ6IElFCgkJCWRvYy53cml0ZSgpOwoJCQlkb2MuY2xvc2UoKTsKCgkJCWRpc3BsYXkgPSBhY3R1YWxEaXNwbGF5KCBub2RlTmFtZSwgZG9jICk7CgkJCWlmcmFtZS5kZXRhY2goKTsKCQl9CgoJCS8vIFN0b3JlIHRoZSBjb3JyZWN0IGRlZmF1bHQgZGlzcGxheQoJCWVsZW1kaXNwbGF5WyBub2RlTmFtZSBdID0gZGlzcGxheTsKCX0KCglyZXR1cm4gZGlzcGxheTsKfQp2YXIgcm1hcmdpbiA9ICgvXm1hcmdpbi8pOwoKdmFyIHJudW1ub25weCA9IG5ldyBSZWdFeHAoICJeKCIgKyBwbnVtICsgIikoPyFweClbYS16JV0rJCIsICJpIiApOwoKdmFyIGdldFN0eWxlcyA9IGZ1bmN0aW9uKCBlbGVtICkgewoJCXJldHVybiBlbGVtLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcuZ2V0Q29tcHV0ZWRTdHlsZSggZWxlbSwgbnVsbCApOwoJfTsKCgoKZnVuY3Rpb24gY3VyQ1NTKCBlbGVtLCBuYW1lLCBjb21wdXRlZCApIHsKCXZhciB3aWR0aCwgbWluV2lkdGgsIG1heFdpZHRoLCByZXQsCgkJc3R5bGUgPSBlbGVtLnN0eWxlOwoKCWNvbXB1dGVkID0gY29tcHV0ZWQgfHwgZ2V0U3R5bGVzKCBlbGVtICk7CgoJLy8gU3VwcG9ydDogSUU5CgkvLyBnZXRQcm9wZXJ0eVZhbHVlIGlzIG9ubHkgbmVlZGVkIGZvciAuY3NzKCdmaWx0ZXInKSBpbiBJRTksIHNlZSAjMTI1MzcKCWlmICggY29tcHV0ZWQgKSB7CgkJcmV0ID0gY29tcHV0ZWQuZ2V0UHJvcGVydHlWYWx1ZSggbmFtZSApIHx8IGNvbXB1dGVkWyBuYW1lIF07Cgl9CgoJaWYgKCBjb21wdXRlZCApIHsKCgkJaWYgKCByZXQgPT09ICIiICYmICFqUXVlcnkuY29udGFpbnMoIGVsZW0ub3duZXJEb2N1bWVudCwgZWxlbSApICkgewoJCQlyZXQgPSBqUXVlcnkuc3R5bGUoIGVsZW0sIG5hbWUgKTsKCQl9CgoJCS8vIFN1cHBvcnQ6IGlPUyA8IDYKCQkvLyBBIHRyaWJ1dGUgdG8gdGhlICJhd2Vzb21lIGhhY2sgYnkgRGVhbiBFZHdhcmRzIgoJCS8vIGlPUyA8IDYgKGF0IGxlYXN0KSByZXR1cm5zIHBlcmNlbnRhZ2UgZm9yIGEgbGFyZ2VyIHNldCBvZiB2YWx1ZXMsIGJ1dCB3aWR0aCBzZWVtcyB0byBiZSByZWxpYWJseSBwaXhlbHMKCQkvLyB0aGlzIGlzIGFnYWluc3QgdGhlIENTU09NIGRyYWZ0IHNwZWM6IGh0dHA6Ly9kZXYudzMub3JnL2Nzc3dnL2Nzc29tLyNyZXNvbHZlZC12YWx1ZXMKCQlpZiAoIHJudW1ub25weC50ZXN0KCByZXQgKSAmJiBybWFyZ2luLnRlc3QoIG5hbWUgKSApIHsKCgkJCS8vIFJlbWVtYmVyIHRoZSBvcmlnaW5hbCB2YWx1ZXMKCQkJd2lkdGggPSBzdHlsZS53aWR0aDsKCQkJbWluV2lkdGggPSBzdHlsZS5taW5XaWR0aDsKCQkJbWF4V2lkdGggPSBzdHlsZS5tYXhXaWR0aDsKCgkJCS8vIFB1dCBpbiB0aGUgbmV3IHZhbHVlcyB0byBnZXQgYSBjb21wdXRlZCB2YWx1ZSBvdXQKCQkJc3R5bGUubWluV2lkdGggPSBzdHlsZS5tYXhXaWR0aCA9IHN0eWxlLndpZHRoID0gcmV0OwoJCQlyZXQgPSBjb21wdXRlZC53aWR0aDsKCgkJCS8vIFJldmVydCB0aGUgY2hhbmdlZCB2YWx1ZXMKCQkJc3R5bGUud2lkdGggPSB3aWR0aDsKCQkJc3R5bGUubWluV2lkdGggPSBtaW5XaWR0aDsKCQkJc3R5bGUubWF4V2lkdGggPSBtYXhXaWR0aDsKCQl9Cgl9CgoJcmV0dXJuIHJldCAhPT0gdW5kZWZpbmVkID8KCQkvLyBTdXBwb3J0OiBJRQoJCS8vIElFIHJldHVybnMgekluZGV4IHZhbHVlIGFzIGFuIGludGVnZXIuCgkJcmV0ICsgIiIgOgoJCXJldDsKfQoKCmZ1bmN0aW9uIGFkZEdldEhvb2tJZiggY29uZGl0aW9uRm4sIGhvb2tGbiApIHsKCS8vIERlZmluZSB0aGUgaG9vaywgd2UnbGwgY2hlY2sgb24gdGhlIGZpcnN0IHJ1biBpZiBpdCdzIHJlYWxseSBuZWVkZWQuCglyZXR1cm4gewoJCWdldDogZnVuY3Rpb24oKSB7CgkJCWlmICggY29uZGl0aW9uRm4oKSApIHsKCQkJCS8vIEhvb2sgbm90IG5lZWRlZCAob3IgaXQncyBub3QgcG9zc2libGUgdG8gdXNlIGl0IGR1ZSB0byBtaXNzaW5nIGRlcGVuZGVuY3kpLAoJCQkJLy8gcmVtb3ZlIGl0LgoJCQkJLy8gU2luY2UgdGhlcmUgYXJlIG5vIG90aGVyIGhvb2tzIGZvciBtYXJnaW5SaWdodCwgcmVtb3ZlIHRoZSB3aG9sZSBvYmplY3QuCgkJCQlkZWxldGUgdGhpcy5nZXQ7CgkJCQlyZXR1cm47CgkJCX0KCgkJCS8vIEhvb2sgbmVlZGVkOyByZWRlZmluZSBpdCBzbyB0aGF0IHRoZSBzdXBwb3J0IHRlc3QgaXMgbm90IGV4ZWN1dGVkIGFnYWluLgoKCQkJcmV0dXJuICh0aGlzLmdldCA9IGhvb2tGbikuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApOwoJCX0KCX07Cn0KCgooZnVuY3Rpb24oKSB7Cgl2YXIgcGl4ZWxQb3NpdGlvblZhbCwgYm94U2l6aW5nUmVsaWFibGVWYWwsCgkJZG9jRWxlbSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCwKCQljb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAiZGl2IiApLAoJCWRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICJkaXYiICk7CgoJaWYgKCAhZGl2LnN0eWxlICkgewoJCXJldHVybjsKCX0KCglkaXYuc3R5bGUuYmFja2dyb3VuZENsaXAgPSAiY29udGVudC1ib3giOwoJZGl2LmNsb25lTm9kZSggdHJ1ZSApLnN0eWxlLmJhY2tncm91bmRDbGlwID0gIiI7CglzdXBwb3J0LmNsZWFyQ2xvbmVTdHlsZSA9IGRpdi5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9PT0gImNvbnRlbnQtYm94IjsKCgljb250YWluZXIuc3R5bGUuY3NzVGV4dCA9ICJib3JkZXI6MDt3aWR0aDowO2hlaWdodDowO3RvcDowO2xlZnQ6LTk5OTlweDttYXJnaW4tdG9wOjFweDsiICsKCQkicG9zaXRpb246YWJzb2x1dGUiOwoJY29udGFpbmVyLmFwcGVuZENoaWxkKCBkaXYgKTsKCgkvLyBFeGVjdXRpbmcgYm90aCBwaXhlbFBvc2l0aW9uICYgYm94U2l6aW5nUmVsaWFibGUgdGVzdHMgcmVxdWlyZSBvbmx5IG9uZSBsYXlvdXQKCS8vIHNvIHRoZXkncmUgZXhlY3V0ZWQgYXQgdGhlIHNhbWUgdGltZSB0byBzYXZlIHRoZSBzZWNvbmQgY29tcHV0YXRpb24uCglmdW5jdGlvbiBjb21wdXRlUGl4ZWxQb3NpdGlvbkFuZEJveFNpemluZ1JlbGlhYmxlKCkgewoJCWRpdi5zdHlsZS5jc3NUZXh0ID0KCQkJLy8gU3VwcG9ydDogRmlyZWZveDwyOSwgQW5kcm9pZCAyLjMKCQkJLy8gVmVuZG9yLXByZWZpeCBib3gtc2l6aW5nCgkJCSItd2Via2l0LWJveC1zaXppbmc6Ym9yZGVyLWJveDstbW96LWJveC1zaXppbmc6Ym9yZGVyLWJveDsiICsKCQkJImJveC1zaXppbmc6Ym9yZGVyLWJveDtkaXNwbGF5OmJsb2NrO21hcmdpbi10b3A6MSU7dG9wOjElOyIgKwoJCQkiYm9yZGVyOjFweDtwYWRkaW5nOjFweDt3aWR0aDo0cHg7cG9zaXRpb246YWJzb2x1dGUiOwoJCWRpdi5pbm5lckhUTUwgPSAiIjsKCQlkb2NFbGVtLmFwcGVuZENoaWxkKCBjb250YWluZXIgKTsKCgkJdmFyIGRpdlN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoIGRpdiwgbnVsbCApOwoJCXBpeGVsUG9zaXRpb25WYWwgPSBkaXZTdHlsZS50b3AgIT09ICIxJSI7CgkJYm94U2l6aW5nUmVsaWFibGVWYWwgPSBkaXZTdHlsZS53aWR0aCA9PT0gIjRweCI7CgoJCWRvY0VsZW0ucmVtb3ZlQ2hpbGQoIGNvbnRhaW5lciApOwoJfQoKCS8vIFN1cHBvcnQ6IG5vZGUuanMganNkb20KCS8vIERvbid0IGFzc3VtZSB0aGF0IGdldENvbXB1dGVkU3R5bGUgaXMgYSBwcm9wZXJ0eSBvZiB0aGUgZ2xvYmFsIG9iamVjdAoJaWYgKCB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSApIHsKCQlqUXVlcnkuZXh0ZW5kKCBzdXBwb3J0LCB7CgkJCXBpeGVsUG9zaXRpb246IGZ1bmN0aW9uKCkgewoJCQkJLy8gVGhpcyB0ZXN0IGlzIGV4ZWN1dGVkIG9ubHkgb25jZSBidXQgd2Ugc3RpbGwgZG8gbWVtb2l6aW5nCgkJCQkvLyBzaW5jZSB3ZSBjYW4gdXNlIHRoZSBib3hTaXppbmdSZWxpYWJsZSBwcmUtY29tcHV0aW5nLgoJCQkJLy8gTm8gbmVlZCB0byBjaGVjayBpZiB0aGUgdGVzdCB3YXMgYWxyZWFkeSBwZXJmb3JtZWQsIHRob3VnaC4KCQkJCWNvbXB1dGVQaXhlbFBvc2l0aW9uQW5kQm94U2l6aW5nUmVsaWFibGUoKTsKCQkJCXJldHVybiBwaXhlbFBvc2l0aW9uVmFsOwoJCQl9LAoJCQlib3hTaXppbmdSZWxpYWJsZTogZnVuY3Rpb24oKSB7CgkJCQlpZiAoIGJveFNpemluZ1JlbGlhYmxlVmFsID09IG51bGwgKSB7CgkJCQkJY29tcHV0ZVBpeGVsUG9zaXRpb25BbmRCb3hTaXppbmdSZWxpYWJsZSgpOwoJCQkJfQoJCQkJcmV0dXJuIGJveFNpemluZ1JlbGlhYmxlVmFsOwoJCQl9LAoJCQlyZWxpYWJsZU1hcmdpblJpZ2h0OiBmdW5jdGlvbigpIHsKCQkJCS8vIFN1cHBvcnQ6IEFuZHJvaWQgMi4zCgkJCQkvLyBDaGVjayBpZiBkaXYgd2l0aCBleHBsaWNpdCB3aWR0aCBhbmQgbm8gbWFyZ2luLXJpZ2h0IGluY29ycmVjdGx5CgkJCQkvLyBnZXRzIGNvbXB1dGVkIG1hcmdpbi1yaWdodCBiYXNlZCBvbiB3aWR0aCBvZiBjb250YWluZXIuICgjMzMzMykKCQkJCS8vIFdlYktpdCBCdWcgMTMzNDMgLSBnZXRDb21wdXRlZFN0eWxlIHJldHVybnMgd3JvbmcgdmFsdWUgZm9yIG1hcmdpbi1yaWdodAoJCQkJLy8gVGhpcyBzdXBwb3J0IGZ1bmN0aW9uIGlzIG9ubHkgZXhlY3V0ZWQgb25jZSBzbyBubyBtZW1vaXppbmcgaXMgbmVlZGVkLgoJCQkJdmFyIHJldCwKCQkJCQltYXJnaW5EaXYgPSBkaXYuYXBwZW5kQ2hpbGQoIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICJkaXYiICkgKTsKCgkJCQkvLyBSZXNldCBDU1M6IGJveC1zaXppbmc7IGRpc3BsYXk7IG1hcmdpbjsgYm9yZGVyOyBwYWRkaW5nCgkJCQltYXJnaW5EaXYuc3R5bGUuY3NzVGV4dCA9IGRpdi5zdHlsZS5jc3NUZXh0ID0KCQkJCQkvLyBTdXBwb3J0OiBGaXJlZm94PDI5LCBBbmRyb2lkIDIuMwoJCQkJCS8vIFZlbmRvci1wcmVmaXggYm94LXNpemluZwoJCQkJCSItd2Via2l0LWJveC1zaXppbmc6Y29udGVudC1ib3g7LW1vei1ib3gtc2l6aW5nOmNvbnRlbnQtYm94OyIgKwoJCQkJCSJib3gtc2l6aW5nOmNvbnRlbnQtYm94O2Rpc3BsYXk6YmxvY2s7bWFyZ2luOjA7Ym9yZGVyOjA7cGFkZGluZzowIjsKCQkJCW1hcmdpbkRpdi5zdHlsZS5tYXJnaW5SaWdodCA9IG1hcmdpbkRpdi5zdHlsZS53aWR0aCA9ICIwIjsKCQkJCWRpdi5zdHlsZS53aWR0aCA9ICIxcHgiOwoJCQkJZG9jRWxlbS5hcHBlbmRDaGlsZCggY29udGFpbmVyICk7CgoJCQkJcmV0ID0gIXBhcnNlRmxvYXQoIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKCBtYXJnaW5EaXYsIG51bGwgKS5tYXJnaW5SaWdodCApOwoKCQkJCWRvY0VsZW0ucmVtb3ZlQ2hpbGQoIGNvbnRhaW5lciApOwoKCQkJCXJldHVybiByZXQ7CgkJCX0KCQl9KTsKCX0KfSkoKTsKCgovLyBBIG1ldGhvZCBmb3IgcXVpY2tseSBzd2FwcGluZyBpbi9vdXQgQ1NTIHByb3BlcnRpZXMgdG8gZ2V0IGNvcnJlY3QgY2FsY3VsYXRpb25zLgpqUXVlcnkuc3dhcCA9IGZ1bmN0aW9uKCBlbGVtLCBvcHRpb25zLCBjYWxsYmFjaywgYXJncyApIHsKCXZhciByZXQsIG5hbWUsCgkJb2xkID0ge307CgoJLy8gUmVtZW1iZXIgdGhlIG9sZCB2YWx1ZXMsIGFuZCBpbnNlcnQgdGhlIG5ldyBvbmVzCglmb3IgKCBuYW1lIGluIG9wdGlvbnMgKSB7CgkJb2xkWyBuYW1lIF0gPSBlbGVtLnN0eWxlWyBuYW1lIF07CgkJZWxlbS5zdHlsZVsgbmFtZSBdID0gb3B0aW9uc1sgbmFtZSBdOwoJfQoKCXJldCA9IGNhbGxiYWNrLmFwcGx5KCBlbGVtLCBhcmdzIHx8IFtdICk7CgoJLy8gUmV2ZXJ0IHRoZSBvbGQgdmFsdWVzCglmb3IgKCBuYW1lIGluIG9wdGlvbnMgKSB7CgkJZWxlbS5zdHlsZVsgbmFtZSBdID0gb2xkWyBuYW1lIF07Cgl9CgoJcmV0dXJuIHJldDsKfTsKCgp2YXIKCS8vIHN3YXBwYWJsZSBpZiBkaXNwbGF5IGlzIG5vbmUgb3Igc3RhcnRzIHdpdGggdGFibGUgZXhjZXB0ICJ0YWJsZSIsICJ0YWJsZS1jZWxsIiwgb3IgInRhYmxlLWNhcHRpb24iCgkvLyBzZWUgaGVyZSBmb3IgZGlzcGxheSB2YWx1ZXM6IGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvQ1NTL2Rpc3BsYXkKCXJkaXNwbGF5c3dhcCA9IC9eKG5vbmV8dGFibGUoPyEtY1tlYV0pLispLywKCXJudW1zcGxpdCA9IG5ldyBSZWdFeHAoICJeKCIgKyBwbnVtICsgIikoLiopJCIsICJpIiApLAoJcnJlbE51bSA9IG5ldyBSZWdFeHAoICJeKFsrLV0pPSgiICsgcG51bSArICIpIiwgImkiICksCgoJY3NzU2hvdyA9IHsgcG9zaXRpb246ICJhYnNvbHV0ZSIsIHZpc2liaWxpdHk6ICJoaWRkZW4iLCBkaXNwbGF5OiAiYmxvY2siIH0sCgljc3NOb3JtYWxUcmFuc2Zvcm0gPSB7CgkJbGV0dGVyU3BhY2luZzogIjAiLAoJCWZvbnRXZWlnaHQ6ICI0MDAiCgl9LAoKCWNzc1ByZWZpeGVzID0gWyAiV2Via2l0IiwgIk8iLCAiTW96IiwgIm1zIiBdOwoKLy8gcmV0dXJuIGEgY3NzIHByb3BlcnR5IG1hcHBlZCB0byBhIHBvdGVudGlhbGx5IHZlbmRvciBwcmVmaXhlZCBwcm9wZXJ0eQpmdW5jdGlvbiB2ZW5kb3JQcm9wTmFtZSggc3R5bGUsIG5hbWUgKSB7CgoJLy8gc2hvcnRjdXQgZm9yIG5hbWVzIHRoYXQgYXJlIG5vdCB2ZW5kb3IgcHJlZml4ZWQKCWlmICggbmFtZSBpbiBzdHlsZSApIHsKCQlyZXR1cm4gbmFtZTsKCX0KCgkvLyBjaGVjayBmb3IgdmVuZG9yIHByZWZpeGVkIG5hbWVzCgl2YXIgY2FwTmFtZSA9IG5hbWVbMF0udG9VcHBlckNhc2UoKSArIG5hbWUuc2xpY2UoMSksCgkJb3JpZ05hbWUgPSBuYW1lLAoJCWkgPSBjc3NQcmVmaXhlcy5sZW5ndGg7CgoJd2hpbGUgKCBpLS0gKSB7CgkJbmFtZSA9IGNzc1ByZWZpeGVzWyBpIF0gKyBjYXBOYW1lOwoJCWlmICggbmFtZSBpbiBzdHlsZSApIHsKCQkJcmV0dXJuIG5hbWU7CgkJfQoJfQoKCXJldHVybiBvcmlnTmFtZTsKfQoKZnVuY3Rpb24gc2V0UG9zaXRpdmVOdW1iZXIoIGVsZW0sIHZhbHVlLCBzdWJ0cmFjdCApIHsKCXZhciBtYXRjaGVzID0gcm51bXNwbGl0LmV4ZWMoIHZhbHVlICk7CglyZXR1cm4gbWF0Y2hlcyA/CgkJLy8gR3VhcmQgYWdhaW5zdCB1bmRlZmluZWQgInN1YnRyYWN0IiwgZS5nLiwgd2hlbiB1c2VkIGFzIGluIGNzc0hvb2tzCgkJTWF0aC5tYXgoIDAsIG1hdGNoZXNbIDEgXSAtICggc3VidHJhY3QgfHwgMCApICkgKyAoIG1hdGNoZXNbIDIgXSB8fCAicHgiICkgOgoJCXZhbHVlOwp9CgpmdW5jdGlvbiBhdWdtZW50V2lkdGhPckhlaWdodCggZWxlbSwgbmFtZSwgZXh0cmEsIGlzQm9yZGVyQm94LCBzdHlsZXMgKSB7Cgl2YXIgaSA9IGV4dHJhID09PSAoIGlzQm9yZGVyQm94ID8gImJvcmRlciIgOiAiY29udGVudCIgKSA/CgkJLy8gSWYgd2UgYWxyZWFkeSBoYXZlIHRoZSByaWdodCBtZWFzdXJlbWVudCwgYXZvaWQgYXVnbWVudGF0aW9uCgkJNCA6CgkJLy8gT3RoZXJ3aXNlIGluaXRpYWxpemUgZm9yIGhvcml6b250YWwgb3IgdmVydGljYWwgcHJvcGVydGllcwoJCW5hbWUgPT09ICJ3aWR0aCIgPyAxIDogMCwKCgkJdmFsID0gMDsKCglmb3IgKCA7IGkgPCA0OyBpICs9IDIgKSB7CgkJLy8gYm90aCBib3ggbW9kZWxzIGV4Y2x1ZGUgbWFyZ2luLCBzbyBhZGQgaXQgaWYgd2Ugd2FudCBpdAoJCWlmICggZXh0cmEgPT09ICJtYXJnaW4iICkgewoJCQl2YWwgKz0galF1ZXJ5LmNzcyggZWxlbSwgZXh0cmEgKyBjc3NFeHBhbmRbIGkgXSwgdHJ1ZSwgc3R5bGVzICk7CgkJfQoKCQlpZiAoIGlzQm9yZGVyQm94ICkgewoJCQkvLyBib3JkZXItYm94IGluY2x1ZGVzIHBhZGRpbmcsIHNvIHJlbW92ZSBpdCBpZiB3ZSB3YW50IGNvbnRlbnQKCQkJaWYgKCBleHRyYSA9PT0gImNvbnRlbnQiICkgewoJCQkJdmFsIC09IGpRdWVyeS5jc3MoIGVsZW0sICJwYWRkaW5nIiArIGNzc0V4cGFuZFsgaSBdLCB0cnVlLCBzdHlsZXMgKTsKCQkJfQoKCQkJLy8gYXQgdGhpcyBwb2ludCwgZXh0cmEgaXNuJ3QgYm9yZGVyIG5vciBtYXJnaW4sIHNvIHJlbW92ZSBib3JkZXIKCQkJaWYgKCBleHRyYSAhPT0gIm1hcmdpbiIgKSB7CgkJCQl2YWwgLT0galF1ZXJ5LmNzcyggZWxlbSwgImJvcmRlciIgKyBjc3NFeHBhbmRbIGkgXSArICJXaWR0aCIsIHRydWUsIHN0eWxlcyApOwoJCQl9CgkJfSBlbHNlIHsKCQkJLy8gYXQgdGhpcyBwb2ludCwgZXh0cmEgaXNuJ3QgY29udGVudCwgc28gYWRkIHBhZGRpbmcKCQkJdmFsICs9IGpRdWVyeS5jc3MoIGVsZW0sICJwYWRkaW5nIiArIGNzc0V4cGFuZFsgaSBdLCB0cnVlLCBzdHlsZXMgKTsKCgkJCS8vIGF0IHRoaXMgcG9pbnQsIGV4dHJhIGlzbid0IGNvbnRlbnQgbm9yIHBhZGRpbmcsIHNvIGFkZCBib3JkZXIKCQkJaWYgKCBleHRyYSAhPT0gInBhZGRpbmciICkgewoJCQkJdmFsICs9IGpRdWVyeS5jc3MoIGVsZW0sICJib3JkZXIiICsgY3NzRXhwYW5kWyBpIF0gKyAiV2lkdGgiLCB0cnVlLCBzdHlsZXMgKTsKCQkJfQoJCX0KCX0KCglyZXR1cm4gdmFsOwp9CgpmdW5jdGlvbiBnZXRXaWR0aE9ySGVpZ2h0KCBlbGVtLCBuYW1lLCBleHRyYSApIHsKCgkvLyBTdGFydCB3aXRoIG9mZnNldCBwcm9wZXJ0eSwgd2hpY2ggaXMgZXF1aXZhbGVudCB0byB0aGUgYm9yZGVyLWJveCB2YWx1ZQoJdmFyIHZhbHVlSXNCb3JkZXJCb3ggPSB0cnVlLAoJCXZhbCA9IG5hbWUgPT09ICJ3aWR0aCIgPyBlbGVtLm9mZnNldFdpZHRoIDogZWxlbS5vZmZzZXRIZWlnaHQsCgkJc3R5bGVzID0gZ2V0U3R5bGVzKCBlbGVtICksCgkJaXNCb3JkZXJCb3ggPSBqUXVlcnkuY3NzKCBlbGVtLCAiYm94U2l6aW5nIiwgZmFsc2UsIHN0eWxlcyApID09PSAiYm9yZGVyLWJveCI7CgoJLy8gc29tZSBub24taHRtbCBlbGVtZW50cyByZXR1cm4gdW5kZWZpbmVkIGZvciBvZmZzZXRXaWR0aCwgc28gY2hlY2sgZm9yIG51bGwvdW5kZWZpbmVkCgkvLyBzdmcgLSBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02NDkyODUKCS8vIE1hdGhNTCAtIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTQ5MTY2OAoJaWYgKCB2YWwgPD0gMCB8fCB2YWwgPT0gbnVsbCApIHsKCQkvLyBGYWxsIGJhY2sgdG8gY29tcHV0ZWQgdGhlbiB1bmNvbXB1dGVkIGNzcyBpZiBuZWNlc3NhcnkKCQl2YWwgPSBjdXJDU1MoIGVsZW0sIG5hbWUsIHN0eWxlcyApOwoJCWlmICggdmFsIDwgMCB8fCB2YWwgPT0gbnVsbCApIHsKCQkJdmFsID0gZWxlbS5zdHlsZVsgbmFtZSBdOwoJCX0KCgkJLy8gQ29tcHV0ZWQgdW5pdCBpcyBub3QgcGl4ZWxzLiBTdG9wIGhlcmUgYW5kIHJldHVybi4KCQlpZiAoIHJudW1ub25weC50ZXN0KHZhbCkgKSB7CgkJCXJldHVybiB2YWw7CgkJfQoKCQkvLyB3ZSBuZWVkIHRoZSBjaGVjayBmb3Igc3R5bGUgaW4gY2FzZSBhIGJyb3dzZXIgd2hpY2ggcmV0dXJucyB1bnJlbGlhYmxlIHZhbHVlcwoJCS8vIGZvciBnZXRDb21wdXRlZFN0eWxlIHNpbGVudGx5IGZhbGxzIGJhY2sgdG8gdGhlIHJlbGlhYmxlIGVsZW0uc3R5bGUKCQl2YWx1ZUlzQm9yZGVyQm94ID0gaXNCb3JkZXJCb3ggJiYKCQkJKCBzdXBwb3J0LmJveFNpemluZ1JlbGlhYmxlKCkgfHwgdmFsID09PSBlbGVtLnN0eWxlWyBuYW1lIF0gKTsKCgkJLy8gTm9ybWFsaXplICIiLCBhdXRvLCBhbmQgcHJlcGFyZSBmb3IgZXh0cmEKCQl2YWwgPSBwYXJzZUZsb2F0KCB2YWwgKSB8fCAwOwoJfQoKCS8vIHVzZSB0aGUgYWN0aXZlIGJveC1zaXppbmcgbW9kZWwgdG8gYWRkL3N1YnRyYWN0IGlycmVsZXZhbnQgc3R5bGVzCglyZXR1cm4gKCB2YWwgKwoJCWF1Z21lbnRXaWR0aE9ySGVpZ2h0KAoJCQllbGVtLAoJCQluYW1lLAoJCQlleHRyYSB8fCAoIGlzQm9yZGVyQm94ID8gImJvcmRlciIgOiAiY29udGVudCIgKSwKCQkJdmFsdWVJc0JvcmRlckJveCwKCQkJc3R5bGVzCgkJKQoJKSArICJweCI7Cn0KCmZ1bmN0aW9uIHNob3dIaWRlKCBlbGVtZW50cywgc2hvdyApIHsKCXZhciBkaXNwbGF5LCBlbGVtLCBoaWRkZW4sCgkJdmFsdWVzID0gW10sCgkJaW5kZXggPSAwLAoJCWxlbmd0aCA9IGVsZW1lbnRzLmxlbmd0aDsKCglmb3IgKCA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkgewoJCWVsZW0gPSBlbGVtZW50c1sgaW5kZXggXTsKCQlpZiAoICFlbGVtLnN0eWxlICkgewoJCQljb250aW51ZTsKCQl9CgoJCXZhbHVlc1sgaW5kZXggXSA9IGRhdGFfcHJpdi5nZXQoIGVsZW0sICJvbGRkaXNwbGF5IiApOwoJCWRpc3BsYXkgPSBlbGVtLnN0eWxlLmRpc3BsYXk7CgkJaWYgKCBzaG93ICkgewoJCQkvLyBSZXNldCB0aGUgaW5saW5lIGRpc3BsYXkgb2YgdGhpcyBlbGVtZW50IHRvIGxlYXJuIGlmIGl0IGlzCgkJCS8vIGJlaW5nIGhpZGRlbiBieSBjYXNjYWRlZCBydWxlcyBvciBub3QKCQkJaWYgKCAhdmFsdWVzWyBpbmRleCBdICYmIGRpc3BsYXkgPT09ICJub25lIiApIHsKCQkJCWVsZW0uc3R5bGUuZGlzcGxheSA9ICIiOwoJCQl9CgoJCQkvLyBTZXQgZWxlbWVudHMgd2hpY2ggaGF2ZSBiZWVuIG92ZXJyaWRkZW4gd2l0aCBkaXNwbGF5OiBub25lCgkJCS8vIGluIGEgc3R5bGVzaGVldCB0byB3aGF0ZXZlciB0aGUgZGVmYXVsdCBicm93c2VyIHN0eWxlIGlzCgkJCS8vIGZvciBzdWNoIGFuIGVsZW1lbnQKCQkJaWYgKCBlbGVtLnN0eWxlLmRpc3BsYXkgPT09ICIiICYmIGlzSGlkZGVuKCBlbGVtICkgKSB7CgkJCQl2YWx1ZXNbIGluZGV4IF0gPSBkYXRhX3ByaXYuYWNjZXNzKCBlbGVtLCAib2xkZGlzcGxheSIsIGRlZmF1bHREaXNwbGF5KGVsZW0ubm9kZU5hbWUpICk7CgkJCX0KCQl9IGVsc2UgewoJCQloaWRkZW4gPSBpc0hpZGRlbiggZWxlbSApOwoKCQkJaWYgKCBkaXNwbGF5ICE9PSAibm9uZSIgfHwgIWhpZGRlbiApIHsKCQkJCWRhdGFfcHJpdi5zZXQoIGVsZW0sICJvbGRkaXNwbGF5IiwgaGlkZGVuID8gZGlzcGxheSA6IGpRdWVyeS5jc3MoIGVsZW0sICJkaXNwbGF5IiApICk7CgkJCX0KCQl9Cgl9CgoJLy8gU2V0IHRoZSBkaXNwbGF5IG9mIG1vc3Qgb2YgdGhlIGVsZW1lbnRzIGluIGEgc2Vjb25kIGxvb3AKCS8vIHRvIGF2b2lkIHRoZSBjb25zdGFudCByZWZsb3cKCWZvciAoIGluZGV4ID0gMDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KysgKSB7CgkJZWxlbSA9IGVsZW1lbnRzWyBpbmRleCBdOwoJCWlmICggIWVsZW0uc3R5bGUgKSB7CgkJCWNvbnRpbnVlOwoJCX0KCQlpZiAoICFzaG93IHx8IGVsZW0uc3R5bGUuZGlzcGxheSA9PT0gIm5vbmUiIHx8IGVsZW0uc3R5bGUuZGlzcGxheSA9PT0gIiIgKSB7CgkJCWVsZW0uc3R5bGUuZGlzcGxheSA9IHNob3cgPyB2YWx1ZXNbIGluZGV4IF0gfHwgIiIgOiAibm9uZSI7CgkJfQoJfQoKCXJldHVybiBlbGVtZW50czsKfQoKalF1ZXJ5LmV4dGVuZCh7CgkvLyBBZGQgaW4gc3R5bGUgcHJvcGVydHkgaG9va3MgZm9yIG92ZXJyaWRpbmcgdGhlIGRlZmF1bHQKCS8vIGJlaGF2aW9yIG9mIGdldHRpbmcgYW5kIHNldHRpbmcgYSBzdHlsZSBwcm9wZXJ0eQoJY3NzSG9va3M6IHsKCQlvcGFjaXR5OiB7CgkJCWdldDogZnVuY3Rpb24oIGVsZW0sIGNvbXB1dGVkICkgewoJCQkJaWYgKCBjb21wdXRlZCApIHsKCQkJCQkvLyBXZSBzaG91bGQgYWx3YXlzIGdldCBhIG51bWJlciBiYWNrIGZyb20gb3BhY2l0eQoJCQkJCXZhciByZXQgPSBjdXJDU1MoIGVsZW0sICJvcGFjaXR5IiApOwoJCQkJCXJldHVybiByZXQgPT09ICIiID8gIjEiIDogcmV0OwoJCQkJfQoJCQl9CgkJfQoJfSwKCgkvLyBEb24ndCBhdXRvbWF0aWNhbGx5IGFkZCAicHgiIHRvIHRoZXNlIHBvc3NpYmx5LXVuaXRsZXNzIHByb3BlcnRpZXMKCWNzc051bWJlcjogewoJCSJjb2x1bW5Db3VudCI6IHRydWUsCgkJImZpbGxPcGFjaXR5IjogdHJ1ZSwKCQkiZmxleEdyb3ciOiB0cnVlLAoJCSJmbGV4U2hyaW5rIjogdHJ1ZSwKCQkiZm9udFdlaWdodCI6IHRydWUsCgkJImxpbmVIZWlnaHQiOiB0cnVlLAoJCSJvcGFjaXR5IjogdHJ1ZSwKCQkib3JkZXIiOiB0cnVlLAoJCSJvcnBoYW5zIjogdHJ1ZSwKCQkid2lkb3dzIjogdHJ1ZSwKCQkiekluZGV4IjogdHJ1ZSwKCQkiem9vbSI6IHRydWUKCX0sCgoJLy8gQWRkIGluIHByb3BlcnRpZXMgd2hvc2UgbmFtZXMgeW91IHdpc2ggdG8gZml4IGJlZm9yZQoJLy8gc2V0dGluZyBvciBnZXR0aW5nIHRoZSB2YWx1ZQoJY3NzUHJvcHM6IHsKCQkvLyBub3JtYWxpemUgZmxvYXQgY3NzIHByb3BlcnR5CgkJImZsb2F0IjogImNzc0Zsb2F0IgoJfSwKCgkvLyBHZXQgYW5kIHNldCB0aGUgc3R5bGUgcHJvcGVydHkgb24gYSBET00gTm9kZQoJc3R5bGU6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCB2YWx1ZSwgZXh0cmEgKSB7CgkJLy8gRG9uJ3Qgc2V0IHN0eWxlcyBvbiB0ZXh0IGFuZCBjb21tZW50IG5vZGVzCgkJaWYgKCAhZWxlbSB8fCBlbGVtLm5vZGVUeXBlID09PSAzIHx8IGVsZW0ubm9kZVR5cGUgPT09IDggfHwgIWVsZW0uc3R5bGUgKSB7CgkJCXJldHVybjsKCQl9CgoJCS8vIE1ha2Ugc3VyZSB0aGF0IHdlJ3JlIHdvcmtpbmcgd2l0aCB0aGUgcmlnaHQgbmFtZQoJCXZhciByZXQsIHR5cGUsIGhvb2tzLAoJCQlvcmlnTmFtZSA9IGpRdWVyeS5jYW1lbENhc2UoIG5hbWUgKSwKCQkJc3R5bGUgPSBlbGVtLnN0eWxlOwoKCQluYW1lID0galF1ZXJ5LmNzc1Byb3BzWyBvcmlnTmFtZSBdIHx8ICggalF1ZXJ5LmNzc1Byb3BzWyBvcmlnTmFtZSBdID0gdmVuZG9yUHJvcE5hbWUoIHN0eWxlLCBvcmlnTmFtZSApICk7CgoJCS8vIGdldHMgaG9vayBmb3IgdGhlIHByZWZpeGVkIHZlcnNpb24KCQkvLyBmb2xsb3dlZCBieSB0aGUgdW5wcmVmaXhlZCB2ZXJzaW9uCgkJaG9va3MgPSBqUXVlcnkuY3NzSG9va3NbIG5hbWUgXSB8fCBqUXVlcnkuY3NzSG9va3NbIG9yaWdOYW1lIF07CgoJCS8vIENoZWNrIGlmIHdlJ3JlIHNldHRpbmcgYSB2YWx1ZQoJCWlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHsKCQkJdHlwZSA9IHR5cGVvZiB2YWx1ZTsKCgkJCS8vIGNvbnZlcnQgcmVsYXRpdmUgbnVtYmVyIHN0cmluZ3MgKCs9IG9yIC09KSB0byByZWxhdGl2ZSBudW1iZXJzLiAjNzM0NQoJCQlpZiAoIHR5cGUgPT09ICJzdHJpbmciICYmIChyZXQgPSBycmVsTnVtLmV4ZWMoIHZhbHVlICkpICkgewoJCQkJdmFsdWUgPSAoIHJldFsxXSArIDEgKSAqIHJldFsyXSArIHBhcnNlRmxvYXQoIGpRdWVyeS5jc3MoIGVsZW0sIG5hbWUgKSApOwoJCQkJLy8gRml4ZXMgYnVnICM5MjM3CgkJCQl0eXBlID0gIm51bWJlciI7CgkJCX0KCgkJCS8vIE1ha2Ugc3VyZSB0aGF0IG51bGwgYW5kIE5hTiB2YWx1ZXMgYXJlbid0IHNldC4gU2VlOiAjNzExNgoJCQlpZiAoIHZhbHVlID09IG51bGwgfHwgdmFsdWUgIT09IHZhbHVlICkgewoJCQkJcmV0dXJuOwoJCQl9CgoJCQkvLyBJZiBhIG51bWJlciB3YXMgcGFzc2VkIGluLCBhZGQgJ3B4JyB0byB0aGUgKGV4Y2VwdCBmb3IgY2VydGFpbiBDU1MgcHJvcGVydGllcykKCQkJaWYgKCB0eXBlID09PSAibnVtYmVyIiAmJiAhalF1ZXJ5LmNzc051bWJlclsgb3JpZ05hbWUgXSApIHsKCQkJCXZhbHVlICs9ICJweCI7CgkJCX0KCgkJCS8vIEZpeGVzICM4OTA4LCBpdCBjYW4gYmUgZG9uZSBtb3JlIGNvcnJlY3RseSBieSBzcGVjaWZ5aW5nIHNldHRlcnMgaW4gY3NzSG9va3MsCgkJCS8vIGJ1dCBpdCB3b3VsZCBtZWFuIHRvIGRlZmluZSBlaWdodCAoZm9yIGV2ZXJ5IHByb2JsZW1hdGljIHByb3BlcnR5KSBpZGVudGljYWwgZnVuY3Rpb25zCgkJCWlmICggIXN1cHBvcnQuY2xlYXJDbG9uZVN0eWxlICYmIHZhbHVlID09PSAiIiAmJiBuYW1lLmluZGV4T2YoICJiYWNrZ3JvdW5kIiApID09PSAwICkgewoJCQkJc3R5bGVbIG5hbWUgXSA9ICJpbmhlcml0IjsKCQkJfQoKCQkJLy8gSWYgYSBob29rIHdhcyBwcm92aWRlZCwgdXNlIHRoYXQgdmFsdWUsIG90aGVyd2lzZSBqdXN0IHNldCB0aGUgc3BlY2lmaWVkIHZhbHVlCgkJCWlmICggIWhvb2tzIHx8ICEoInNldCIgaW4gaG9va3MpIHx8ICh2YWx1ZSA9IGhvb2tzLnNldCggZWxlbSwgdmFsdWUsIGV4dHJhICkpICE9PSB1bmRlZmluZWQgKSB7CgkJCQlzdHlsZVsgbmFtZSBdID0gdmFsdWU7CgkJCX0KCgkJfSBlbHNlIHsKCQkJLy8gSWYgYSBob29rIHdhcyBwcm92aWRlZCBnZXQgdGhlIG5vbi1jb21wdXRlZCB2YWx1ZSBmcm9tIHRoZXJlCgkJCWlmICggaG9va3MgJiYgImdldCIgaW4gaG9va3MgJiYgKHJldCA9IGhvb2tzLmdldCggZWxlbSwgZmFsc2UsIGV4dHJhICkpICE9PSB1bmRlZmluZWQgKSB7CgkJCQlyZXR1cm4gcmV0OwoJCQl9CgoJCQkvLyBPdGhlcndpc2UganVzdCBnZXQgdGhlIHZhbHVlIGZyb20gdGhlIHN0eWxlIG9iamVjdAoJCQlyZXR1cm4gc3R5bGVbIG5hbWUgXTsKCQl9Cgl9LAoKCWNzczogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGV4dHJhLCBzdHlsZXMgKSB7CgkJdmFyIHZhbCwgbnVtLCBob29rcywKCQkJb3JpZ05hbWUgPSBqUXVlcnkuY2FtZWxDYXNlKCBuYW1lICk7CgoJCS8vIE1ha2Ugc3VyZSB0aGF0IHdlJ3JlIHdvcmtpbmcgd2l0aCB0aGUgcmlnaHQgbmFtZQoJCW5hbWUgPSBqUXVlcnkuY3NzUHJvcHNbIG9yaWdOYW1lIF0gfHwgKCBqUXVlcnkuY3NzUHJvcHNbIG9yaWdOYW1lIF0gPSB2ZW5kb3JQcm9wTmFtZSggZWxlbS5zdHlsZSwgb3JpZ05hbWUgKSApOwoKCQkvLyBnZXRzIGhvb2sgZm9yIHRoZSBwcmVmaXhlZCB2ZXJzaW9uCgkJLy8gZm9sbG93ZWQgYnkgdGhlIHVucHJlZml4ZWQgdmVyc2lvbgoJCWhvb2tzID0galF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0gfHwgalF1ZXJ5LmNzc0hvb2tzWyBvcmlnTmFtZSBdOwoKCQkvLyBJZiBhIGhvb2sgd2FzIHByb3ZpZGVkIGdldCB0aGUgY29tcHV0ZWQgdmFsdWUgZnJvbSB0aGVyZQoJCWlmICggaG9va3MgJiYgImdldCIgaW4gaG9va3MgKSB7CgkJCXZhbCA9IGhvb2tzLmdldCggZWxlbSwgdHJ1ZSwgZXh0cmEgKTsKCQl9CgoJCS8vIE90aGVyd2lzZSwgaWYgYSB3YXkgdG8gZ2V0IHRoZSBjb21wdXRlZCB2YWx1ZSBleGlzdHMsIHVzZSB0aGF0CgkJaWYgKCB2YWwgPT09IHVuZGVmaW5lZCApIHsKCQkJdmFsID0gY3VyQ1NTKCBlbGVtLCBuYW1lLCBzdHlsZXMgKTsKCQl9CgoJCS8vY29udmVydCAibm9ybWFsIiB0byBjb21wdXRlZCB2YWx1ZQoJCWlmICggdmFsID09PSAibm9ybWFsIiAmJiBuYW1lIGluIGNzc05vcm1hbFRyYW5zZm9ybSApIHsKCQkJdmFsID0gY3NzTm9ybWFsVHJhbnNmb3JtWyBuYW1lIF07CgkJfQoKCQkvLyBSZXR1cm4sIGNvbnZlcnRpbmcgdG8gbnVtYmVyIGlmIGZvcmNlZCBvciBhIHF1YWxpZmllciB3YXMgcHJvdmlkZWQgYW5kIHZhbCBsb29rcyBudW1lcmljCgkJaWYgKCBleHRyYSA9PT0gIiIgfHwgZXh0cmEgKSB7CgkJCW51bSA9IHBhcnNlRmxvYXQoIHZhbCApOwoJCQlyZXR1cm4gZXh0cmEgPT09IHRydWUgfHwgalF1ZXJ5LmlzTnVtZXJpYyggbnVtICkgPyBudW0gfHwgMCA6IHZhbDsKCQl9CgkJcmV0dXJuIHZhbDsKCX0KfSk7CgpqUXVlcnkuZWFjaChbICJoZWlnaHQiLCAid2lkdGgiIF0sIGZ1bmN0aW9uKCBpLCBuYW1lICkgewoJalF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0gPSB7CgkJZ2V0OiBmdW5jdGlvbiggZWxlbSwgY29tcHV0ZWQsIGV4dHJhICkgewoJCQlpZiAoIGNvbXB1dGVkICkgewoJCQkJLy8gY2VydGFpbiBlbGVtZW50cyBjYW4gaGF2ZSBkaW1lbnNpb24gaW5mbyBpZiB3ZSBpbnZpc2libHkgc2hvdyB0aGVtCgkJCQkvLyBob3dldmVyLCBpdCBtdXN0IGhhdmUgYSBjdXJyZW50IGRpc3BsYXkgc3R5bGUgdGhhdCB3b3VsZCBiZW5lZml0IGZyb20gdGhpcwoJCQkJcmV0dXJuIHJkaXNwbGF5c3dhcC50ZXN0KCBqUXVlcnkuY3NzKCBlbGVtLCAiZGlzcGxheSIgKSApICYmIGVsZW0ub2Zmc2V0V2lkdGggPT09IDAgPwoJCQkJCWpRdWVyeS5zd2FwKCBlbGVtLCBjc3NTaG93LCBmdW5jdGlvbigpIHsKCQkJCQkJcmV0dXJuIGdldFdpZHRoT3JIZWlnaHQoIGVsZW0sIG5hbWUsIGV4dHJhICk7CgkJCQkJfSkgOgoJCQkJCWdldFdpZHRoT3JIZWlnaHQoIGVsZW0sIG5hbWUsIGV4dHJhICk7CgkJCX0KCQl9LAoKCQlzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSwgZXh0cmEgKSB7CgkJCXZhciBzdHlsZXMgPSBleHRyYSAmJiBnZXRTdHlsZXMoIGVsZW0gKTsKCQkJcmV0dXJuIHNldFBvc2l0aXZlTnVtYmVyKCBlbGVtLCB2YWx1ZSwgZXh0cmEgPwoJCQkJYXVnbWVudFdpZHRoT3JIZWlnaHQoCgkJCQkJZWxlbSwKCQkJCQluYW1lLAoJCQkJCWV4dHJhLAoJCQkJCWpRdWVyeS5jc3MoIGVsZW0sICJib3hTaXppbmciLCBmYWxzZSwgc3R5bGVzICkgPT09ICJib3JkZXItYm94IiwKCQkJCQlzdHlsZXMKCQkJCSkgOiAwCgkJCSk7CgkJfQoJfTsKfSk7CgovLyBTdXBwb3J0OiBBbmRyb2lkIDIuMwpqUXVlcnkuY3NzSG9va3MubWFyZ2luUmlnaHQgPSBhZGRHZXRIb29rSWYoIHN1cHBvcnQucmVsaWFibGVNYXJnaW5SaWdodCwKCWZ1bmN0aW9uKCBlbGVtLCBjb21wdXRlZCApIHsKCQlpZiAoIGNvbXB1dGVkICkgewoJCQkvLyBXZWJLaXQgQnVnIDEzMzQzIC0gZ2V0Q29tcHV0ZWRTdHlsZSByZXR1cm5zIHdyb25nIHZhbHVlIGZvciBtYXJnaW4tcmlnaHQKCQkJLy8gV29yayBhcm91bmQgYnkgdGVtcG9yYXJpbHkgc2V0dGluZyBlbGVtZW50IGRpc3BsYXkgdG8gaW5saW5lLWJsb2NrCgkJCXJldHVybiBqUXVlcnkuc3dhcCggZWxlbSwgeyAiZGlzcGxheSI6ICJpbmxpbmUtYmxvY2siIH0sCgkJCQljdXJDU1MsIFsgZWxlbSwgIm1hcmdpblJpZ2h0IiBdICk7CgkJfQoJfQopOwoKLy8gVGhlc2UgaG9va3MgYXJlIHVzZWQgYnkgYW5pbWF0ZSB0byBleHBhbmQgcHJvcGVydGllcwpqUXVlcnkuZWFjaCh7CgltYXJnaW46ICIiLAoJcGFkZGluZzogIiIsCglib3JkZXI6ICJXaWR0aCIKfSwgZnVuY3Rpb24oIHByZWZpeCwgc3VmZml4ICkgewoJalF1ZXJ5LmNzc0hvb2tzWyBwcmVmaXggKyBzdWZmaXggXSA9IHsKCQlleHBhbmQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHsKCQkJdmFyIGkgPSAwLAoJCQkJZXhwYW5kZWQgPSB7fSwKCgkJCQkvLyBhc3N1bWVzIGEgc2luZ2xlIG51bWJlciBpZiBub3QgYSBzdHJpbmcKCQkJCXBhcnRzID0gdHlwZW9mIHZhbHVlID09PSAic3RyaW5nIiA/IHZhbHVlLnNwbGl0KCIgIikgOiBbIHZhbHVlIF07CgoJCQlmb3IgKCA7IGkgPCA0OyBpKysgKSB7CgkJCQlleHBhbmRlZFsgcHJlZml4ICsgY3NzRXhwYW5kWyBpIF0gKyBzdWZmaXggXSA9CgkJCQkJcGFydHNbIGkgXSB8fCBwYXJ0c1sgaSAtIDIgXSB8fCBwYXJ0c1sgMCBdOwoJCQl9CgoJCQlyZXR1cm4gZXhwYW5kZWQ7CgkJfQoJfTsKCglpZiAoICFybWFyZ2luLnRlc3QoIHByZWZpeCApICkgewoJCWpRdWVyeS5jc3NIb29rc1sgcHJlZml4ICsgc3VmZml4IF0uc2V0ID0gc2V0UG9zaXRpdmVOdW1iZXI7Cgl9Cn0pOwoKalF1ZXJ5LmZuLmV4dGVuZCh7Cgljc3M6IGZ1bmN0aW9uKCBuYW1lLCB2YWx1ZSApIHsKCQlyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgdmFsdWUgKSB7CgkJCXZhciBzdHlsZXMsIGxlbiwKCQkJCW1hcCA9IHt9LAoJCQkJaSA9IDA7CgoJCQlpZiAoIGpRdWVyeS5pc0FycmF5KCBuYW1lICkgKSB7CgkJCQlzdHlsZXMgPSBnZXRTdHlsZXMoIGVsZW0gKTsKCQkJCWxlbiA9IG5hbWUubGVuZ3RoOwoKCQkJCWZvciAoIDsgaSA8IGxlbjsgaSsrICkgewoJCQkJCW1hcFsgbmFtZVsgaSBdIF0gPSBqUXVlcnkuY3NzKCBlbGVtLCBuYW1lWyBpIF0sIGZhbHNlLCBzdHlsZXMgKTsKCQkJCX0KCgkJCQlyZXR1cm4gbWFwOwoJCQl9CgoJCQlyZXR1cm4gdmFsdWUgIT09IHVuZGVmaW5lZCA/CgkJCQlqUXVlcnkuc3R5bGUoIGVsZW0sIG5hbWUsIHZhbHVlICkgOgoJCQkJalF1ZXJ5LmNzcyggZWxlbSwgbmFtZSApOwoJCX0sIG5hbWUsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoID4gMSApOwoJfSwKCXNob3c6IGZ1bmN0aW9uKCkgewoJCXJldHVybiBzaG93SGlkZSggdGhpcywgdHJ1ZSApOwoJfSwKCWhpZGU6IGZ1bmN0aW9uKCkgewoJCXJldHVybiBzaG93SGlkZSggdGhpcyApOwoJfSwKCXRvZ2dsZTogZnVuY3Rpb24oIHN0YXRlICkgewoJCWlmICggdHlwZW9mIHN0YXRlID09PSAiYm9vbGVhbiIgKSB7CgkJCXJldHVybiBzdGF0ZSA/IHRoaXMuc2hvdygpIDogdGhpcy5oaWRlKCk7CgkJfQoKCQlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkgewoJCQlpZiAoIGlzSGlkZGVuKCB0aGlzICkgKSB7CgkJCQlqUXVlcnkoIHRoaXMgKS5zaG93KCk7CgkJCX0gZWxzZSB7CgkJCQlqUXVlcnkoIHRoaXMgKS5oaWRlKCk7CgkJCX0KCQl9KTsKCX0KfSk7CgoKZnVuY3Rpb24gVHdlZW4oIGVsZW0sIG9wdGlvbnMsIHByb3AsIGVuZCwgZWFzaW5nICkgewoJcmV0dXJuIG5ldyBUd2Vlbi5wcm90b3R5cGUuaW5pdCggZWxlbSwgb3B0aW9ucywgcHJvcCwgZW5kLCBlYXNpbmcgKTsKfQpqUXVlcnkuVHdlZW4gPSBUd2VlbjsKClR3ZWVuLnByb3RvdHlwZSA9IHsKCWNvbnN0cnVjdG9yOiBUd2VlbiwKCWluaXQ6IGZ1bmN0aW9uKCBlbGVtLCBvcHRpb25zLCBwcm9wLCBlbmQsIGVhc2luZywgdW5pdCApIHsKCQl0aGlzLmVsZW0gPSBlbGVtOwoJCXRoaXMucHJvcCA9IHByb3A7CgkJdGhpcy5lYXNpbmcgPSBlYXNpbmcgfHwgInN3aW5nIjsKCQl0aGlzLm9wdGlvbnMgPSBvcHRpb25zOwoJCXRoaXMuc3RhcnQgPSB0aGlzLm5vdyA9IHRoaXMuY3VyKCk7CgkJdGhpcy5lbmQgPSBlbmQ7CgkJdGhpcy51bml0ID0gdW5pdCB8fCAoIGpRdWVyeS5jc3NOdW1iZXJbIHByb3AgXSA/ICIiIDogInB4IiApOwoJfSwKCWN1cjogZnVuY3Rpb24oKSB7CgkJdmFyIGhvb2tzID0gVHdlZW4ucHJvcEhvb2tzWyB0aGlzLnByb3AgXTsKCgkJcmV0dXJuIGhvb2tzICYmIGhvb2tzLmdldCA/CgkJCWhvb2tzLmdldCggdGhpcyApIDoKCQkJVHdlZW4ucHJvcEhvb2tzLl9kZWZhdWx0LmdldCggdGhpcyApOwoJfSwKCXJ1bjogZnVuY3Rpb24oIHBlcmNlbnQgKSB7CgkJdmFyIGVhc2VkLAoJCQlob29rcyA9IFR3ZWVuLnByb3BIb29rc1sgdGhpcy5wcm9wIF07CgoJCWlmICggdGhpcy5vcHRpb25zLmR1cmF0aW9uICkgewoJCQl0aGlzLnBvcyA9IGVhc2VkID0galF1ZXJ5LmVhc2luZ1sgdGhpcy5lYXNpbmcgXSgKCQkJCXBlcmNlbnQsIHRoaXMub3B0aW9ucy5kdXJhdGlvbiAqIHBlcmNlbnQsIDAsIDEsIHRoaXMub3B0aW9ucy5kdXJhdGlvbgoJCQkpOwoJCX0gZWxzZSB7CgkJCXRoaXMucG9zID0gZWFzZWQgPSBwZXJjZW50OwoJCX0KCQl0aGlzLm5vdyA9ICggdGhpcy5lbmQgLSB0aGlzLnN0YXJ0ICkgKiBlYXNlZCArIHRoaXMuc3RhcnQ7CgoJCWlmICggdGhpcy5vcHRpb25zLnN0ZXAgKSB7CgkJCXRoaXMub3B0aW9ucy5zdGVwLmNhbGwoIHRoaXMuZWxlbSwgdGhpcy5ub3csIHRoaXMgKTsKCQl9CgoJCWlmICggaG9va3MgJiYgaG9va3Muc2V0ICkgewoJCQlob29rcy5zZXQoIHRoaXMgKTsKCQl9IGVsc2UgewoJCQlUd2Vlbi5wcm9wSG9va3MuX2RlZmF1bHQuc2V0KCB0aGlzICk7CgkJfQoJCXJldHVybiB0aGlzOwoJfQp9OwoKVHdlZW4ucHJvdG90eXBlLmluaXQucHJvdG90eXBlID0gVHdlZW4ucHJvdG90eXBlOwoKVHdlZW4ucHJvcEhvb2tzID0gewoJX2RlZmF1bHQ6IHsKCQlnZXQ6IGZ1bmN0aW9uKCB0d2VlbiApIHsKCQkJdmFyIHJlc3VsdDsKCgkJCWlmICggdHdlZW4uZWxlbVsgdHdlZW4ucHJvcCBdICE9IG51bGwgJiYKCQkJCSghdHdlZW4uZWxlbS5zdHlsZSB8fCB0d2Vlbi5lbGVtLnN0eWxlWyB0d2Vlbi5wcm9wIF0gPT0gbnVsbCkgKSB7CgkJCQlyZXR1cm4gdHdlZW4uZWxlbVsgdHdlZW4ucHJvcCBdOwoJCQl9CgoJCQkvLyBwYXNzaW5nIGFuIGVtcHR5IHN0cmluZyBhcyBhIDNyZCBwYXJhbWV0ZXIgdG8gLmNzcyB3aWxsIGF1dG9tYXRpY2FsbHkKCQkJLy8gYXR0ZW1wdCBhIHBhcnNlRmxvYXQgYW5kIGZhbGxiYWNrIHRvIGEgc3RyaW5nIGlmIHRoZSBwYXJzZSBmYWlscwoJCQkvLyBzbywgc2ltcGxlIHZhbHVlcyBzdWNoIGFzICIxMHB4IiBhcmUgcGFyc2VkIHRvIEZsb2F0LgoJCQkvLyBjb21wbGV4IHZhbHVlcyBzdWNoIGFzICJyb3RhdGUoMXJhZCkiIGFyZSByZXR1cm5lZCBhcyBpcy4KCQkJcmVzdWx0ID0galF1ZXJ5LmNzcyggdHdlZW4uZWxlbSwgdHdlZW4ucHJvcCwgIiIgKTsKCQkJLy8gRW1wdHkgc3RyaW5ncywgbnVsbCwgdW5kZWZpbmVkIGFuZCAiYXV0byIgYXJlIGNvbnZlcnRlZCB0byAwLgoJCQlyZXR1cm4gIXJlc3VsdCB8fCByZXN1bHQgPT09ICJhdXRvIiA/IDAgOiByZXN1bHQ7CgkJfSwKCQlzZXQ6IGZ1bmN0aW9uKCB0d2VlbiApIHsKCQkJLy8gdXNlIHN0ZXAgaG9vayBmb3IgYmFjayBjb21wYXQgLSB1c2UgY3NzSG9vayBpZiBpdHMgdGhlcmUgLSB1c2UgLnN0eWxlIGlmIGl0cwoJCQkvLyBhdmFpbGFibGUgYW5kIHVzZSBwbGFpbiBwcm9wZXJ0aWVzIHdoZXJlIGF2YWlsYWJsZQoJCQlpZiAoIGpRdWVyeS5meC5zdGVwWyB0d2Vlbi5wcm9wIF0gKSB7CgkJCQlqUXVlcnkuZnguc3RlcFsgdHdlZW4ucHJvcCBdKCB0d2VlbiApOwoJCQl9IGVsc2UgaWYgKCB0d2Vlbi5lbGVtLnN0eWxlICYmICggdHdlZW4uZWxlbS5zdHlsZVsgalF1ZXJ5LmNzc1Byb3BzWyB0d2Vlbi5wcm9wIF0gXSAhPSBudWxsIHx8IGpRdWVyeS5jc3NIb29rc1sgdHdlZW4ucHJvcCBdICkgKSB7CgkJCQlqUXVlcnkuc3R5bGUoIHR3ZWVuLmVsZW0sIHR3ZWVuLnByb3AsIHR3ZWVuLm5vdyArIHR3ZWVuLnVuaXQgKTsKCQkJfSBlbHNlIHsKCQkJCXR3ZWVuLmVsZW1bIHR3ZWVuLnByb3AgXSA9IHR3ZWVuLm5vdzsKCQkJfQoJCX0KCX0KfTsKCi8vIFN1cHBvcnQ6IElFOQovLyBQYW5pYyBiYXNlZCBhcHByb2FjaCB0byBzZXR0aW5nIHRoaW5ncyBvbiBkaXNjb25uZWN0ZWQgbm9kZXMKClR3ZWVuLnByb3BIb29rcy5zY3JvbGxUb3AgPSBUd2Vlbi5wcm9wSG9va3Muc2Nyb2xsTGVmdCA9IHsKCXNldDogZnVuY3Rpb24oIHR3ZWVuICkgewoJCWlmICggdHdlZW4uZWxlbS5ub2RlVHlwZSAmJiB0d2Vlbi5lbGVtLnBhcmVudE5vZGUgKSB7CgkJCXR3ZWVuLmVsZW1bIHR3ZWVuLnByb3AgXSA9IHR3ZWVuLm5vdzsKCQl9Cgl9Cn07CgpqUXVlcnkuZWFzaW5nID0gewoJbGluZWFyOiBmdW5jdGlvbiggcCApIHsKCQlyZXR1cm4gcDsKCX0sCglzd2luZzogZnVuY3Rpb24oIHAgKSB7CgkJcmV0dXJuIDAuNSAtIE1hdGguY29zKCBwICogTWF0aC5QSSApIC8gMjsKCX0KfTsKCmpRdWVyeS5meCA9IFR3ZWVuLnByb3RvdHlwZS5pbml0OwoKLy8gQmFjayBDb21wYXQgPDEuOCBleHRlbnNpb24gcG9pbnQKalF1ZXJ5LmZ4LnN0ZXAgPSB7fTsKCgoKCnZhcgoJZnhOb3csIHRpbWVySWQsCglyZnh0eXBlcyA9IC9eKD86dG9nZ2xlfHNob3d8aGlkZSkkLywKCXJmeG51bSA9IG5ldyBSZWdFeHAoICJeKD86KFsrLV0pPXwpKCIgKyBwbnVtICsgIikoW2EteiVdKikkIiwgImkiICksCglycnVuID0gL3F1ZXVlSG9va3MkLywKCWFuaW1hdGlvblByZWZpbHRlcnMgPSBbIGRlZmF1bHRQcmVmaWx0ZXIgXSwKCXR3ZWVuZXJzID0gewoJCSIqIjogWyBmdW5jdGlvbiggcHJvcCwgdmFsdWUgKSB7CgkJCXZhciB0d2VlbiA9IHRoaXMuY3JlYXRlVHdlZW4oIHByb3AsIHZhbHVlICksCgkJCQl0YXJnZXQgPSB0d2Vlbi5jdXIoKSwKCQkJCXBhcnRzID0gcmZ4bnVtLmV4ZWMoIHZhbHVlICksCgkJCQl1bml0ID0gcGFydHMgJiYgcGFydHNbIDMgXSB8fCAoIGpRdWVyeS5jc3NOdW1iZXJbIHByb3AgXSA/ICIiIDogInB4IiApLAoKCQkJCS8vIFN0YXJ0aW5nIHZhbHVlIGNvbXB1dGF0aW9uIGlzIHJlcXVpcmVkIGZvciBwb3RlbnRpYWwgdW5pdCBtaXNtYXRjaGVzCgkJCQlzdGFydCA9ICggalF1ZXJ5LmNzc051bWJlclsgcHJvcCBdIHx8IHVuaXQgIT09ICJweCIgJiYgK3RhcmdldCApICYmCgkJCQkJcmZ4bnVtLmV4ZWMoIGpRdWVyeS5jc3MoIHR3ZWVuLmVsZW0sIHByb3AgKSApLAoJCQkJc2NhbGUgPSAxLAoJCQkJbWF4SXRlcmF0aW9ucyA9IDIwOwoKCQkJaWYgKCBzdGFydCAmJiBzdGFydFsgMyBdICE9PSB1bml0ICkgewoJCQkJLy8gVHJ1c3QgdW5pdHMgcmVwb3J0ZWQgYnkgalF1ZXJ5LmNzcwoJCQkJdW5pdCA9IHVuaXQgfHwgc3RhcnRbIDMgXTsKCgkJCQkvLyBNYWtlIHN1cmUgd2UgdXBkYXRlIHRoZSB0d2VlbiBwcm9wZXJ0aWVzIGxhdGVyIG9uCgkJCQlwYXJ0cyA9IHBhcnRzIHx8IFtdOwoKCQkJCS8vIEl0ZXJhdGl2ZWx5IGFwcHJveGltYXRlIGZyb20gYSBub256ZXJvIHN0YXJ0aW5nIHBvaW50CgkJCQlzdGFydCA9ICt0YXJnZXQgfHwgMTsKCgkJCQlkbyB7CgkJCQkJLy8gSWYgcHJldmlvdXMgaXRlcmF0aW9uIHplcm9lZCBvdXQsIGRvdWJsZSB1bnRpbCB3ZSBnZXQgKnNvbWV0aGluZyoKCQkJCQkvLyBVc2UgYSBzdHJpbmcgZm9yIGRvdWJsaW5nIGZhY3RvciBzbyB3ZSBkb24ndCBhY2NpZGVudGFsbHkgc2VlIHNjYWxlIGFzIHVuY2hhbmdlZCBiZWxvdwoJCQkJCXNjYWxlID0gc2NhbGUgfHwgIi41IjsKCgkJCQkJLy8gQWRqdXN0IGFuZCBhcHBseQoJCQkJCXN0YXJ0ID0gc3RhcnQgLyBzY2FsZTsKCQkJCQlqUXVlcnkuc3R5bGUoIHR3ZWVuLmVsZW0sIHByb3AsIHN0YXJ0ICsgdW5pdCApOwoKCQkJCS8vIFVwZGF0ZSBzY2FsZSwgdG9sZXJhdGluZyB6ZXJvIG9yIE5hTiBmcm9tIHR3ZWVuLmN1cigpCgkJCQkvLyBBbmQgYnJlYWtpbmcgdGhlIGxvb3AgaWYgc2NhbGUgaXMgdW5jaGFuZ2VkIG9yIHBlcmZlY3QsIG9yIGlmIHdlJ3ZlIGp1c3QgaGFkIGVub3VnaAoJCQkJfSB3aGlsZSAoIHNjYWxlICE9PSAoc2NhbGUgPSB0d2Vlbi5jdXIoKSAvIHRhcmdldCkgJiYgc2NhbGUgIT09IDEgJiYgLS1tYXhJdGVyYXRpb25zICk7CgkJCX0KCgkJCS8vIFVwZGF0ZSB0d2VlbiBwcm9wZXJ0aWVzCgkJCWlmICggcGFydHMgKSB7CgkJCQlzdGFydCA9IHR3ZWVuLnN0YXJ0ID0gK3N0YXJ0IHx8ICt0YXJnZXQgfHwgMDsKCQkJCXR3ZWVuLnVuaXQgPSB1bml0OwoJCQkJLy8gSWYgYSArPS8tPSB0b2tlbiB3YXMgcHJvdmlkZWQsIHdlJ3JlIGRvaW5nIGEgcmVsYXRpdmUgYW5pbWF0aW9uCgkJCQl0d2Vlbi5lbmQgPSBwYXJ0c1sgMSBdID8KCQkJCQlzdGFydCArICggcGFydHNbIDEgXSArIDEgKSAqIHBhcnRzWyAyIF0gOgoJCQkJCStwYXJ0c1sgMiBdOwoJCQl9CgoJCQlyZXR1cm4gdHdlZW47CgkJfSBdCgl9OwoKLy8gQW5pbWF0aW9ucyBjcmVhdGVkIHN5bmNocm9ub3VzbHkgd2lsbCBydW4gc3luY2hyb25vdXNseQpmdW5jdGlvbiBjcmVhdGVGeE5vdygpIHsKCXNldFRpbWVvdXQoZnVuY3Rpb24oKSB7CgkJZnhOb3cgPSB1bmRlZmluZWQ7Cgl9KTsKCXJldHVybiAoIGZ4Tm93ID0galF1ZXJ5Lm5vdygpICk7Cn0KCi8vIEdlbmVyYXRlIHBhcmFtZXRlcnMgdG8gY3JlYXRlIGEgc3RhbmRhcmQgYW5pbWF0aW9uCmZ1bmN0aW9uIGdlbkZ4KCB0eXBlLCBpbmNsdWRlV2lkdGggKSB7Cgl2YXIgd2hpY2gsCgkJaSA9IDAsCgkJYXR0cnMgPSB7IGhlaWdodDogdHlwZSB9OwoKCS8vIGlmIHdlIGluY2x1ZGUgd2lkdGgsIHN0ZXAgdmFsdWUgaXMgMSB0byBkbyBhbGwgY3NzRXhwYW5kIHZhbHVlcywKCS8vIGlmIHdlIGRvbid0IGluY2x1ZGUgd2lkdGgsIHN0ZXAgdmFsdWUgaXMgMiB0byBza2lwIG92ZXIgTGVmdCBhbmQgUmlnaHQKCWluY2x1ZGVXaWR0aCA9IGluY2x1ZGVXaWR0aCA/IDEgOiAwOwoJZm9yICggOyBpIDwgNCA7IGkgKz0gMiAtIGluY2x1ZGVXaWR0aCApIHsKCQl3aGljaCA9IGNzc0V4cGFuZFsgaSBdOwoJCWF0dHJzWyAibWFyZ2luIiArIHdoaWNoIF0gPSBhdHRyc1sgInBhZGRpbmciICsgd2hpY2ggXSA9IHR5cGU7Cgl9CgoJaWYgKCBpbmNsdWRlV2lkdGggKSB7CgkJYXR0cnMub3BhY2l0eSA9IGF0dHJzLndpZHRoID0gdHlwZTsKCX0KCglyZXR1cm4gYXR0cnM7Cn0KCmZ1bmN0aW9uIGNyZWF0ZVR3ZWVuKCB2YWx1ZSwgcHJvcCwgYW5pbWF0aW9uICkgewoJdmFyIHR3ZWVuLAoJCWNvbGxlY3Rpb24gPSAoIHR3ZWVuZXJzWyBwcm9wIF0gfHwgW10gKS5jb25jYXQoIHR3ZWVuZXJzWyAiKiIgXSApLAoJCWluZGV4ID0gMCwKCQlsZW5ndGggPSBjb2xsZWN0aW9uLmxlbmd0aDsKCWZvciAoIDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KysgKSB7CgkJaWYgKCAodHdlZW4gPSBjb2xsZWN0aW9uWyBpbmRleCBdLmNhbGwoIGFuaW1hdGlvbiwgcHJvcCwgdmFsdWUgKSkgKSB7CgoJCQkvLyB3ZSdyZSBkb25lIHdpdGggdGhpcyBwcm9wZXJ0eQoJCQlyZXR1cm4gdHdlZW47CgkJfQoJfQp9CgpmdW5jdGlvbiBkZWZhdWx0UHJlZmlsdGVyKCBlbGVtLCBwcm9wcywgb3B0cyApIHsKCS8qIGpzaGludCB2YWxpZHRoaXM6IHRydWUgKi8KCXZhciBwcm9wLCB2YWx1ZSwgdG9nZ2xlLCB0d2VlbiwgaG9va3MsIG9sZGZpcmUsIGRpc3BsYXksIGNoZWNrRGlzcGxheSwKCQlhbmltID0gdGhpcywKCQlvcmlnID0ge30sCgkJc3R5bGUgPSBlbGVtLnN0eWxlLAoJCWhpZGRlbiA9IGVsZW0ubm9kZVR5cGUgJiYgaXNIaWRkZW4oIGVsZW0gKSwKCQlkYXRhU2hvdyA9IGRhdGFfcHJpdi5nZXQoIGVsZW0sICJmeHNob3ciICk7CgoJLy8gaGFuZGxlIHF1ZXVlOiBmYWxzZSBwcm9taXNlcwoJaWYgKCAhb3B0cy5xdWV1ZSApIHsKCQlob29rcyA9IGpRdWVyeS5fcXVldWVIb29rcyggZWxlbSwgImZ4IiApOwoJCWlmICggaG9va3MudW5xdWV1ZWQgPT0gbnVsbCApIHsKCQkJaG9va3MudW5xdWV1ZWQgPSAwOwoJCQlvbGRmaXJlID0gaG9va3MuZW1wdHkuZmlyZTsKCQkJaG9va3MuZW1wdHkuZmlyZSA9IGZ1bmN0aW9uKCkgewoJCQkJaWYgKCAhaG9va3MudW5xdWV1ZWQgKSB7CgkJCQkJb2xkZmlyZSgpOwoJCQkJfQoJCQl9OwoJCX0KCQlob29rcy51bnF1ZXVlZCsrOwoKCQlhbmltLmFsd2F5cyhmdW5jdGlvbigpIHsKCQkJLy8gZG9pbmcgdGhpcyBtYWtlcyBzdXJlIHRoYXQgdGhlIGNvbXBsZXRlIGhhbmRsZXIgd2lsbCBiZSBjYWxsZWQKCQkJLy8gYmVmb3JlIHRoaXMgY29tcGxldGVzCgkJCWFuaW0uYWx3YXlzKGZ1bmN0aW9uKCkgewoJCQkJaG9va3MudW5xdWV1ZWQtLTsKCQkJCWlmICggIWpRdWVyeS5xdWV1ZSggZWxlbSwgImZ4IiApLmxlbmd0aCApIHsKCQkJCQlob29rcy5lbXB0eS5maXJlKCk7CgkJCQl9CgkJCX0pOwoJCX0pOwoJfQoKCS8vIGhlaWdodC93aWR0aCBvdmVyZmxvdyBwYXNzCglpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgJiYgKCAiaGVpZ2h0IiBpbiBwcm9wcyB8fCAid2lkdGgiIGluIHByb3BzICkgKSB7CgkJLy8gTWFrZSBzdXJlIHRoYXQgbm90aGluZyBzbmVha3Mgb3V0CgkJLy8gUmVjb3JkIGFsbCAzIG92ZXJmbG93IGF0dHJpYnV0ZXMgYmVjYXVzZSBJRTktMTAgZG8gbm90CgkJLy8gY2hhbmdlIHRoZSBvdmVyZmxvdyBhdHRyaWJ1dGUgd2hlbiBvdmVyZmxvd1ggYW5kCgkJLy8gb3ZlcmZsb3dZIGFyZSBzZXQgdG8gdGhlIHNhbWUgdmFsdWUKCQlvcHRzLm92ZXJmbG93ID0gWyBzdHlsZS5vdmVyZmxvdywgc3R5bGUub3ZlcmZsb3dYLCBzdHlsZS5vdmVyZmxvd1kgXTsKCgkJLy8gU2V0IGRpc3BsYXkgcHJvcGVydHkgdG8gaW5saW5lLWJsb2NrIGZvciBoZWlnaHQvd2lkdGgKCQkvLyBhbmltYXRpb25zIG9uIGlubGluZSBlbGVtZW50cyB0aGF0IGFyZSBoYXZpbmcgd2lkdGgvaGVpZ2h0IGFuaW1hdGVkCgkJZGlzcGxheSA9IGpRdWVyeS5jc3MoIGVsZW0sICJkaXNwbGF5IiApOwoKCQkvLyBUZXN0IGRlZmF1bHQgZGlzcGxheSBpZiBkaXNwbGF5IGlzIGN1cnJlbnRseSAibm9uZSIKCQljaGVja0Rpc3BsYXkgPSBkaXNwbGF5ID09PSAibm9uZSIgPwoJCQlkYXRhX3ByaXYuZ2V0KCBlbGVtLCAib2xkZGlzcGxheSIgKSB8fCBkZWZhdWx0RGlzcGxheSggZWxlbS5ub2RlTmFtZSApIDogZGlzcGxheTsKCgkJaWYgKCBjaGVja0Rpc3BsYXkgPT09ICJpbmxpbmUiICYmIGpRdWVyeS5jc3MoIGVsZW0sICJmbG9hdCIgKSA9PT0gIm5vbmUiICkgewoJCQlzdHlsZS5kaXNwbGF5ID0gImlubGluZS1ibG9jayI7CgkJfQoJfQoKCWlmICggb3B0cy5vdmVyZmxvdyApIHsKCQlzdHlsZS5vdmVyZmxvdyA9ICJoaWRkZW4iOwoJCWFuaW0uYWx3YXlzKGZ1bmN0aW9uKCkgewoJCQlzdHlsZS5vdmVyZmxvdyA9IG9wdHMub3ZlcmZsb3dbIDAgXTsKCQkJc3R5bGUub3ZlcmZsb3dYID0gb3B0cy5vdmVyZmxvd1sgMSBdOwoJCQlzdHlsZS5vdmVyZmxvd1kgPSBvcHRzLm92ZXJmbG93WyAyIF07CgkJfSk7Cgl9CgoJLy8gc2hvdy9oaWRlIHBhc3MKCWZvciAoIHByb3AgaW4gcHJvcHMgKSB7CgkJdmFsdWUgPSBwcm9wc1sgcHJvcCBdOwoJCWlmICggcmZ4dHlwZXMuZXhlYyggdmFsdWUgKSApIHsKCQkJZGVsZXRlIHByb3BzWyBwcm9wIF07CgkJCXRvZ2dsZSA9IHRvZ2dsZSB8fCB2YWx1ZSA9PT0gInRvZ2dsZSI7CgkJCWlmICggdmFsdWUgPT09ICggaGlkZGVuID8gImhpZGUiIDogInNob3ciICkgKSB7CgoJCQkJLy8gSWYgdGhlcmUgaXMgZGF0YVNob3cgbGVmdCBvdmVyIGZyb20gYSBzdG9wcGVkIGhpZGUgb3Igc2hvdyBhbmQgd2UgYXJlIGdvaW5nIHRvIHByb2NlZWQgd2l0aCBzaG93LCB3ZSBzaG91bGQgcHJldGVuZCB0byBiZSBoaWRkZW4KCQkJCWlmICggdmFsdWUgPT09ICJzaG93IiAmJiBkYXRhU2hvdyAmJiBkYXRhU2hvd1sgcHJvcCBdICE9PSB1bmRlZmluZWQgKSB7CgkJCQkJaGlkZGVuID0gdHJ1ZTsKCQkJCX0gZWxzZSB7CgkJCQkJY29udGludWU7CgkJCQl9CgkJCX0KCQkJb3JpZ1sgcHJvcCBdID0gZGF0YVNob3cgJiYgZGF0YVNob3dbIHByb3AgXSB8fCBqUXVlcnkuc3R5bGUoIGVsZW0sIHByb3AgKTsKCgkJLy8gQW55IG5vbi1meCB2YWx1ZSBzdG9wcyB1cyBmcm9tIHJlc3RvcmluZyB0aGUgb3JpZ2luYWwgZGlzcGxheSB2YWx1ZQoJCX0gZWxzZSB7CgkJCWRpc3BsYXkgPSB1bmRlZmluZWQ7CgkJfQoJfQoKCWlmICggIWpRdWVyeS5pc0VtcHR5T2JqZWN0KCBvcmlnICkgKSB7CgkJaWYgKCBkYXRhU2hvdyApIHsKCQkJaWYgKCAiaGlkZGVuIiBpbiBkYXRhU2hvdyApIHsKCQkJCWhpZGRlbiA9IGRhdGFTaG93LmhpZGRlbjsKCQkJfQoJCX0gZWxzZSB7CgkJCWRhdGFTaG93ID0gZGF0YV9wcml2LmFjY2VzcyggZWxlbSwgImZ4c2hvdyIsIHt9ICk7CgkJfQoKCQkvLyBzdG9yZSBzdGF0ZSBpZiBpdHMgdG9nZ2xlIC0gZW5hYmxlcyAuc3RvcCgpLnRvZ2dsZSgpIHRvICJyZXZlcnNlIgoJCWlmICggdG9nZ2xlICkgewoJCQlkYXRhU2hvdy5oaWRkZW4gPSAhaGlkZGVuOwoJCX0KCQlpZiAoIGhpZGRlbiApIHsKCQkJalF1ZXJ5KCBlbGVtICkuc2hvdygpOwoJCX0gZWxzZSB7CgkJCWFuaW0uZG9uZShmdW5jdGlvbigpIHsKCQkJCWpRdWVyeSggZWxlbSApLmhpZGUoKTsKCQkJfSk7CgkJfQoJCWFuaW0uZG9uZShmdW5jdGlvbigpIHsKCQkJdmFyIHByb3A7CgoJCQlkYXRhX3ByaXYucmVtb3ZlKCBlbGVtLCAiZnhzaG93IiApOwoJCQlmb3IgKCBwcm9wIGluIG9yaWcgKSB7CgkJCQlqUXVlcnkuc3R5bGUoIGVsZW0sIHByb3AsIG9yaWdbIHByb3AgXSApOwoJCQl9CgkJfSk7CgkJZm9yICggcHJvcCBpbiBvcmlnICkgewoJCQl0d2VlbiA9IGNyZWF0ZVR3ZWVuKCBoaWRkZW4gPyBkYXRhU2hvd1sgcHJvcCBdIDogMCwgcHJvcCwgYW5pbSApOwoKCQkJaWYgKCAhKCBwcm9wIGluIGRhdGFTaG93ICkgKSB7CgkJCQlkYXRhU2hvd1sgcHJvcCBdID0gdHdlZW4uc3RhcnQ7CgkJCQlpZiAoIGhpZGRlbiApIHsKCQkJCQl0d2Vlbi5lbmQgPSB0d2Vlbi5zdGFydDsKCQkJCQl0d2Vlbi5zdGFydCA9IHByb3AgPT09ICJ3aWR0aCIgfHwgcHJvcCA9PT0gImhlaWdodCIgPyAxIDogMDsKCQkJCX0KCQkJfQoJCX0KCgkvLyBJZiB0aGlzIGlzIGEgbm9vcCBsaWtlIC5oaWRlKCkuaGlkZSgpLCByZXN0b3JlIGFuIG92ZXJ3cml0dGVuIGRpc3BsYXkgdmFsdWUKCX0gZWxzZSBpZiAoIChkaXNwbGF5ID09PSAibm9uZSIgPyBkZWZhdWx0RGlzcGxheSggZWxlbS5ub2RlTmFtZSApIDogZGlzcGxheSkgPT09ICJpbmxpbmUiICkgewoJCXN0eWxlLmRpc3BsYXkgPSBkaXNwbGF5OwoJfQp9CgpmdW5jdGlvbiBwcm9wRmlsdGVyKCBwcm9wcywgc3BlY2lhbEVhc2luZyApIHsKCXZhciBpbmRleCwgbmFtZSwgZWFzaW5nLCB2YWx1ZSwgaG9va3M7CgoJLy8gY2FtZWxDYXNlLCBzcGVjaWFsRWFzaW5nIGFuZCBleHBhbmQgY3NzSG9vayBwYXNzCglmb3IgKCBpbmRleCBpbiBwcm9wcyApIHsKCQluYW1lID0galF1ZXJ5LmNhbWVsQ2FzZSggaW5kZXggKTsKCQllYXNpbmcgPSBzcGVjaWFsRWFzaW5nWyBuYW1lIF07CgkJdmFsdWUgPSBwcm9wc1sgaW5kZXggXTsKCQlpZiAoIGpRdWVyeS5pc0FycmF5KCB2YWx1ZSApICkgewoJCQllYXNpbmcgPSB2YWx1ZVsgMSBdOwoJCQl2YWx1ZSA9IHByb3BzWyBpbmRleCBdID0gdmFsdWVbIDAgXTsKCQl9CgoJCWlmICggaW5kZXggIT09IG5hbWUgKSB7CgkJCXByb3BzWyBuYW1lIF0gPSB2YWx1ZTsKCQkJZGVsZXRlIHByb3BzWyBpbmRleCBdOwoJCX0KCgkJaG9va3MgPSBqUXVlcnkuY3NzSG9va3NbIG5hbWUgXTsKCQlpZiAoIGhvb2tzICYmICJleHBhbmQiIGluIGhvb2tzICkgewoJCQl2YWx1ZSA9IGhvb2tzLmV4cGFuZCggdmFsdWUgKTsKCQkJZGVsZXRlIHByb3BzWyBuYW1lIF07CgoJCQkvLyBub3QgcXVpdGUgJC5leHRlbmQsIHRoaXMgd29udCBvdmVyd3JpdGUga2V5cyBhbHJlYWR5IHByZXNlbnQuCgkJCS8vIGFsc28gLSByZXVzaW5nICdpbmRleCcgZnJvbSBhYm92ZSBiZWNhdXNlIHdlIGhhdmUgdGhlIGNvcnJlY3QgIm5hbWUiCgkJCWZvciAoIGluZGV4IGluIHZhbHVlICkgewoJCQkJaWYgKCAhKCBpbmRleCBpbiBwcm9wcyApICkgewoJCQkJCXByb3BzWyBpbmRleCBdID0gdmFsdWVbIGluZGV4IF07CgkJCQkJc3BlY2lhbEVhc2luZ1sgaW5kZXggXSA9IGVhc2luZzsKCQkJCX0KCQkJfQoJCX0gZWxzZSB7CgkJCXNwZWNpYWxFYXNpbmdbIG5hbWUgXSA9IGVhc2luZzsKCQl9Cgl9Cn0KCmZ1bmN0aW9uIEFuaW1hdGlvbiggZWxlbSwgcHJvcGVydGllcywgb3B0aW9ucyApIHsKCXZhciByZXN1bHQsCgkJc3RvcHBlZCwKCQlpbmRleCA9IDAsCgkJbGVuZ3RoID0gYW5pbWF0aW9uUHJlZmlsdGVycy5sZW5ndGgsCgkJZGVmZXJyZWQgPSBqUXVlcnkuRGVmZXJyZWQoKS5hbHdheXMoIGZ1bmN0aW9uKCkgewoJCQkvLyBkb24ndCBtYXRjaCBlbGVtIGluIHRoZSA6YW5pbWF0ZWQgc2VsZWN0b3IKCQkJZGVsZXRlIHRpY2suZWxlbTsKCQl9KSwKCQl0aWNrID0gZnVuY3Rpb24oKSB7CgkJCWlmICggc3RvcHBlZCApIHsKCQkJCXJldHVybiBmYWxzZTsKCQkJfQoJCQl2YXIgY3VycmVudFRpbWUgPSBmeE5vdyB8fCBjcmVhdGVGeE5vdygpLAoJCQkJcmVtYWluaW5nID0gTWF0aC5tYXgoIDAsIGFuaW1hdGlvbi5zdGFydFRpbWUgKyBhbmltYXRpb24uZHVyYXRpb24gLSBjdXJyZW50VGltZSApLAoJCQkJLy8gYXJjaGFpYyBjcmFzaCBidWcgd29uJ3QgYWxsb3cgdXMgdG8gdXNlIDEgLSAoIDAuNSB8fCAwICkgKCMxMjQ5NykKCQkJCXRlbXAgPSByZW1haW5pbmcgLyBhbmltYXRpb24uZHVyYXRpb24gfHwgMCwKCQkJCXBlcmNlbnQgPSAxIC0gdGVtcCwKCQkJCWluZGV4ID0gMCwKCQkJCWxlbmd0aCA9IGFuaW1hdGlvbi50d2VlbnMubGVuZ3RoOwoKCQkJZm9yICggOyBpbmRleCA8IGxlbmd0aCA7IGluZGV4KysgKSB7CgkJCQlhbmltYXRpb24udHdlZW5zWyBpbmRleCBdLnJ1biggcGVyY2VudCApOwoJCQl9CgoJCQlkZWZlcnJlZC5ub3RpZnlXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgcGVyY2VudCwgcmVtYWluaW5nIF0pOwoKCQkJaWYgKCBwZXJjZW50IDwgMSAmJiBsZW5ndGggKSB7CgkJCQlyZXR1cm4gcmVtYWluaW5nOwoJCQl9IGVsc2UgewoJCQkJZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGVsZW0sIFsgYW5pbWF0aW9uIF0gKTsKCQkJCXJldHVybiBmYWxzZTsKCQkJfQoJCX0sCgkJYW5pbWF0aW9uID0gZGVmZXJyZWQucHJvbWlzZSh7CgkJCWVsZW06IGVsZW0sCgkJCXByb3BzOiBqUXVlcnkuZXh0ZW5kKCB7fSwgcHJvcGVydGllcyApLAoJCQlvcHRzOiBqUXVlcnkuZXh0ZW5kKCB0cnVlLCB7IHNwZWNpYWxFYXNpbmc6IHt9IH0sIG9wdGlvbnMgKSwKCQkJb3JpZ2luYWxQcm9wZXJ0aWVzOiBwcm9wZXJ0aWVzLAoJCQlvcmlnaW5hbE9wdGlvbnM6IG9wdGlvbnMsCgkJCXN0YXJ0VGltZTogZnhOb3cgfHwgY3JlYXRlRnhOb3coKSwKCQkJZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sCgkJCXR3ZWVuczogW10sCgkJCWNyZWF0ZVR3ZWVuOiBmdW5jdGlvbiggcHJvcCwgZW5kICkgewoJCQkJdmFyIHR3ZWVuID0galF1ZXJ5LlR3ZWVuKCBlbGVtLCBhbmltYXRpb24ub3B0cywgcHJvcCwgZW5kLAoJCQkJCQlhbmltYXRpb24ub3B0cy5zcGVjaWFsRWFzaW5nWyBwcm9wIF0gfHwgYW5pbWF0aW9uLm9wdHMuZWFzaW5nICk7CgkJCQlhbmltYXRpb24udHdlZW5zLnB1c2goIHR3ZWVuICk7CgkJCQlyZXR1cm4gdHdlZW47CgkJCX0sCgkJCXN0b3A6IGZ1bmN0aW9uKCBnb3RvRW5kICkgewoJCQkJdmFyIGluZGV4ID0gMCwKCQkJCQkvLyBpZiB3ZSBhcmUgZ29pbmcgdG8gdGhlIGVuZCwgd2Ugd2FudCB0byBydW4gYWxsIHRoZSB0d2VlbnMKCQkJCQkvLyBvdGhlcndpc2Ugd2Ugc2tpcCB0aGlzIHBhcnQKCQkJCQlsZW5ndGggPSBnb3RvRW5kID8gYW5pbWF0aW9uLnR3ZWVucy5sZW5ndGggOiAwOwoJCQkJaWYgKCBzdG9wcGVkICkgewoJCQkJCXJldHVybiB0aGlzOwoJCQkJfQoJCQkJc3RvcHBlZCA9IHRydWU7CgkJCQlmb3IgKCA7IGluZGV4IDwgbGVuZ3RoIDsgaW5kZXgrKyApIHsKCQkJCQlhbmltYXRpb24udHdlZW5zWyBpbmRleCBdLnJ1biggMSApOwoJCQkJfQoKCQkJCS8vIHJlc29sdmUgd2hlbiB3ZSBwbGF5ZWQgdGhlIGxhc3QgZnJhbWUKCQkJCS8vIG90aGVyd2lzZSwgcmVqZWN0CgkJCQlpZiAoIGdvdG9FbmQgKSB7CgkJCQkJZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGVsZW0sIFsgYW5pbWF0aW9uLCBnb3RvRW5kIF0gKTsKCQkJCX0gZWxzZSB7CgkJCQkJZGVmZXJyZWQucmVqZWN0V2l0aCggZWxlbSwgWyBhbmltYXRpb24sIGdvdG9FbmQgXSApOwoJCQkJfQoJCQkJcmV0dXJuIHRoaXM7CgkJCX0KCQl9KSwKCQlwcm9wcyA9IGFuaW1hdGlvbi5wcm9wczsKCglwcm9wRmlsdGVyKCBwcm9wcywgYW5pbWF0aW9uLm9wdHMuc3BlY2lhbEVhc2luZyApOwoKCWZvciAoIDsgaW5kZXggPCBsZW5ndGggOyBpbmRleCsrICkgewoJCXJlc3VsdCA9IGFuaW1hdGlvblByZWZpbHRlcnNbIGluZGV4IF0uY2FsbCggYW5pbWF0aW9uLCBlbGVtLCBwcm9wcywgYW5pbWF0aW9uLm9wdHMgKTsKCQlpZiAoIHJlc3VsdCApIHsKCQkJcmV0dXJuIHJlc3VsdDsKCQl9Cgl9CgoJalF1ZXJ5Lm1hcCggcHJvcHMsIGNyZWF0ZVR3ZWVuLCBhbmltYXRpb24gKTsKCglpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBhbmltYXRpb24ub3B0cy5zdGFydCApICkgewoJCWFuaW1hdGlvbi5vcHRzLnN0YXJ0LmNhbGwoIGVsZW0sIGFuaW1hdGlvbiApOwoJfQoKCWpRdWVyeS5meC50aW1lcigKCQlqUXVlcnkuZXh0ZW5kKCB0aWNrLCB7CgkJCWVsZW06IGVsZW0sCgkJCWFuaW06IGFuaW1hdGlvbiwKCQkJcXVldWU6IGFuaW1hdGlvbi5vcHRzLnF1ZXVlCgkJfSkKCSk7CgoJLy8gYXR0YWNoIGNhbGxiYWNrcyBmcm9tIG9wdGlvbnMKCXJldHVybiBhbmltYXRpb24ucHJvZ3Jlc3MoIGFuaW1hdGlvbi5vcHRzLnByb2dyZXNzICkKCQkuZG9uZSggYW5pbWF0aW9uLm9wdHMuZG9uZSwgYW5pbWF0aW9uLm9wdHMuY29tcGxldGUgKQoJCS5mYWlsKCBhbmltYXRpb24ub3B0cy5mYWlsICkKCQkuYWx3YXlzKCBhbmltYXRpb24ub3B0cy5hbHdheXMgKTsKfQoKalF1ZXJ5LkFuaW1hdGlvbiA9IGpRdWVyeS5leHRlbmQoIEFuaW1hdGlvbiwgewoKCXR3ZWVuZXI6IGZ1bmN0aW9uKCBwcm9wcywgY2FsbGJhY2sgKSB7CgkJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggcHJvcHMgKSApIHsKCQkJY2FsbGJhY2sgPSBwcm9wczsKCQkJcHJvcHMgPSBbICIqIiBdOwoJCX0gZWxzZSB7CgkJCXByb3BzID0gcHJvcHMuc3BsaXQoIiAiKTsKCQl9CgoJCXZhciBwcm9wLAoJCQlpbmRleCA9IDAsCgkJCWxlbmd0aCA9IHByb3BzLmxlbmd0aDsKCgkJZm9yICggOyBpbmRleCA8IGxlbmd0aCA7IGluZGV4KysgKSB7CgkJCXByb3AgPSBwcm9wc1sgaW5kZXggXTsKCQkJdHdlZW5lcnNbIHByb3AgXSA9IHR3ZWVuZXJzWyBwcm9wIF0gfHwgW107CgkJCXR3ZWVuZXJzWyBwcm9wIF0udW5zaGlmdCggY2FsbGJhY2sgKTsKCQl9Cgl9LAoKCXByZWZpbHRlcjogZnVuY3Rpb24oIGNhbGxiYWNrLCBwcmVwZW5kICkgewoJCWlmICggcHJlcGVuZCApIHsKCQkJYW5pbWF0aW9uUHJlZmlsdGVycy51bnNoaWZ0KCBjYWxsYmFjayApOwoJCX0gZWxzZSB7CgkJCWFuaW1hdGlvblByZWZpbHRlcnMucHVzaCggY2FsbGJhY2sgKTsKCQl9Cgl9Cn0pOwoKalF1ZXJ5LnNwZWVkID0gZnVuY3Rpb24oIHNwZWVkLCBlYXNpbmcsIGZuICkgewoJdmFyIG9wdCA9IHNwZWVkICYmIHR5cGVvZiBzcGVlZCA9PT0gIm9iamVjdCIgPyBqUXVlcnkuZXh0ZW5kKCB7fSwgc3BlZWQgKSA6IHsKCQljb21wbGV0ZTogZm4gfHwgIWZuICYmIGVhc2luZyB8fAoJCQlqUXVlcnkuaXNGdW5jdGlvbiggc3BlZWQgKSAmJiBzcGVlZCwKCQlkdXJhdGlvbjogc3BlZWQsCgkJZWFzaW5nOiBmbiAmJiBlYXNpbmcgfHwgZWFzaW5nICYmICFqUXVlcnkuaXNGdW5jdGlvbiggZWFzaW5nICkgJiYgZWFzaW5nCgl9OwoKCW9wdC5kdXJhdGlvbiA9IGpRdWVyeS5meC5vZmYgPyAwIDogdHlwZW9mIG9wdC5kdXJhdGlvbiA9PT0gIm51bWJlciIgPyBvcHQuZHVyYXRpb24gOgoJCW9wdC5kdXJhdGlvbiBpbiBqUXVlcnkuZnguc3BlZWRzID8galF1ZXJ5LmZ4LnNwZWVkc1sgb3B0LmR1cmF0aW9uIF0gOiBqUXVlcnkuZnguc3BlZWRzLl9kZWZhdWx0OwoKCS8vIG5vcm1hbGl6ZSBvcHQucXVldWUgLSB0cnVlL3VuZGVmaW5lZC9udWxsIC0+ICJmeCIKCWlmICggb3B0LnF1ZXVlID09IG51bGwgfHwgb3B0LnF1ZXVlID09PSB0cnVlICkgewoJCW9wdC5xdWV1ZSA9ICJmeCI7Cgl9CgoJLy8gUXVldWVpbmcKCW9wdC5vbGQgPSBvcHQuY29tcGxldGU7CgoJb3B0LmNvbXBsZXRlID0gZnVuY3Rpb24oKSB7CgkJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggb3B0Lm9sZCApICkgewoJCQlvcHQub2xkLmNhbGwoIHRoaXMgKTsKCQl9CgoJCWlmICggb3B0LnF1ZXVlICkgewoJCQlqUXVlcnkuZGVxdWV1ZSggdGhpcywgb3B0LnF1ZXVlICk7CgkJfQoJfTsKCglyZXR1cm4gb3B0Owp9OwoKalF1ZXJ5LmZuLmV4dGVuZCh7CglmYWRlVG86IGZ1bmN0aW9uKCBzcGVlZCwgdG8sIGVhc2luZywgY2FsbGJhY2sgKSB7CgoJCS8vIHNob3cgYW55IGhpZGRlbiBlbGVtZW50cyBhZnRlciBzZXR0aW5nIG9wYWNpdHkgdG8gMAoJCXJldHVybiB0aGlzLmZpbHRlciggaXNIaWRkZW4gKS5jc3MoICJvcGFjaXR5IiwgMCApLnNob3coKQoKCQkJLy8gYW5pbWF0ZSB0byB0aGUgdmFsdWUgc3BlY2lmaWVkCgkJCS5lbmQoKS5hbmltYXRlKHsgb3BhY2l0eTogdG8gfSwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKTsKCX0sCglhbmltYXRlOiBmdW5jdGlvbiggcHJvcCwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7CgkJdmFyIGVtcHR5ID0galF1ZXJ5LmlzRW1wdHlPYmplY3QoIHByb3AgKSwKCQkJb3B0YWxsID0galF1ZXJ5LnNwZWVkKCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApLAoJCQlkb0FuaW1hdGlvbiA9IGZ1bmN0aW9uKCkgewoJCQkJLy8gT3BlcmF0ZSBvbiBhIGNvcHkgb2YgcHJvcCBzbyBwZXItcHJvcGVydHkgZWFzaW5nIHdvbid0IGJlIGxvc3QKCQkJCXZhciBhbmltID0gQW5pbWF0aW9uKCB0aGlzLCBqUXVlcnkuZXh0ZW5kKCB7fSwgcHJvcCApLCBvcHRhbGwgKTsKCgkJCQkvLyBFbXB0eSBhbmltYXRpb25zLCBvciBmaW5pc2hpbmcgcmVzb2x2ZXMgaW1tZWRpYXRlbHkKCQkJCWlmICggZW1wdHkgfHwgZGF0YV9wcml2LmdldCggdGhpcywgImZpbmlzaCIgKSApIHsKCQkJCQlhbmltLnN0b3AoIHRydWUgKTsKCQkJCX0KCQkJfTsKCQkJZG9BbmltYXRpb24uZmluaXNoID0gZG9BbmltYXRpb247CgoJCXJldHVybiBlbXB0eSB8fCBvcHRhbGwucXVldWUgPT09IGZhbHNlID8KCQkJdGhpcy5lYWNoKCBkb0FuaW1hdGlvbiApIDoKCQkJdGhpcy5xdWV1ZSggb3B0YWxsLnF1ZXVlLCBkb0FuaW1hdGlvbiApOwoJfSwKCXN0b3A6IGZ1bmN0aW9uKCB0eXBlLCBjbGVhclF1ZXVlLCBnb3RvRW5kICkgewoJCXZhciBzdG9wUXVldWUgPSBmdW5jdGlvbiggaG9va3MgKSB7CgkJCXZhciBzdG9wID0gaG9va3Muc3RvcDsKCQkJZGVsZXRlIGhvb2tzLnN0b3A7CgkJCXN0b3AoIGdvdG9FbmQgKTsKCQl9OwoKCQlpZiAoIHR5cGVvZiB0eXBlICE9PSAic3RyaW5nIiApIHsKCQkJZ290b0VuZCA9IGNsZWFyUXVldWU7CgkJCWNsZWFyUXVldWUgPSB0eXBlOwoJCQl0eXBlID0gdW5kZWZpbmVkOwoJCX0KCQlpZiAoIGNsZWFyUXVldWUgJiYgdHlwZSAhPT0gZmFsc2UgKSB7CgkJCXRoaXMucXVldWUoIHR5cGUgfHwgImZ4IiwgW10gKTsKCQl9CgoJCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7CgkJCXZhciBkZXF1ZXVlID0gdHJ1ZSwKCQkJCWluZGV4ID0gdHlwZSAhPSBudWxsICYmIHR5cGUgKyAicXVldWVIb29rcyIsCgkJCQl0aW1lcnMgPSBqUXVlcnkudGltZXJzLAoJCQkJZGF0YSA9IGRhdGFfcHJpdi5nZXQoIHRoaXMgKTsKCgkJCWlmICggaW5kZXggKSB7CgkJCQlpZiAoIGRhdGFbIGluZGV4IF0gJiYgZGF0YVsgaW5kZXggXS5zdG9wICkgewoJCQkJCXN0b3BRdWV1ZSggZGF0YVsgaW5kZXggXSApOwoJCQkJfQoJCQl9IGVsc2UgewoJCQkJZm9yICggaW5kZXggaW4gZGF0YSApIHsKCQkJCQlpZiAoIGRhdGFbIGluZGV4IF0gJiYgZGF0YVsgaW5kZXggXS5zdG9wICYmIHJydW4udGVzdCggaW5kZXggKSApIHsKCQkJCQkJc3RvcFF1ZXVlKCBkYXRhWyBpbmRleCBdICk7CgkJCQkJfQoJCQkJfQoJCQl9CgoJCQlmb3IgKCBpbmRleCA9IHRpbWVycy5sZW5ndGg7IGluZGV4LS07ICkgewoJCQkJaWYgKCB0aW1lcnNbIGluZGV4IF0uZWxlbSA9PT0gdGhpcyAmJiAodHlwZSA9PSBudWxsIHx8IHRpbWVyc1sgaW5kZXggXS5xdWV1ZSA9PT0gdHlwZSkgKSB7CgkJCQkJdGltZXJzWyBpbmRleCBdLmFuaW0uc3RvcCggZ290b0VuZCApOwoJCQkJCWRlcXVldWUgPSBmYWxzZTsKCQkJCQl0aW1lcnMuc3BsaWNlKCBpbmRleCwgMSApOwoJCQkJfQoJCQl9CgoJCQkvLyBzdGFydCB0aGUgbmV4dCBpbiB0aGUgcXVldWUgaWYgdGhlIGxhc3Qgc3RlcCB3YXNuJ3QgZm9yY2VkCgkJCS8vIHRpbWVycyBjdXJyZW50bHkgd2lsbCBjYWxsIHRoZWlyIGNvbXBsZXRlIGNhbGxiYWNrcywgd2hpY2ggd2lsbCBkZXF1ZXVlCgkJCS8vIGJ1dCBvbmx5IGlmIHRoZXkgd2VyZSBnb3RvRW5kCgkJCWlmICggZGVxdWV1ZSB8fCAhZ290b0VuZCApIHsKCQkJCWpRdWVyeS5kZXF1ZXVlKCB0aGlzLCB0eXBlICk7CgkJCX0KCQl9KTsKCX0sCglmaW5pc2g6IGZ1bmN0aW9uKCB0eXBlICkgewoJCWlmICggdHlwZSAhPT0gZmFsc2UgKSB7CgkJCXR5cGUgPSB0eXBlIHx8ICJmeCI7CgkJfQoJCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7CgkJCXZhciBpbmRleCwKCQkJCWRhdGEgPSBkYXRhX3ByaXYuZ2V0KCB0aGlzICksCgkJCQlxdWV1ZSA9IGRhdGFbIHR5cGUgKyAicXVldWUiIF0sCgkJCQlob29rcyA9IGRhdGFbIHR5cGUgKyAicXVldWVIb29rcyIgXSwKCQkJCXRpbWVycyA9IGpRdWVyeS50aW1lcnMsCgkJCQlsZW5ndGggPSBxdWV1ZSA/IHF1ZXVlLmxlbmd0aCA6IDA7CgoJCQkvLyBlbmFibGUgZmluaXNoaW5nIGZsYWcgb24gcHJpdmF0ZSBkYXRhCgkJCWRhdGEuZmluaXNoID0gdHJ1ZTsKCgkJCS8vIGVtcHR5IHRoZSBxdWV1ZSBmaXJzdAoJCQlqUXVlcnkucXVldWUoIHRoaXMsIHR5cGUsIFtdICk7CgoJCQlpZiAoIGhvb2tzICYmIGhvb2tzLnN0b3AgKSB7CgkJCQlob29rcy5zdG9wLmNhbGwoIHRoaXMsIHRydWUgKTsKCQkJfQoKCQkJLy8gbG9vayBmb3IgYW55IGFjdGl2ZSBhbmltYXRpb25zLCBhbmQgZmluaXNoIHRoZW0KCQkJZm9yICggaW5kZXggPSB0aW1lcnMubGVuZ3RoOyBpbmRleC0tOyApIHsKCQkJCWlmICggdGltZXJzWyBpbmRleCBdLmVsZW0gPT09IHRoaXMgJiYgdGltZXJzWyBpbmRleCBdLnF1ZXVlID09PSB0eXBlICkgewoJCQkJCXRpbWVyc1sgaW5kZXggXS5hbmltLnN0b3AoIHRydWUgKTsKCQkJCQl0aW1lcnMuc3BsaWNlKCBpbmRleCwgMSApOwoJCQkJfQoJCQl9CgoJCQkvLyBsb29rIGZvciBhbnkgYW5pbWF0aW9ucyBpbiB0aGUgb2xkIHF1ZXVlIGFuZCBmaW5pc2ggdGhlbQoJCQlmb3IgKCBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkgewoJCQkJaWYgKCBxdWV1ZVsgaW5kZXggXSAmJiBxdWV1ZVsgaW5kZXggXS5maW5pc2ggKSB7CgkJCQkJcXVldWVbIGluZGV4IF0uZmluaXNoLmNhbGwoIHRoaXMgKTsKCQkJCX0KCQkJfQoKCQkJLy8gdHVybiBvZmYgZmluaXNoaW5nIGZsYWcKCQkJZGVsZXRlIGRhdGEuZmluaXNoOwoJCX0pOwoJfQp9KTsKCmpRdWVyeS5lYWNoKFsgInRvZ2dsZSIsICJzaG93IiwgImhpZGUiIF0sIGZ1bmN0aW9uKCBpLCBuYW1lICkgewoJdmFyIGNzc0ZuID0galF1ZXJ5LmZuWyBuYW1lIF07CglqUXVlcnkuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHsKCQlyZXR1cm4gc3BlZWQgPT0gbnVsbCB8fCB0eXBlb2Ygc3BlZWQgPT09ICJib29sZWFuIiA/CgkJCWNzc0ZuLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSA6CgkJCXRoaXMuYW5pbWF0ZSggZ2VuRngoIG5hbWUsIHRydWUgKSwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKTsKCX07Cn0pOwoKLy8gR2VuZXJhdGUgc2hvcnRjdXRzIGZvciBjdXN0b20gYW5pbWF0aW9ucwpqUXVlcnkuZWFjaCh7CglzbGlkZURvd246IGdlbkZ4KCJzaG93IiksCglzbGlkZVVwOiBnZW5GeCgiaGlkZSIpLAoJc2xpZGVUb2dnbGU6IGdlbkZ4KCJ0b2dnbGUiKSwKCWZhZGVJbjogeyBvcGFjaXR5OiAic2hvdyIgfSwKCWZhZGVPdXQ6IHsgb3BhY2l0eTogImhpZGUiIH0sCglmYWRlVG9nZ2xlOiB7IG9wYWNpdHk6ICJ0b2dnbGUiIH0KfSwgZnVuY3Rpb24oIG5hbWUsIHByb3BzICkgewoJalF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7CgkJcmV0dXJuIHRoaXMuYW5pbWF0ZSggcHJvcHMsIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7Cgl9Owp9KTsKCmpRdWVyeS50aW1lcnMgPSBbXTsKalF1ZXJ5LmZ4LnRpY2sgPSBmdW5jdGlvbigpIHsKCXZhciB0aW1lciwKCQlpID0gMCwKCQl0aW1lcnMgPSBqUXVlcnkudGltZXJzOwoKCWZ4Tm93ID0galF1ZXJ5Lm5vdygpOwoKCWZvciAoIDsgaSA8IHRpbWVycy5sZW5ndGg7IGkrKyApIHsKCQl0aW1lciA9IHRpbWVyc1sgaSBdOwoJCS8vIENoZWNrcyB0aGUgdGltZXIgaGFzIG5vdCBhbHJlYWR5IGJlZW4gcmVtb3ZlZAoJCWlmICggIXRpbWVyKCkgJiYgdGltZXJzWyBpIF0gPT09IHRpbWVyICkgewoJCQl0aW1lcnMuc3BsaWNlKCBpLS0sIDEgKTsKCQl9Cgl9CgoJaWYgKCAhdGltZXJzLmxlbmd0aCApIHsKCQlqUXVlcnkuZnguc3RvcCgpOwoJfQoJZnhOb3cgPSB1bmRlZmluZWQ7Cn07CgpqUXVlcnkuZngudGltZXIgPSBmdW5jdGlvbiggdGltZXIgKSB7CglqUXVlcnkudGltZXJzLnB1c2goIHRpbWVyICk7CglpZiAoIHRpbWVyKCkgKSB7CgkJalF1ZXJ5LmZ4LnN0YXJ0KCk7Cgl9IGVsc2UgewoJCWpRdWVyeS50aW1lcnMucG9wKCk7Cgl9Cn07CgpqUXVlcnkuZnguaW50ZXJ2YWwgPSAxMzsKCmpRdWVyeS5meC5zdGFydCA9IGZ1bmN0aW9uKCkgewoJaWYgKCAhdGltZXJJZCApIHsKCQl0aW1lcklkID0gc2V0SW50ZXJ2YWwoIGpRdWVyeS5meC50aWNrLCBqUXVlcnkuZnguaW50ZXJ2YWwgKTsKCX0KfTsKCmpRdWVyeS5meC5zdG9wID0gZnVuY3Rpb24oKSB7CgljbGVhckludGVydmFsKCB0aW1lcklkICk7Cgl0aW1lcklkID0gbnVsbDsKfTsKCmpRdWVyeS5meC5zcGVlZHMgPSB7CglzbG93OiA2MDAsCglmYXN0OiAyMDAsCgkvLyBEZWZhdWx0IHNwZWVkCglfZGVmYXVsdDogNDAwCn07CgoKLy8gQmFzZWQgb2ZmIG9mIHRoZSBwbHVnaW4gYnkgQ2xpbnQgSGVsZmVycywgd2l0aCBwZXJtaXNzaW9uLgovLyBodHRwOi8vYmxpbmRzaWduYWxzLmNvbS9pbmRleC5waHAvMjAwOS8wNy9qcXVlcnktZGVsYXkvCmpRdWVyeS5mbi5kZWxheSA9IGZ1bmN0aW9uKCB0aW1lLCB0eXBlICkgewoJdGltZSA9IGpRdWVyeS5meCA/IGpRdWVyeS5meC5zcGVlZHNbIHRpbWUgXSB8fCB0aW1lIDogdGltZTsKCXR5cGUgPSB0eXBlIHx8ICJmeCI7CgoJcmV0dXJuIHRoaXMucXVldWUoIHR5cGUsIGZ1bmN0aW9uKCBuZXh0LCBob29rcyApIHsKCQl2YXIgdGltZW91dCA9IHNldFRpbWVvdXQoIG5leHQsIHRpbWUgKTsKCQlob29rcy5zdG9wID0gZnVuY3Rpb24oKSB7CgkJCWNsZWFyVGltZW91dCggdGltZW91dCApOwoJCX07Cgl9KTsKfTsKCgooZnVuY3Rpb24oKSB7Cgl2YXIgaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAiaW5wdXQiICksCgkJc2VsZWN0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggInNlbGVjdCIgKSwKCQlvcHQgPSBzZWxlY3QuYXBwZW5kQ2hpbGQoIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICJvcHRpb24iICkgKTsKCglpbnB1dC50eXBlID0gImNoZWNrYm94IjsKCgkvLyBTdXBwb3J0OiBpT1MgNS4xLCBBbmRyb2lkIDQueCwgQW5kcm9pZCAyLjMKCS8vIENoZWNrIHRoZSBkZWZhdWx0IGNoZWNrYm94L3JhZGlvIHZhbHVlICgiIiBvbiBvbGQgV2ViS2l0OyAib24iIGVsc2V3aGVyZSkKCXN1cHBvcnQuY2hlY2tPbiA9IGlucHV0LnZhbHVlICE9PSAiIjsKCgkvLyBNdXN0IGFjY2VzcyB0aGUgcGFyZW50IHRvIG1ha2UgYW4gb3B0aW9uIHNlbGVjdCBwcm9wZXJseQoJLy8gU3VwcG9ydDogSUU5LCBJRTEwCglzdXBwb3J0Lm9wdFNlbGVjdGVkID0gb3B0LnNlbGVjdGVkOwoKCS8vIE1ha2Ugc3VyZSB0aGF0IHRoZSBvcHRpb25zIGluc2lkZSBkaXNhYmxlZCBzZWxlY3RzIGFyZW4ndCBtYXJrZWQgYXMgZGlzYWJsZWQKCS8vIChXZWJLaXQgbWFya3MgdGhlbSBhcyBkaXNhYmxlZCkKCXNlbGVjdC5kaXNhYmxlZCA9IHRydWU7CglzdXBwb3J0Lm9wdERpc2FibGVkID0gIW9wdC5kaXNhYmxlZDsKCgkvLyBDaGVjayBpZiBhbiBpbnB1dCBtYWludGFpbnMgaXRzIHZhbHVlIGFmdGVyIGJlY29taW5nIGEgcmFkaW8KCS8vIFN1cHBvcnQ6IElFOSwgSUUxMAoJaW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAiaW5wdXQiICk7CglpbnB1dC52YWx1ZSA9ICJ0IjsKCWlucHV0LnR5cGUgPSAicmFkaW8iOwoJc3VwcG9ydC5yYWRpb1ZhbHVlID0gaW5wdXQudmFsdWUgPT09ICJ0IjsKfSkoKTsKCgp2YXIgbm9kZUhvb2ssIGJvb2xIb29rLAoJYXR0ckhhbmRsZSA9IGpRdWVyeS5leHByLmF0dHJIYW5kbGU7CgpqUXVlcnkuZm4uZXh0ZW5kKHsKCWF0dHI6IGZ1bmN0aW9uKCBuYW1lLCB2YWx1ZSApIHsKCQlyZXR1cm4gYWNjZXNzKCB0aGlzLCBqUXVlcnkuYXR0ciwgbmFtZSwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggPiAxICk7Cgl9LAoKCXJlbW92ZUF0dHI6IGZ1bmN0aW9uKCBuYW1lICkgewoJCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7CgkJCWpRdWVyeS5yZW1vdmVBdHRyKCB0aGlzLCBuYW1lICk7CgkJfSk7Cgl9Cn0pOwoKalF1ZXJ5LmV4dGVuZCh7CglhdHRyOiBmdW5jdGlvbiggZWxlbSwgbmFtZSwgdmFsdWUgKSB7CgkJdmFyIGhvb2tzLCByZXQsCgkJCW5UeXBlID0gZWxlbS5ub2RlVHlwZTsKCgkJLy8gZG9uJ3QgZ2V0L3NldCBhdHRyaWJ1dGVzIG9uIHRleHQsIGNvbW1lbnQgYW5kIGF0dHJpYnV0ZSBub2RlcwoJCWlmICggIWVsZW0gfHwgblR5cGUgPT09IDMgfHwgblR5cGUgPT09IDggfHwgblR5cGUgPT09IDIgKSB7CgkJCXJldHVybjsKCQl9CgoJCS8vIEZhbGxiYWNrIHRvIHByb3Agd2hlbiBhdHRyaWJ1dGVzIGFyZSBub3Qgc3VwcG9ydGVkCgkJaWYgKCB0eXBlb2YgZWxlbS5nZXRBdHRyaWJ1dGUgPT09IHN0cnVuZGVmaW5lZCApIHsKCQkJcmV0dXJuIGpRdWVyeS5wcm9wKCBlbGVtLCBuYW1lLCB2YWx1ZSApOwoJCX0KCgkJLy8gQWxsIGF0dHJpYnV0ZXMgYXJlIGxvd2VyY2FzZQoJCS8vIEdyYWIgbmVjZXNzYXJ5IGhvb2sgaWYgb25lIGlzIGRlZmluZWQKCQlpZiAoIG5UeXBlICE9PSAxIHx8ICFqUXVlcnkuaXNYTUxEb2MoIGVsZW0gKSApIHsKCQkJbmFtZSA9IG5hbWUudG9Mb3dlckNhc2UoKTsKCQkJaG9va3MgPSBqUXVlcnkuYXR0ckhvb2tzWyBuYW1lIF0gfHwKCQkJCSggalF1ZXJ5LmV4cHIubWF0Y2guYm9vbC50ZXN0KCBuYW1lICkgPyBib29sSG9vayA6IG5vZGVIb29rICk7CgkJfQoKCQlpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7CgoJCQlpZiAoIHZhbHVlID09PSBudWxsICkgewoJCQkJalF1ZXJ5LnJlbW92ZUF0dHIoIGVsZW0sIG5hbWUgKTsKCgkJCX0gZWxzZSBpZiAoIGhvb2tzICYmICJzZXQiIGluIGhvb2tzICYmIChyZXQgPSBob29rcy5zZXQoIGVsZW0sIHZhbHVlLCBuYW1lICkpICE9PSB1bmRlZmluZWQgKSB7CgkJCQlyZXR1cm4gcmV0OwoKCQkJfSBlbHNlIHsKCQkJCWVsZW0uc2V0QXR0cmlidXRlKCBuYW1lLCB2YWx1ZSArICIiICk7CgkJCQlyZXR1cm4gdmFsdWU7CgkJCX0KCgkJfSBlbHNlIGlmICggaG9va3MgJiYgImdldCIgaW4gaG9va3MgJiYgKHJldCA9IGhvb2tzLmdldCggZWxlbSwgbmFtZSApKSAhPT0gbnVsbCApIHsKCQkJcmV0dXJuIHJldDsKCgkJfSBlbHNlIHsKCQkJcmV0ID0galF1ZXJ5LmZpbmQuYXR0ciggZWxlbSwgbmFtZSApOwoKCQkJLy8gTm9uLWV4aXN0ZW50IGF0dHJpYnV0ZXMgcmV0dXJuIG51bGwsIHdlIG5vcm1hbGl6ZSB0byB1bmRlZmluZWQKCQkJcmV0dXJuIHJldCA9PSBudWxsID8KCQkJCXVuZGVmaW5lZCA6CgkJCQlyZXQ7CgkJfQoJfSwKCglyZW1vdmVBdHRyOiBmdW5jdGlvbiggZWxlbSwgdmFsdWUgKSB7CgkJdmFyIG5hbWUsIHByb3BOYW1lLAoJCQlpID0gMCwKCQkJYXR0ck5hbWVzID0gdmFsdWUgJiYgdmFsdWUubWF0Y2goIHJub3R3aGl0ZSApOwoKCQlpZiAoIGF0dHJOYW1lcyAmJiBlbGVtLm5vZGVUeXBlID09PSAxICkgewoJCQl3aGlsZSAoIChuYW1lID0gYXR0ck5hbWVzW2krK10pICkgewoJCQkJcHJvcE5hbWUgPSBqUXVlcnkucHJvcEZpeFsgbmFtZSBdIHx8IG5hbWU7CgoJCQkJLy8gQm9vbGVhbiBhdHRyaWJ1dGVzIGdldCBzcGVjaWFsIHRyZWF0bWVudCAoIzEwODcwKQoJCQkJaWYgKCBqUXVlcnkuZXhwci5tYXRjaC5ib29sLnRlc3QoIG5hbWUgKSApIHsKCQkJCQkvLyBTZXQgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSB0byBmYWxzZQoJCQkJCWVsZW1bIHByb3BOYW1lIF0gPSBmYWxzZTsKCQkJCX0KCgkJCQllbGVtLnJlbW92ZUF0dHJpYnV0ZSggbmFtZSApOwoJCQl9CgkJfQoJfSwKCglhdHRySG9va3M6IHsKCQl0eXBlOiB7CgkJCXNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlICkgewoJCQkJaWYgKCAhc3VwcG9ydC5yYWRpb1ZhbHVlICYmIHZhbHVlID09PSAicmFkaW8iICYmCgkJCQkJalF1ZXJ5Lm5vZGVOYW1lKCBlbGVtLCAiaW5wdXQiICkgKSB7CgkJCQkJLy8gU2V0dGluZyB0aGUgdHlwZSBvbiBhIHJhZGlvIGJ1dHRvbiBhZnRlciB0aGUgdmFsdWUgcmVzZXRzIHRoZSB2YWx1ZSBpbiBJRTYtOQoJCQkJCS8vIFJlc2V0IHZhbHVlIHRvIGRlZmF1bHQgaW4gY2FzZSB0eXBlIGlzIHNldCBhZnRlciB2YWx1ZSBkdXJpbmcgY3JlYXRpb24KCQkJCQl2YXIgdmFsID0gZWxlbS52YWx1ZTsKCQkJCQllbGVtLnNldEF0dHJpYnV0ZSggInR5cGUiLCB2YWx1ZSApOwoJCQkJCWlmICggdmFsICkgewoJCQkJCQllbGVtLnZhbHVlID0gdmFsOwoJCQkJCX0KCQkJCQlyZXR1cm4gdmFsdWU7CgkJCQl9CgkJCX0KCQl9Cgl9Cn0pOwoKLy8gSG9va3MgZm9yIGJvb2xlYW4gYXR0cmlidXRlcwpib29sSG9vayA9IHsKCXNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlLCBuYW1lICkgewoJCWlmICggdmFsdWUgPT09IGZhbHNlICkgewoJCQkvLyBSZW1vdmUgYm9vbGVhbiBhdHRyaWJ1dGVzIHdoZW4gc2V0IHRvIGZhbHNlCgkJCWpRdWVyeS5yZW1vdmVBdHRyKCBlbGVtLCBuYW1lICk7CgkJfSBlbHNlIHsKCQkJZWxlbS5zZXRBdHRyaWJ1dGUoIG5hbWUsIG5hbWUgKTsKCQl9CgkJcmV0dXJuIG5hbWU7Cgl9Cn07CmpRdWVyeS5lYWNoKCBqUXVlcnkuZXhwci5tYXRjaC5ib29sLnNvdXJjZS5tYXRjaCggL1x3Ky9nICksIGZ1bmN0aW9uKCBpLCBuYW1lICkgewoJdmFyIGdldHRlciA9IGF0dHJIYW5kbGVbIG5hbWUgXSB8fCBqUXVlcnkuZmluZC5hdHRyOwoKCWF0dHJIYW5kbGVbIG5hbWUgXSA9IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCBpc1hNTCApIHsKCQl2YXIgcmV0LCBoYW5kbGU7CgkJaWYgKCAhaXNYTUwgKSB7CgkJCS8vIEF2b2lkIGFuIGluZmluaXRlIGxvb3AgYnkgdGVtcG9yYXJpbHkgcmVtb3ZpbmcgdGhpcyBmdW5jdGlvbiBmcm9tIHRoZSBnZXR0ZXIKCQkJaGFuZGxlID0gYXR0ckhhbmRsZVsgbmFtZSBdOwoJCQlhdHRySGFuZGxlWyBuYW1lIF0gPSByZXQ7CgkJCXJldCA9IGdldHRlciggZWxlbSwgbmFtZSwgaXNYTUwgKSAhPSBudWxsID8KCQkJCW5hbWUudG9Mb3dlckNhc2UoKSA6CgkJCQludWxsOwoJCQlhdHRySGFuZGxlWyBuYW1lIF0gPSBoYW5kbGU7CgkJfQoJCXJldHVybiByZXQ7Cgl9Owp9KTsKCgoKCnZhciByZm9jdXNhYmxlID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaTsKCmpRdWVyeS5mbi5leHRlbmQoewoJcHJvcDogZnVuY3Rpb24oIG5hbWUsIHZhbHVlICkgewoJCXJldHVybiBhY2Nlc3MoIHRoaXMsIGpRdWVyeS5wcm9wLCBuYW1lLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCA+IDEgKTsKCX0sCgoJcmVtb3ZlUHJvcDogZnVuY3Rpb24oIG5hbWUgKSB7CgkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHsKCQkJZGVsZXRlIHRoaXNbIGpRdWVyeS5wcm9wRml4WyBuYW1lIF0gfHwgbmFtZSBdOwoJCX0pOwoJfQp9KTsKCmpRdWVyeS5leHRlbmQoewoJcHJvcEZpeDogewoJCSJmb3IiOiAiaHRtbEZvciIsCgkJImNsYXNzIjogImNsYXNzTmFtZSIKCX0sCgoJcHJvcDogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIHZhbHVlICkgewoJCXZhciByZXQsIGhvb2tzLCBub3R4bWwsCgkJCW5UeXBlID0gZWxlbS5ub2RlVHlwZTsKCgkJLy8gZG9uJ3QgZ2V0L3NldCBwcm9wZXJ0aWVzIG9uIHRleHQsIGNvbW1lbnQgYW5kIGF0dHJpYnV0ZSBub2RlcwoJCWlmICggIWVsZW0gfHwgblR5cGUgPT09IDMgfHwgblR5cGUgPT09IDggfHwgblR5cGUgPT09IDIgKSB7CgkJCXJldHVybjsKCQl9CgoJCW5vdHhtbCA9IG5UeXBlICE9PSAxIHx8ICFqUXVlcnkuaXNYTUxEb2MoIGVsZW0gKTsKCgkJaWYgKCBub3R4bWwgKSB7CgkJCS8vIEZpeCBuYW1lIGFuZCBhdHRhY2ggaG9va3MKCQkJbmFtZSA9IGpRdWVyeS5wcm9wRml4WyBuYW1lIF0gfHwgbmFtZTsKCQkJaG9va3MgPSBqUXVlcnkucHJvcEhvb2tzWyBuYW1lIF07CgkJfQoKCQlpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7CgkJCXJldHVybiBob29rcyAmJiAic2V0IiBpbiBob29rcyAmJiAocmV0ID0gaG9va3Muc2V0KCBlbGVtLCB2YWx1ZSwgbmFtZSApKSAhPT0gdW5kZWZpbmVkID8KCQkJCXJldCA6CgkJCQkoIGVsZW1bIG5hbWUgXSA9IHZhbHVlICk7CgoJCX0gZWxzZSB7CgkJCXJldHVybiBob29rcyAmJiAiZ2V0IiBpbiBob29rcyAmJiAocmV0ID0gaG9va3MuZ2V0KCBlbGVtLCBuYW1lICkpICE9PSBudWxsID8KCQkJCXJldCA6CgkJCQllbGVtWyBuYW1lIF07CgkJfQoJfSwKCglwcm9wSG9va3M6IHsKCQl0YWJJbmRleDogewoJCQlnZXQ6IGZ1bmN0aW9uKCBlbGVtICkgewoJCQkJcmV0dXJuIGVsZW0uaGFzQXR0cmlidXRlKCAidGFiaW5kZXgiICkgfHwgcmZvY3VzYWJsZS50ZXN0KCBlbGVtLm5vZGVOYW1lICkgfHwgZWxlbS5ocmVmID8KCQkJCQllbGVtLnRhYkluZGV4IDoKCQkJCQktMTsKCQkJfQoJCX0KCX0KfSk7CgovLyBTdXBwb3J0OiBJRTkrCi8vIFNlbGVjdGVkbmVzcyBmb3IgYW4gb3B0aW9uIGluIGFuIG9wdGdyb3VwIGNhbiBiZSBpbmFjY3VyYXRlCmlmICggIXN1cHBvcnQub3B0U2VsZWN0ZWQgKSB7CglqUXVlcnkucHJvcEhvb2tzLnNlbGVjdGVkID0gewoJCWdldDogZnVuY3Rpb24oIGVsZW0gKSB7CgkJCXZhciBwYXJlbnQgPSBlbGVtLnBhcmVudE5vZGU7CgkJCWlmICggcGFyZW50ICYmIHBhcmVudC5wYXJlbnROb2RlICkgewoJCQkJcGFyZW50LnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleDsKCQkJfQoJCQlyZXR1cm4gbnVsbDsKCQl9Cgl9Owp9CgpqUXVlcnkuZWFjaChbCgkidGFiSW5kZXgiLAoJInJlYWRPbmx5IiwKCSJtYXhMZW5ndGgiLAoJImNlbGxTcGFjaW5nIiwKCSJjZWxsUGFkZGluZyIsCgkicm93U3BhbiIsCgkiY29sU3BhbiIsCgkidXNlTWFwIiwKCSJmcmFtZUJvcmRlciIsCgkiY29udGVudEVkaXRhYmxlIgpdLCBmdW5jdGlvbigpIHsKCWpRdWVyeS5wcm9wRml4WyB0aGlzLnRvTG93ZXJDYXNlKCkgXSA9IHRoaXM7Cn0pOwoKCgoKdmFyIHJjbGFzcyA9IC9bXHRcclxuXGZdL2c7CgpqUXVlcnkuZm4uZXh0ZW5kKHsKCWFkZENsYXNzOiBmdW5jdGlvbiggdmFsdWUgKSB7CgkJdmFyIGNsYXNzZXMsIGVsZW0sIGN1ciwgY2xhenosIGosIGZpbmFsVmFsdWUsCgkJCXByb2NlZWQgPSB0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciICYmIHZhbHVlLAoJCQlpID0gMCwKCQkJbGVuID0gdGhpcy5sZW5ndGg7CgoJCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIHZhbHVlICkgKSB7CgkJCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oIGogKSB7CgkJCQlqUXVlcnkoIHRoaXMgKS5hZGRDbGFzcyggdmFsdWUuY2FsbCggdGhpcywgaiwgdGhpcy5jbGFzc05hbWUgKSApOwoJCQl9KTsKCQl9CgoJCWlmICggcHJvY2VlZCApIHsKCQkJLy8gVGhlIGRpc2p1bmN0aW9uIGhlcmUgaXMgZm9yIGJldHRlciBjb21wcmVzc2liaWxpdHkgKHNlZSByZW1vdmVDbGFzcykKCQkJY2xhc3NlcyA9ICggdmFsdWUgfHwgIiIgKS5tYXRjaCggcm5vdHdoaXRlICkgfHwgW107CgoJCQlmb3IgKCA7IGkgPCBsZW47IGkrKyApIHsKCQkJCWVsZW0gPSB0aGlzWyBpIF07CgkJCQljdXIgPSBlbGVtLm5vZGVUeXBlID09PSAxICYmICggZWxlbS5jbGFzc05hbWUgPwoJCQkJCSggIiAiICsgZWxlbS5jbGFzc05hbWUgKyAiICIgKS5yZXBsYWNlKCByY2xhc3MsICIgIiApIDoKCQkJCQkiICIKCQkJCSk7CgoJCQkJaWYgKCBjdXIgKSB7CgkJCQkJaiA9IDA7CgkJCQkJd2hpbGUgKCAoY2xhenogPSBjbGFzc2VzW2orK10pICkgewoJCQkJCQlpZiAoIGN1ci5pbmRleE9mKCAiICIgKyBjbGF6eiArICIgIiApIDwgMCApIHsKCQkJCQkJCWN1ciArPSBjbGF6eiArICIgIjsKCQkJCQkJfQoJCQkJCX0KCgkJCQkJLy8gb25seSBhc3NpZ24gaWYgZGlmZmVyZW50IHRvIGF2b2lkIHVubmVlZGVkIHJlbmRlcmluZy4KCQkJCQlmaW5hbFZhbHVlID0galF1ZXJ5LnRyaW0oIGN1ciApOwoJCQkJCWlmICggZWxlbS5jbGFzc05hbWUgIT09IGZpbmFsVmFsdWUgKSB7CgkJCQkJCWVsZW0uY2xhc3NOYW1lID0gZmluYWxWYWx1ZTsKCQkJCQl9CgkJCQl9CgkJCX0KCQl9CgoJCXJldHVybiB0aGlzOwoJfSwKCglyZW1vdmVDbGFzczogZnVuY3Rpb24oIHZhbHVlICkgewoJCXZhciBjbGFzc2VzLCBlbGVtLCBjdXIsIGNsYXp6LCBqLCBmaW5hbFZhbHVlLAoJCQlwcm9jZWVkID0gYXJndW1lbnRzLmxlbmd0aCA9PT0gMCB8fCB0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciICYmIHZhbHVlLAoJCQlpID0gMCwKCQkJbGVuID0gdGhpcy5sZW5ndGg7CgoJCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIHZhbHVlICkgKSB7CgkJCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oIGogKSB7CgkJCQlqUXVlcnkoIHRoaXMgKS5yZW1vdmVDbGFzcyggdmFsdWUuY2FsbCggdGhpcywgaiwgdGhpcy5jbGFzc05hbWUgKSApOwoJCQl9KTsKCQl9CgkJaWYgKCBwcm9jZWVkICkgewoJCQljbGFzc2VzID0gKCB2YWx1ZSB8fCAiIiApLm1hdGNoKCBybm90d2hpdGUgKSB8fCBbXTsKCgkJCWZvciAoIDsgaSA8IGxlbjsgaSsrICkgewoJCQkJZWxlbSA9IHRoaXNbIGkgXTsKCQkJCS8vIFRoaXMgZXhwcmVzc2lvbiBpcyBoZXJlIGZvciBiZXR0ZXIgY29tcHJlc3NpYmlsaXR5IChzZWUgYWRkQ2xhc3MpCgkJCQljdXIgPSBlbGVtLm5vZGVUeXBlID09PSAxICYmICggZWxlbS5jbGFzc05hbWUgPwoJCQkJCSggIiAiICsgZWxlbS5jbGFzc05hbWUgKyAiICIgKS5yZXBsYWNlKCByY2xhc3MsICIgIiApIDoKCQkJCQkiIgoJCQkJKTsKCgkJCQlpZiAoIGN1ciApIHsKCQkJCQlqID0gMDsKCQkJCQl3aGlsZSAoIChjbGF6eiA9IGNsYXNzZXNbaisrXSkgKSB7CgkJCQkJCS8vIFJlbW92ZSAqYWxsKiBpbnN0YW5jZXMKCQkJCQkJd2hpbGUgKCBjdXIuaW5kZXhPZiggIiAiICsgY2xhenogKyAiICIgKSA+PSAwICkgewoJCQkJCQkJY3VyID0gY3VyLnJlcGxhY2UoICIgIiArIGNsYXp6ICsgIiAiLCAiICIgKTsKCQkJCQkJfQoJCQkJCX0KCgkJCQkJLy8gb25seSBhc3NpZ24gaWYgZGlmZmVyZW50IHRvIGF2b2lkIHVubmVlZGVkIHJlbmRlcmluZy4KCQkJCQlmaW5hbFZhbHVlID0gdmFsdWUgPyBqUXVlcnkudHJpbSggY3VyICkgOiAiIjsKCQkJCQlpZiAoIGVsZW0uY2xhc3NOYW1lICE9PSBmaW5hbFZhbHVlICkgewoJCQkJCQllbGVtLmNsYXNzTmFtZSA9IGZpbmFsVmFsdWU7CgkJCQkJfQoJCQkJfQoJCQl9CgkJfQoKCQlyZXR1cm4gdGhpczsKCX0sCgoJdG9nZ2xlQ2xhc3M6IGZ1bmN0aW9uKCB2YWx1ZSwgc3RhdGVWYWwgKSB7CgkJdmFyIHR5cGUgPSB0eXBlb2YgdmFsdWU7CgoJCWlmICggdHlwZW9mIHN0YXRlVmFsID09PSAiYm9vbGVhbiIgJiYgdHlwZSA9PT0gInN0cmluZyIgKSB7CgkJCXJldHVybiBzdGF0ZVZhbCA/IHRoaXMuYWRkQ2xhc3MoIHZhbHVlICkgOiB0aGlzLnJlbW92ZUNsYXNzKCB2YWx1ZSApOwoJCX0KCgkJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggdmFsdWUgKSApIHsKCQkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiggaSApIHsKCQkJCWpRdWVyeSggdGhpcyApLnRvZ2dsZUNsYXNzKCB2YWx1ZS5jYWxsKHRoaXMsIGksIHRoaXMuY2xhc3NOYW1lLCBzdGF0ZVZhbCksIHN0YXRlVmFsICk7CgkJCX0pOwoJCX0KCgkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHsKCQkJaWYgKCB0eXBlID09PSAic3RyaW5nIiApIHsKCQkJCS8vIHRvZ2dsZSBpbmRpdmlkdWFsIGNsYXNzIG5hbWVzCgkJCQl2YXIgY2xhc3NOYW1lLAoJCQkJCWkgPSAwLAoJCQkJCXNlbGYgPSBqUXVlcnkoIHRoaXMgKSwKCQkJCQljbGFzc05hbWVzID0gdmFsdWUubWF0Y2goIHJub3R3aGl0ZSApIHx8IFtdOwoKCQkJCXdoaWxlICggKGNsYXNzTmFtZSA9IGNsYXNzTmFtZXNbIGkrKyBdKSApIHsKCQkJCQkvLyBjaGVjayBlYWNoIGNsYXNzTmFtZSBnaXZlbiwgc3BhY2Ugc2VwYXJhdGVkIGxpc3QKCQkJCQlpZiAoIHNlbGYuaGFzQ2xhc3MoIGNsYXNzTmFtZSApICkgewoJCQkJCQlzZWxmLnJlbW92ZUNsYXNzKCBjbGFzc05hbWUgKTsKCQkJCQl9IGVsc2UgewoJCQkJCQlzZWxmLmFkZENsYXNzKCBjbGFzc05hbWUgKTsKCQkJCQl9CgkJCQl9CgoJCQkvLyBUb2dnbGUgd2hvbGUgY2xhc3MgbmFtZQoJCQl9IGVsc2UgaWYgKCB0eXBlID09PSBzdHJ1bmRlZmluZWQgfHwgdHlwZSA9PT0gImJvb2xlYW4iICkgewoJCQkJaWYgKCB0aGlzLmNsYXNzTmFtZSApIHsKCQkJCQkvLyBzdG9yZSBjbGFzc05hbWUgaWYgc2V0CgkJCQkJZGF0YV9wcml2LnNldCggdGhpcywgIl9fY2xhc3NOYW1lX18iLCB0aGlzLmNsYXNzTmFtZSApOwoJCQkJfQoKCQkJCS8vIElmIHRoZSBlbGVtZW50IGhhcyBhIGNsYXNzIG5hbWUgb3IgaWYgd2UncmUgcGFzc2VkICJmYWxzZSIsCgkJCQkvLyB0aGVuIHJlbW92ZSB0aGUgd2hvbGUgY2xhc3NuYW1lIChpZiB0aGVyZSB3YXMgb25lLCB0aGUgYWJvdmUgc2F2ZWQgaXQpLgoJCQkJLy8gT3RoZXJ3aXNlIGJyaW5nIGJhY2sgd2hhdGV2ZXIgd2FzIHByZXZpb3VzbHkgc2F2ZWQgKGlmIGFueXRoaW5nKSwKCQkJCS8vIGZhbGxpbmcgYmFjayB0byB0aGUgZW1wdHkgc3RyaW5nIGlmIG5vdGhpbmcgd2FzIHN0b3JlZC4KCQkJCXRoaXMuY2xhc3NOYW1lID0gdGhpcy5jbGFzc05hbWUgfHwgdmFsdWUgPT09IGZhbHNlID8gIiIgOiBkYXRhX3ByaXYuZ2V0KCB0aGlzLCAiX19jbGFzc05hbWVfXyIgKSB8fCAiIjsKCQkJfQoJCX0pOwoJfSwKCgloYXNDbGFzczogZnVuY3Rpb24oIHNlbGVjdG9yICkgewoJCXZhciBjbGFzc05hbWUgPSAiICIgKyBzZWxlY3RvciArICIgIiwKCQkJaSA9IDAsCgkJCWwgPSB0aGlzLmxlbmd0aDsKCQlmb3IgKCA7IGkgPCBsOyBpKysgKSB7CgkJCWlmICggdGhpc1tpXS5ub2RlVHlwZSA9PT0gMSAmJiAoIiAiICsgdGhpc1tpXS5jbGFzc05hbWUgKyAiICIpLnJlcGxhY2UocmNsYXNzLCAiICIpLmluZGV4T2YoIGNsYXNzTmFtZSApID49IDAgKSB7CgkJCQlyZXR1cm4gdHJ1ZTsKCQkJfQoJCX0KCgkJcmV0dXJuIGZhbHNlOwoJfQp9KTsKCgoKCnZhciBycmV0dXJuID0gL1xyL2c7CgpqUXVlcnkuZm4uZXh0ZW5kKHsKCXZhbDogZnVuY3Rpb24oIHZhbHVlICkgewoJCXZhciBob29rcywgcmV0LCBpc0Z1bmN0aW9uLAoJCQllbGVtID0gdGhpc1swXTsKCgkJaWYgKCAhYXJndW1lbnRzLmxlbmd0aCApIHsKCQkJaWYgKCBlbGVtICkgewoJCQkJaG9va3MgPSBqUXVlcnkudmFsSG9va3NbIGVsZW0udHlwZSBdIHx8IGpRdWVyeS52YWxIb29rc1sgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpIF07CgoJCQkJaWYgKCBob29rcyAmJiAiZ2V0IiBpbiBob29rcyAmJiAocmV0ID0gaG9va3MuZ2V0KCBlbGVtLCAidmFsdWUiICkpICE9PSB1bmRlZmluZWQgKSB7CgkJCQkJcmV0dXJuIHJldDsKCQkJCX0KCgkJCQlyZXQgPSBlbGVtLnZhbHVlOwoKCQkJCXJldHVybiB0eXBlb2YgcmV0ID09PSAic3RyaW5nIiA/CgkJCQkJLy8gaGFuZGxlIG1vc3QgY29tbW9uIHN0cmluZyBjYXNlcwoJCQkJCXJldC5yZXBsYWNlKHJyZXR1cm4sICIiKSA6CgkJCQkJLy8gaGFuZGxlIGNhc2VzIHdoZXJlIHZhbHVlIGlzIG51bGwvdW5kZWYgb3IgbnVtYmVyCgkJCQkJcmV0ID09IG51bGwgPyAiIiA6IHJldDsKCQkJfQoKCQkJcmV0dXJuOwoJCX0KCgkJaXNGdW5jdGlvbiA9IGpRdWVyeS5pc0Z1bmN0aW9uKCB2YWx1ZSApOwoKCQlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCBpICkgewoJCQl2YXIgdmFsOwoKCQkJaWYgKCB0aGlzLm5vZGVUeXBlICE9PSAxICkgewoJCQkJcmV0dXJuOwoJCQl9CgoJCQlpZiAoIGlzRnVuY3Rpb24gKSB7CgkJCQl2YWwgPSB2YWx1ZS5jYWxsKCB0aGlzLCBpLCBqUXVlcnkoIHRoaXMgKS52YWwoKSApOwoJCQl9IGVsc2UgewoJCQkJdmFsID0gdmFsdWU7CgkJCX0KCgkJCS8vIFRyZWF0IG51bGwvdW5kZWZpbmVkIGFzICIiOyBjb252ZXJ0IG51bWJlcnMgdG8gc3RyaW5nCgkJCWlmICggdmFsID09IG51bGwgKSB7CgkJCQl2YWwgPSAiIjsKCgkJCX0gZWxzZSBpZiAoIHR5cGVvZiB2YWwgPT09ICJudW1iZXIiICkgewoJCQkJdmFsICs9ICIiOwoKCQkJfSBlbHNlIGlmICggalF1ZXJ5LmlzQXJyYXkoIHZhbCApICkgewoJCQkJdmFsID0galF1ZXJ5Lm1hcCggdmFsLCBmdW5jdGlvbiggdmFsdWUgKSB7CgkJCQkJcmV0dXJuIHZhbHVlID09IG51bGwgPyAiIiA6IHZhbHVlICsgIiI7CgkJCQl9KTsKCQkJfQoKCQkJaG9va3MgPSBqUXVlcnkudmFsSG9va3NbIHRoaXMudHlwZSBdIHx8IGpRdWVyeS52YWxIb29rc1sgdGhpcy5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpIF07CgoJCQkvLyBJZiBzZXQgcmV0dXJucyB1bmRlZmluZWQsIGZhbGwgYmFjayB0byBub3JtYWwgc2V0dGluZwoJCQlpZiAoICFob29rcyB8fCAhKCJzZXQiIGluIGhvb2tzKSB8fCBob29rcy5zZXQoIHRoaXMsIHZhbCwgInZhbHVlIiApID09PSB1bmRlZmluZWQgKSB7CgkJCQl0aGlzLnZhbHVlID0gdmFsOwoJCQl9CgkJfSk7Cgl9Cn0pOwoKalF1ZXJ5LmV4dGVuZCh7Cgl2YWxIb29rczogewoJCW9wdGlvbjogewoJCQlnZXQ6IGZ1bmN0aW9uKCBlbGVtICkgewoJCQkJdmFyIHZhbCA9IGpRdWVyeS5maW5kLmF0dHIoIGVsZW0sICJ2YWx1ZSIgKTsKCQkJCXJldHVybiB2YWwgIT0gbnVsbCA/CgkJCQkJdmFsIDoKCQkJCQkvLyBTdXBwb3J0OiBJRTEwLTExKwoJCQkJCS8vIG9wdGlvbi50ZXh0IHRocm93cyBleGNlcHRpb25zICgjMTQ2ODYsICMxNDg1OCkKCQkJCQlqUXVlcnkudHJpbSggalF1ZXJ5LnRleHQoIGVsZW0gKSApOwoJCQl9CgkJfSwKCQlzZWxlY3Q6IHsKCQkJZ2V0OiBmdW5jdGlvbiggZWxlbSApIHsKCQkJCXZhciB2YWx1ZSwgb3B0aW9uLAoJCQkJCW9wdGlvbnMgPSBlbGVtLm9wdGlvbnMsCgkJCQkJaW5kZXggPSBlbGVtLnNlbGVjdGVkSW5kZXgsCgkJCQkJb25lID0gZWxlbS50eXBlID09PSAic2VsZWN0LW9uZSIgfHwgaW5kZXggPCAwLAoJCQkJCXZhbHVlcyA9IG9uZSA/IG51bGwgOiBbXSwKCQkJCQltYXggPSBvbmUgPyBpbmRleCArIDEgOiBvcHRpb25zLmxlbmd0aCwKCQkJCQlpID0gaW5kZXggPCAwID8KCQkJCQkJbWF4IDoKCQkJCQkJb25lID8gaW5kZXggOiAwOwoKCQkJCS8vIExvb3AgdGhyb3VnaCBhbGwgdGhlIHNlbGVjdGVkIG9wdGlvbnMKCQkJCWZvciAoIDsgaSA8IG1heDsgaSsrICkgewoJCQkJCW9wdGlvbiA9IG9wdGlvbnNbIGkgXTsKCgkJCQkJLy8gSUU2LTkgZG9lc24ndCB1cGRhdGUgc2VsZWN0ZWQgYWZ0ZXIgZm9ybSByZXNldCAoIzI1NTEpCgkJCQkJaWYgKCAoIG9wdGlvbi5zZWxlY3RlZCB8fCBpID09PSBpbmRleCApICYmCgkJCQkJCQkvLyBEb24ndCByZXR1cm4gb3B0aW9ucyB0aGF0IGFyZSBkaXNhYmxlZCBvciBpbiBhIGRpc2FibGVkIG9wdGdyb3VwCgkJCQkJCQkoIHN1cHBvcnQub3B0RGlzYWJsZWQgPyAhb3B0aW9uLmRpc2FibGVkIDogb3B0aW9uLmdldEF0dHJpYnV0ZSggImRpc2FibGVkIiApID09PSBudWxsICkgJiYKCQkJCQkJCSggIW9wdGlvbi5wYXJlbnROb2RlLmRpc2FibGVkIHx8ICFqUXVlcnkubm9kZU5hbWUoIG9wdGlvbi5wYXJlbnROb2RlLCAib3B0Z3JvdXAiICkgKSApIHsKCgkJCQkJCS8vIEdldCB0aGUgc3BlY2lmaWMgdmFsdWUgZm9yIHRoZSBvcHRpb24KCQkJCQkJdmFsdWUgPSBqUXVlcnkoIG9wdGlvbiApLnZhbCgpOwoKCQkJCQkJLy8gV2UgZG9uJ3QgbmVlZCBhbiBhcnJheSBmb3Igb25lIHNlbGVjdHMKCQkJCQkJaWYgKCBvbmUgKSB7CgkJCQkJCQlyZXR1cm4gdmFsdWU7CgkJCQkJCX0KCgkJCQkJCS8vIE11bHRpLVNlbGVjdHMgcmV0dXJuIGFuIGFycmF5CgkJCQkJCXZhbHVlcy5wdXNoKCB2YWx1ZSApOwoJCQkJCX0KCQkJCX0KCgkJCQlyZXR1cm4gdmFsdWVzOwoJCQl9LAoKCQkJc2V0OiBmdW5jdGlvbiggZWxlbSwgdmFsdWUgKSB7CgkJCQl2YXIgb3B0aW9uU2V0LCBvcHRpb24sCgkJCQkJb3B0aW9ucyA9IGVsZW0ub3B0aW9ucywKCQkJCQl2YWx1ZXMgPSBqUXVlcnkubWFrZUFycmF5KCB2YWx1ZSApLAoJCQkJCWkgPSBvcHRpb25zLmxlbmd0aDsKCgkJCQl3aGlsZSAoIGktLSApIHsKCQkJCQlvcHRpb24gPSBvcHRpb25zWyBpIF07CgkJCQkJaWYgKCAob3B0aW9uLnNlbGVjdGVkID0galF1ZXJ5LmluQXJyYXkoIG9wdGlvbi52YWx1ZSwgdmFsdWVzICkgPj0gMCkgKSB7CgkJCQkJCW9wdGlvblNldCA9IHRydWU7CgkJCQkJfQoJCQkJfQoKCQkJCS8vIGZvcmNlIGJyb3dzZXJzIHRvIGJlaGF2ZSBjb25zaXN0ZW50bHkgd2hlbiBub24tbWF0Y2hpbmcgdmFsdWUgaXMgc2V0CgkJCQlpZiAoICFvcHRpb25TZXQgKSB7CgkJCQkJZWxlbS5zZWxlY3RlZEluZGV4ID0gLTE7CgkJCQl9CgkJCQlyZXR1cm4gdmFsdWVzOwoJCQl9CgkJfQoJfQp9KTsKCi8vIFJhZGlvcyBhbmQgY2hlY2tib3hlcyBnZXR0ZXIvc2V0dGVyCmpRdWVyeS5lYWNoKFsgInJhZGlvIiwgImNoZWNrYm94IiBdLCBmdW5jdGlvbigpIHsKCWpRdWVyeS52YWxIb29rc1sgdGhpcyBdID0gewoJCXNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlICkgewoJCQlpZiAoIGpRdWVyeS5pc0FycmF5KCB2YWx1ZSApICkgewoJCQkJcmV0dXJuICggZWxlbS5jaGVja2VkID0galF1ZXJ5LmluQXJyYXkoIGpRdWVyeShlbGVtKS52YWwoKSwgdmFsdWUgKSA+PSAwICk7CgkJCX0KCQl9Cgl9OwoJaWYgKCAhc3VwcG9ydC5jaGVja09uICkgewoJCWpRdWVyeS52YWxIb29rc1sgdGhpcyBdLmdldCA9IGZ1bmN0aW9uKCBlbGVtICkgewoJCQkvLyBTdXBwb3J0OiBXZWJraXQKCQkJLy8gIiIgaXMgcmV0dXJuZWQgaW5zdGVhZCBvZiAib24iIGlmIGEgdmFsdWUgaXNuJ3Qgc3BlY2lmaWVkCgkJCXJldHVybiBlbGVtLmdldEF0dHJpYnV0ZSgidmFsdWUiKSA9PT0gbnVsbCA/ICJvbiIgOiBlbGVtLnZhbHVlOwoJCX07Cgl9Cn0pOwoKCgoKLy8gUmV0dXJuIGpRdWVyeSBmb3IgYXR0cmlidXRlcy1vbmx5IGluY2x1c2lvbgoKCmpRdWVyeS5lYWNoKCAoImJsdXIgZm9jdXMgZm9jdXNpbiBmb2N1c291dCBsb2FkIHJlc2l6ZSBzY3JvbGwgdW5sb2FkIGNsaWNrIGRibGNsaWNrICIgKwoJIm1vdXNlZG93biBtb3VzZXVwIG1vdXNlbW92ZSBtb3VzZW92ZXIgbW91c2VvdXQgbW91c2VlbnRlciBtb3VzZWxlYXZlICIgKwoJImNoYW5nZSBzZWxlY3Qgc3VibWl0IGtleWRvd24ga2V5cHJlc3Mga2V5dXAgZXJyb3IgY29udGV4dG1lbnUiKS5zcGxpdCgiICIpLCBmdW5jdGlvbiggaSwgbmFtZSApIHsKCgkvLyBIYW5kbGUgZXZlbnQgYmluZGluZwoJalF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggZGF0YSwgZm4gKSB7CgkJcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAwID8KCQkJdGhpcy5vbiggbmFtZSwgbnVsbCwgZGF0YSwgZm4gKSA6CgkJCXRoaXMudHJpZ2dlciggbmFtZSApOwoJfTsKfSk7CgpqUXVlcnkuZm4uZXh0ZW5kKHsKCWhvdmVyOiBmdW5jdGlvbiggZm5PdmVyLCBmbk91dCApIHsKCQlyZXR1cm4gdGhpcy5tb3VzZWVudGVyKCBmbk92ZXIgKS5tb3VzZWxlYXZlKCBmbk91dCB8fCBmbk92ZXIgKTsKCX0sCgoJYmluZDogZnVuY3Rpb24oIHR5cGVzLCBkYXRhLCBmbiApIHsKCQlyZXR1cm4gdGhpcy5vbiggdHlwZXMsIG51bGwsIGRhdGEsIGZuICk7Cgl9LAoJdW5iaW5kOiBmdW5jdGlvbiggdHlwZXMsIGZuICkgewoJCXJldHVybiB0aGlzLm9mZiggdHlwZXMsIG51bGwsIGZuICk7Cgl9LAoKCWRlbGVnYXRlOiBmdW5jdGlvbiggc2VsZWN0b3IsIHR5cGVzLCBkYXRhLCBmbiApIHsKCQlyZXR1cm4gdGhpcy5vbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApOwoJfSwKCXVuZGVsZWdhdGU6IGZ1bmN0aW9uKCBzZWxlY3RvciwgdHlwZXMsIGZuICkgewoJCS8vICggbmFtZXNwYWNlICkgb3IgKCBzZWxlY3RvciwgdHlwZXMgWywgZm5dICkKCQlyZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA9PT0gMSA/IHRoaXMub2ZmKCBzZWxlY3RvciwgIioqIiApIDogdGhpcy5vZmYoIHR5cGVzLCBzZWxlY3RvciB8fCAiKioiLCBmbiApOwoJfQp9KTsKCgp2YXIgbm9uY2UgPSBqUXVlcnkubm93KCk7Cgp2YXIgcnF1ZXJ5ID0gKC9cPy8pOwoKCgovLyBTdXBwb3J0OiBBbmRyb2lkIDIuMwovLyBXb3JrYXJvdW5kIGZhaWx1cmUgdG8gc3RyaW5nLWNhc3QgbnVsbCBpbnB1dApqUXVlcnkucGFyc2VKU09OID0gZnVuY3Rpb24oIGRhdGEgKSB7CglyZXR1cm4gSlNPTi5wYXJzZSggZGF0YSArICIiICk7Cn07CgoKLy8gQ3Jvc3MtYnJvd3NlciB4bWwgcGFyc2luZwpqUXVlcnkucGFyc2VYTUwgPSBmdW5jdGlvbiggZGF0YSApIHsKCXZhciB4bWwsIHRtcDsKCWlmICggIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09ICJzdHJpbmciICkgewoJCXJldHVybiBudWxsOwoJfQoKCS8vIFN1cHBvcnQ6IElFOQoJdHJ5IHsKCQl0bXAgPSBuZXcgRE9NUGFyc2VyKCk7CgkJeG1sID0gdG1wLnBhcnNlRnJvbVN0cmluZyggZGF0YSwgInRleHQveG1sIiApOwoJfSBjYXRjaCAoIGUgKSB7CgkJeG1sID0gdW5kZWZpbmVkOwoJfQoKCWlmICggIXhtbCB8fCB4bWwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoICJwYXJzZXJlcnJvciIgKS5sZW5ndGggKSB7CgkJalF1ZXJ5LmVycm9yKCAiSW52YWxpZCBYTUw6ICIgKyBkYXRhICk7Cgl9CglyZXR1cm4geG1sOwp9OwoKCnZhcgoJLy8gRG9jdW1lbnQgbG9jYXRpb24KCWFqYXhMb2NQYXJ0cywKCWFqYXhMb2NhdGlvbiwKCglyaGFzaCA9IC8jLiokLywKCXJ0cyA9IC8oWz8mXSlfPVteJl0qLywKCXJoZWFkZXJzID0gL14oLio/KTpbIFx0XSooW15cclxuXSopJC9tZywKCS8vICM3NjUzLCAjODEyNSwgIzgxNTI6IGxvY2FsIHByb3RvY29sIGRldGVjdGlvbgoJcmxvY2FsUHJvdG9jb2wgPSAvXig/OmFib3V0fGFwcHxhcHAtc3RvcmFnZXwuKy1leHRlbnNpb258ZmlsZXxyZXN8d2lkZ2V0KTokLywKCXJub0NvbnRlbnQgPSAvXig/OkdFVHxIRUFEKSQvLAoJcnByb3RvY29sID0gL15cL1wvLywKCXJ1cmwgPSAvXihbXHcuKy1dKzopKD86XC9cLyg/OlteXC8/I10qQHwpKFteXC8/IzpdKikoPzo6KFxkKyl8KXwpLywKCgkvKiBQcmVmaWx0ZXJzCgkgKiAxKSBUaGV5IGFyZSB1c2VmdWwgdG8gaW50cm9kdWNlIGN1c3RvbSBkYXRhVHlwZXMgKHNlZSBhamF4L2pzb25wLmpzIGZvciBhbiBleGFtcGxlKQoJICogMikgVGhlc2UgYXJlIGNhbGxlZDoKCSAqICAgIC0gQkVGT1JFIGFza2luZyBmb3IgYSB0cmFuc3BvcnQKCSAqICAgIC0gQUZURVIgcGFyYW0gc2VyaWFsaXphdGlvbiAocy5kYXRhIGlzIGEgc3RyaW5nIGlmIHMucHJvY2Vzc0RhdGEgaXMgdHJ1ZSkKCSAqIDMpIGtleSBpcyB0aGUgZGF0YVR5cGUKCSAqIDQpIHRoZSBjYXRjaGFsbCBzeW1ib2wgIioiIGNhbiBiZSB1c2VkCgkgKiA1KSBleGVjdXRpb24gd2lsbCBzdGFydCB3aXRoIHRyYW5zcG9ydCBkYXRhVHlwZSBhbmQgVEhFTiBjb250aW51ZSBkb3duIHRvICIqIiBpZiBuZWVkZWQKCSAqLwoJcHJlZmlsdGVycyA9IHt9LAoKCS8qIFRyYW5zcG9ydHMgYmluZGluZ3MKCSAqIDEpIGtleSBpcyB0aGUgZGF0YVR5cGUKCSAqIDIpIHRoZSBjYXRjaGFsbCBzeW1ib2wgIioiIGNhbiBiZSB1c2VkCgkgKiAzKSBzZWxlY3Rpb24gd2lsbCBzdGFydCB3aXRoIHRyYW5zcG9ydCBkYXRhVHlwZSBhbmQgVEhFTiBnbyB0byAiKiIgaWYgbmVlZGVkCgkgKi8KCXRyYW5zcG9ydHMgPSB7fSwKCgkvLyBBdm9pZCBjb21tZW50LXByb2xvZyBjaGFyIHNlcXVlbmNlICgjMTAwOTgpOyBtdXN0IGFwcGVhc2UgbGludCBhbmQgZXZhZGUgY29tcHJlc3Npb24KCWFsbFR5cGVzID0gIiovIi5jb25jYXQoIioiKTsKCi8vICM4MTM4LCBJRSBtYXkgdGhyb3cgYW4gZXhjZXB0aW9uIHdoZW4gYWNjZXNzaW5nCi8vIGEgZmllbGQgZnJvbSB3aW5kb3cubG9jYXRpb24gaWYgZG9jdW1lbnQuZG9tYWluIGhhcyBiZWVuIHNldAp0cnkgewoJYWpheExvY2F0aW9uID0gbG9jYXRpb24uaHJlZjsKfSBjYXRjaCggZSApIHsKCS8vIFVzZSB0aGUgaHJlZiBhdHRyaWJ1dGUgb2YgYW4gQSBlbGVtZW50CgkvLyBzaW5jZSBJRSB3aWxsIG1vZGlmeSBpdCBnaXZlbiBkb2N1bWVudC5sb2NhdGlvbgoJYWpheExvY2F0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggImEiICk7CglhamF4TG9jYXRpb24uaHJlZiA9ICIiOwoJYWpheExvY2F0aW9uID0gYWpheExvY2F0aW9uLmhyZWY7Cn0KCi8vIFNlZ21lbnQgbG9jYXRpb24gaW50byBwYXJ0cwphamF4TG9jUGFydHMgPSBydXJsLmV4ZWMoIGFqYXhMb2NhdGlvbi50b0xvd2VyQ2FzZSgpICkgfHwgW107CgovLyBCYXNlICJjb25zdHJ1Y3RvciIgZm9yIGpRdWVyeS5hamF4UHJlZmlsdGVyIGFuZCBqUXVlcnkuYWpheFRyYW5zcG9ydApmdW5jdGlvbiBhZGRUb1ByZWZpbHRlcnNPclRyYW5zcG9ydHMoIHN0cnVjdHVyZSApIHsKCgkvLyBkYXRhVHlwZUV4cHJlc3Npb24gaXMgb3B0aW9uYWwgYW5kIGRlZmF1bHRzIHRvICIqIgoJcmV0dXJuIGZ1bmN0aW9uKCBkYXRhVHlwZUV4cHJlc3Npb24sIGZ1bmMgKSB7CgoJCWlmICggdHlwZW9mIGRhdGFUeXBlRXhwcmVzc2lvbiAhPT0gInN0cmluZyIgKSB7CgkJCWZ1bmMgPSBkYXRhVHlwZUV4cHJlc3Npb247CgkJCWRhdGFUeXBlRXhwcmVzc2lvbiA9ICIqIjsKCQl9CgoJCXZhciBkYXRhVHlwZSwKCQkJaSA9IDAsCgkJCWRhdGFUeXBlcyA9IGRhdGFUeXBlRXhwcmVzc2lvbi50b0xvd2VyQ2FzZSgpLm1hdGNoKCBybm90d2hpdGUgKSB8fCBbXTsKCgkJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggZnVuYyApICkgewoJCQkvLyBGb3IgZWFjaCBkYXRhVHlwZSBpbiB0aGUgZGF0YVR5cGVFeHByZXNzaW9uCgkJCXdoaWxlICggKGRhdGFUeXBlID0gZGF0YVR5cGVzW2krK10pICkgewoJCQkJLy8gUHJlcGVuZCBpZiByZXF1ZXN0ZWQKCQkJCWlmICggZGF0YVR5cGVbMF0gPT09ICIrIiApIHsKCQkJCQlkYXRhVHlwZSA9IGRhdGFUeXBlLnNsaWNlKCAxICkgfHwgIioiOwoJCQkJCShzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gPSBzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gfHwgW10pLnVuc2hpZnQoIGZ1bmMgKTsKCgkJCQkvLyBPdGhlcndpc2UgYXBwZW5kCgkJCQl9IGVsc2UgewoJCQkJCShzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gPSBzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gfHwgW10pLnB1c2goIGZ1bmMgKTsKCQkJCX0KCQkJfQoJCX0KCX07Cn0KCi8vIEJhc2UgaW5zcGVjdGlvbiBmdW5jdGlvbiBmb3IgcHJlZmlsdGVycyBhbmQgdHJhbnNwb3J0cwpmdW5jdGlvbiBpbnNwZWN0UHJlZmlsdGVyc09yVHJhbnNwb3J0cyggc3RydWN0dXJlLCBvcHRpb25zLCBvcmlnaW5hbE9wdGlvbnMsIGpxWEhSICkgewoKCXZhciBpbnNwZWN0ZWQgPSB7fSwKCQlzZWVraW5nVHJhbnNwb3J0ID0gKCBzdHJ1Y3R1cmUgPT09IHRyYW5zcG9ydHMgKTsKCglmdW5jdGlvbiBpbnNwZWN0KCBkYXRhVHlwZSApIHsKCQl2YXIgc2VsZWN0ZWQ7CgkJaW5zcGVjdGVkWyBkYXRhVHlwZSBdID0gdHJ1ZTsKCQlqUXVlcnkuZWFjaCggc3RydWN0dXJlWyBkYXRhVHlwZSBdIHx8IFtdLCBmdW5jdGlvbiggXywgcHJlZmlsdGVyT3JGYWN0b3J5ICkgewoJCQl2YXIgZGF0YVR5cGVPclRyYW5zcG9ydCA9IHByZWZpbHRlck9yRmFjdG9yeSggb3B0aW9ucywgb3JpZ2luYWxPcHRpb25zLCBqcVhIUiApOwoJCQlpZiAoIHR5cGVvZiBkYXRhVHlwZU9yVHJhbnNwb3J0ID09PSAic3RyaW5nIiAmJiAhc2Vla2luZ1RyYW5zcG9ydCAmJiAhaW5zcGVjdGVkWyBkYXRhVHlwZU9yVHJhbnNwb3J0IF0gKSB7CgkJCQlvcHRpb25zLmRhdGFUeXBlcy51bnNoaWZ0KCBkYXRhVHlwZU9yVHJhbnNwb3J0ICk7CgkJCQlpbnNwZWN0KCBkYXRhVHlwZU9yVHJhbnNwb3J0ICk7CgkJCQlyZXR1cm4gZmFsc2U7CgkJCX0gZWxzZSBpZiAoIHNlZWtpbmdUcmFuc3BvcnQgKSB7CgkJCQlyZXR1cm4gISggc2VsZWN0ZWQgPSBkYXRhVHlwZU9yVHJhbnNwb3J0ICk7CgkJCX0KCQl9KTsKCQlyZXR1cm4gc2VsZWN0ZWQ7Cgl9CgoJcmV0dXJuIGluc3BlY3QoIG9wdGlvbnMuZGF0YVR5cGVzWyAwIF0gKSB8fCAhaW5zcGVjdGVkWyAiKiIgXSAmJiBpbnNwZWN0KCAiKiIgKTsKfQoKLy8gQSBzcGVjaWFsIGV4dGVuZCBmb3IgYWpheCBvcHRpb25zCi8vIHRoYXQgdGFrZXMgImZsYXQiIG9wdGlvbnMgKG5vdCB0byBiZSBkZWVwIGV4dGVuZGVkKQovLyBGaXhlcyAjOTg4NwpmdW5jdGlvbiBhamF4RXh0ZW5kKCB0YXJnZXQsIHNyYyApIHsKCXZhciBrZXksIGRlZXAsCgkJZmxhdE9wdGlvbnMgPSBqUXVlcnkuYWpheFNldHRpbmdzLmZsYXRPcHRpb25zIHx8IHt9OwoKCWZvciAoIGtleSBpbiBzcmMgKSB7CgkJaWYgKCBzcmNbIGtleSBdICE9PSB1bmRlZmluZWQgKSB7CgkJCSggZmxhdE9wdGlvbnNbIGtleSBdID8gdGFyZ2V0IDogKCBkZWVwIHx8IChkZWVwID0ge30pICkgKVsga2V5IF0gPSBzcmNbIGtleSBdOwoJCX0KCX0KCWlmICggZGVlcCApIHsKCQlqUXVlcnkuZXh0ZW5kKCB0cnVlLCB0YXJnZXQsIGRlZXAgKTsKCX0KCglyZXR1cm4gdGFyZ2V0Owp9CgovKiBIYW5kbGVzIHJlc3BvbnNlcyB0byBhbiBhamF4IHJlcXVlc3Q6CiAqIC0gZmluZHMgdGhlIHJpZ2h0IGRhdGFUeXBlIChtZWRpYXRlcyBiZXR3ZWVuIGNvbnRlbnQtdHlwZSBhbmQgZXhwZWN0ZWQgZGF0YVR5cGUpCiAqIC0gcmV0dXJucyB0aGUgY29ycmVzcG9uZGluZyByZXNwb25zZQogKi8KZnVuY3Rpb24gYWpheEhhbmRsZVJlc3BvbnNlcyggcywganFYSFIsIHJlc3BvbnNlcyApIHsKCgl2YXIgY3QsIHR5cGUsIGZpbmFsRGF0YVR5cGUsIGZpcnN0RGF0YVR5cGUsCgkJY29udGVudHMgPSBzLmNvbnRlbnRzLAoJCWRhdGFUeXBlcyA9IHMuZGF0YVR5cGVzOwoKCS8vIFJlbW92ZSBhdXRvIGRhdGFUeXBlIGFuZCBnZXQgY29udGVudC10eXBlIGluIHRoZSBwcm9jZXNzCgl3aGlsZSAoIGRhdGFUeXBlc1sgMCBdID09PSAiKiIgKSB7CgkJZGF0YVR5cGVzLnNoaWZ0KCk7CgkJaWYgKCBjdCA9PT0gdW5kZWZpbmVkICkgewoJCQljdCA9IHMubWltZVR5cGUgfHwganFYSFIuZ2V0UmVzcG9uc2VIZWFkZXIoIkNvbnRlbnQtVHlwZSIpOwoJCX0KCX0KCgkvLyBDaGVjayBpZiB3ZSdyZSBkZWFsaW5nIHdpdGggYSBrbm93biBjb250ZW50LXR5cGUKCWlmICggY3QgKSB7CgkJZm9yICggdHlwZSBpbiBjb250ZW50cyApIHsKCQkJaWYgKCBjb250ZW50c1sgdHlwZSBdICYmIGNvbnRlbnRzWyB0eXBlIF0udGVzdCggY3QgKSApIHsKCQkJCWRhdGFUeXBlcy51bnNoaWZ0KCB0eXBlICk7CgkJCQlicmVhazsKCQkJfQoJCX0KCX0KCgkvLyBDaGVjayB0byBzZWUgaWYgd2UgaGF2ZSBhIHJlc3BvbnNlIGZvciB0aGUgZXhwZWN0ZWQgZGF0YVR5cGUKCWlmICggZGF0YVR5cGVzWyAwIF0gaW4gcmVzcG9uc2VzICkgewoJCWZpbmFsRGF0YVR5cGUgPSBkYXRhVHlwZXNbIDAgXTsKCX0gZWxzZSB7CgkJLy8gVHJ5IGNvbnZlcnRpYmxlIGRhdGFUeXBlcwoJCWZvciAoIHR5cGUgaW4gcmVzcG9uc2VzICkgewoJCQlpZiAoICFkYXRhVHlwZXNbIDAgXSB8fCBzLmNvbnZlcnRlcnNbIHR5cGUgKyAiICIgKyBkYXRhVHlwZXNbMF0gXSApIHsKCQkJCWZpbmFsRGF0YVR5cGUgPSB0eXBlOwoJCQkJYnJlYWs7CgkJCX0KCQkJaWYgKCAhZmlyc3REYXRhVHlwZSApIHsKCQkJCWZpcnN0RGF0YVR5cGUgPSB0eXBlOwoJCQl9CgkJfQoJCS8vIE9yIGp1c3QgdXNlIGZpcnN0IG9uZQoJCWZpbmFsRGF0YVR5cGUgPSBmaW5hbERhdGFUeXBlIHx8IGZpcnN0RGF0YVR5cGU7Cgl9CgoJLy8gSWYgd2UgZm91bmQgYSBkYXRhVHlwZQoJLy8gV2UgYWRkIHRoZSBkYXRhVHlwZSB0byB0aGUgbGlzdCBpZiBuZWVkZWQKCS8vIGFuZCByZXR1cm4gdGhlIGNvcnJlc3BvbmRpbmcgcmVzcG9uc2UKCWlmICggZmluYWxEYXRhVHlwZSApIHsKCQlpZiAoIGZpbmFsRGF0YVR5cGUgIT09IGRhdGFUeXBlc1sgMCBdICkgewoJCQlkYXRhVHlwZXMudW5zaGlmdCggZmluYWxEYXRhVHlwZSApOwoJCX0KCQlyZXR1cm4gcmVzcG9uc2VzWyBmaW5hbERhdGFUeXBlIF07Cgl9Cn0KCi8qIENoYWluIGNvbnZlcnNpb25zIGdpdmVuIHRoZSByZXF1ZXN0IGFuZCB0aGUgb3JpZ2luYWwgcmVzcG9uc2UKICogQWxzbyBzZXRzIHRoZSByZXNwb25zZVhYWCBmaWVsZHMgb24gdGhlIGpxWEhSIGluc3RhbmNlCiAqLwpmdW5jdGlvbiBhamF4Q29udmVydCggcywgcmVzcG9uc2UsIGpxWEhSLCBpc1N1Y2Nlc3MgKSB7Cgl2YXIgY29udjIsIGN1cnJlbnQsIGNvbnYsIHRtcCwgcHJldiwKCQljb252ZXJ0ZXJzID0ge30sCgkJLy8gV29yayB3aXRoIGEgY29weSBvZiBkYXRhVHlwZXMgaW4gY2FzZSB3ZSBuZWVkIHRvIG1vZGlmeSBpdCBmb3IgY29udmVyc2lvbgoJCWRhdGFUeXBlcyA9IHMuZGF0YVR5cGVzLnNsaWNlKCk7CgoJLy8gQ3JlYXRlIGNvbnZlcnRlcnMgbWFwIHdpdGggbG93ZXJjYXNlZCBrZXlzCglpZiAoIGRhdGFUeXBlc1sgMSBdICkgewoJCWZvciAoIGNvbnYgaW4gcy5jb252ZXJ0ZXJzICkgewoJCQljb252ZXJ0ZXJzWyBjb252LnRvTG93ZXJDYXNlKCkgXSA9IHMuY29udmVydGVyc1sgY29udiBdOwoJCX0KCX0KCgljdXJyZW50ID0gZGF0YVR5cGVzLnNoaWZ0KCk7CgoJLy8gQ29udmVydCB0byBlYWNoIHNlcXVlbnRpYWwgZGF0YVR5cGUKCXdoaWxlICggY3VycmVudCApIHsKCgkJaWYgKCBzLnJlc3BvbnNlRmllbGRzWyBjdXJyZW50IF0gKSB7CgkJCWpxWEhSWyBzLnJlc3BvbnNlRmllbGRzWyBjdXJyZW50IF0gXSA9IHJlc3BvbnNlOwoJCX0KCgkJLy8gQXBwbHkgdGhlIGRhdGFGaWx0ZXIgaWYgcHJvdmlkZWQKCQlpZiAoICFwcmV2ICYmIGlzU3VjY2VzcyAmJiBzLmRhdGFGaWx0ZXIgKSB7CgkJCXJlc3BvbnNlID0gcy5kYXRhRmlsdGVyKCByZXNwb25zZSwgcy5kYXRhVHlwZSApOwoJCX0KCgkJcHJldiA9IGN1cnJlbnQ7CgkJY3VycmVudCA9IGRhdGFUeXBlcy5zaGlmdCgpOwoKCQlpZiAoIGN1cnJlbnQgKSB7CgoJCS8vIFRoZXJlJ3Mgb25seSB3b3JrIHRvIGRvIGlmIGN1cnJlbnQgZGF0YVR5cGUgaXMgbm9uLWF1dG8KCQkJaWYgKCBjdXJyZW50ID09PSAiKiIgKSB7CgoJCQkJY3VycmVudCA9IHByZXY7CgoJCQkvLyBDb252ZXJ0IHJlc3BvbnNlIGlmIHByZXYgZGF0YVR5cGUgaXMgbm9uLWF1dG8gYW5kIGRpZmZlcnMgZnJvbSBjdXJyZW50CgkJCX0gZWxzZSBpZiAoIHByZXYgIT09ICIqIiAmJiBwcmV2ICE9PSBjdXJyZW50ICkgewoKCQkJCS8vIFNlZWsgYSBkaXJlY3QgY29udmVydGVyCgkJCQljb252ID0gY29udmVydGVyc1sgcHJldiArICIgIiArIGN1cnJlbnQgXSB8fCBjb252ZXJ0ZXJzWyAiKiAiICsgY3VycmVudCBdOwoKCQkJCS8vIElmIG5vbmUgZm91bmQsIHNlZWsgYSBwYWlyCgkJCQlpZiAoICFjb252ICkgewoJCQkJCWZvciAoIGNvbnYyIGluIGNvbnZlcnRlcnMgKSB7CgoJCQkJCQkvLyBJZiBjb252MiBvdXRwdXRzIGN1cnJlbnQKCQkJCQkJdG1wID0gY29udjIuc3BsaXQoICIgIiApOwoJCQkJCQlpZiAoIHRtcFsgMSBdID09PSBjdXJyZW50ICkgewoKCQkJCQkJCS8vIElmIHByZXYgY2FuIGJlIGNvbnZlcnRlZCB0byBhY2NlcHRlZCBpbnB1dAoJCQkJCQkJY29udiA9IGNvbnZlcnRlcnNbIHByZXYgKyAiICIgKyB0bXBbIDAgXSBdIHx8CgkJCQkJCQkJY29udmVydGVyc1sgIiogIiArIHRtcFsgMCBdIF07CgkJCQkJCQlpZiAoIGNvbnYgKSB7CgkJCQkJCQkJLy8gQ29uZGVuc2UgZXF1aXZhbGVuY2UgY29udmVydGVycwoJCQkJCQkJCWlmICggY29udiA9PT0gdHJ1ZSApIHsKCQkJCQkJCQkJY29udiA9IGNvbnZlcnRlcnNbIGNvbnYyIF07CgoJCQkJCQkJCS8vIE90aGVyd2lzZSwgaW5zZXJ0IHRoZSBpbnRlcm1lZGlhdGUgZGF0YVR5cGUKCQkJCQkJCQl9IGVsc2UgaWYgKCBjb252ZXJ0ZXJzWyBjb252MiBdICE9PSB0cnVlICkgewoJCQkJCQkJCQljdXJyZW50ID0gdG1wWyAwIF07CgkJCQkJCQkJCWRhdGFUeXBlcy51bnNoaWZ0KCB0bXBbIDEgXSApOwoJCQkJCQkJCX0KCQkJCQkJCQlicmVhazsKCQkJCQkJCX0KCQkJCQkJfQoJCQkJCX0KCQkJCX0KCgkJCQkvLyBBcHBseSBjb252ZXJ0ZXIgKGlmIG5vdCBhbiBlcXVpdmFsZW5jZSkKCQkJCWlmICggY29udiAhPT0gdHJ1ZSApIHsKCgkJCQkJLy8gVW5sZXNzIGVycm9ycyBhcmUgYWxsb3dlZCB0byBidWJibGUsIGNhdGNoIGFuZCByZXR1cm4gdGhlbQoJCQkJCWlmICggY29udiAmJiBzWyAidGhyb3dzIiBdICkgewoJCQkJCQlyZXNwb25zZSA9IGNvbnYoIHJlc3BvbnNlICk7CgkJCQkJfSBlbHNlIHsKCQkJCQkJdHJ5IHsKCQkJCQkJCXJlc3BvbnNlID0gY29udiggcmVzcG9uc2UgKTsKCQkJCQkJfSBjYXRjaCAoIGUgKSB7CgkJCQkJCQlyZXR1cm4geyBzdGF0ZTogInBhcnNlcmVycm9yIiwgZXJyb3I6IGNvbnYgPyBlIDogIk5vIGNvbnZlcnNpb24gZnJvbSAiICsgcHJldiArICIgdG8gIiArIGN1cnJlbnQgfTsKCQkJCQkJfQoJCQkJCX0KCQkJCX0KCQkJfQoJCX0KCX0KCglyZXR1cm4geyBzdGF0ZTogInN1Y2Nlc3MiLCBkYXRhOiByZXNwb25zZSB9Owp9CgpqUXVlcnkuZXh0ZW5kKHsKCgkvLyBDb3VudGVyIGZvciBob2xkaW5nIHRoZSBudW1iZXIgb2YgYWN0aXZlIHF1ZXJpZXMKCWFjdGl2ZTogMCwKCgkvLyBMYXN0LU1vZGlmaWVkIGhlYWRlciBjYWNoZSBmb3IgbmV4dCByZXF1ZXN0CglsYXN0TW9kaWZpZWQ6IHt9LAoJZXRhZzoge30sCgoJYWpheFNldHRpbmdzOiB7CgkJdXJsOiBhamF4TG9jYXRpb24sCgkJdHlwZTogIkdFVCIsCgkJaXNMb2NhbDogcmxvY2FsUHJvdG9jb2wudGVzdCggYWpheExvY1BhcnRzWyAxIF0gKSwKCQlnbG9iYWw6IHRydWUsCgkJcHJvY2Vzc0RhdGE6IHRydWUsCgkJYXN5bmM6IHRydWUsCgkJY29udGVudFR5cGU6ICJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7IGNoYXJzZXQ9VVRGLTgiLAoJCS8qCgkJdGltZW91dDogMCwKCQlkYXRhOiBudWxsLAoJCWRhdGFUeXBlOiBudWxsLAoJCXVzZXJuYW1lOiBudWxsLAoJCXBhc3N3b3JkOiBudWxsLAoJCWNhY2hlOiBudWxsLAoJCXRocm93czogZmFsc2UsCgkJdHJhZGl0aW9uYWw6IGZhbHNlLAoJCWhlYWRlcnM6IHt9LAoJCSovCgoJCWFjY2VwdHM6IHsKCQkJIioiOiBhbGxUeXBlcywKCQkJdGV4dDogInRleHQvcGxhaW4iLAoJCQlodG1sOiAidGV4dC9odG1sIiwKCQkJeG1sOiAiYXBwbGljYXRpb24veG1sLCB0ZXh0L3htbCIsCgkJCWpzb246ICJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFzY3JpcHQiCgkJfSwKCgkJY29udGVudHM6IHsKCQkJeG1sOiAveG1sLywKCQkJaHRtbDogL2h0bWwvLAoJCQlqc29uOiAvanNvbi8KCQl9LAoKCQlyZXNwb25zZUZpZWxkczogewoJCQl4bWw6ICJyZXNwb25zZVhNTCIsCgkJCXRleHQ6ICJyZXNwb25zZVRleHQiLAoJCQlqc29uOiAicmVzcG9uc2VKU09OIgoJCX0sCgoJCS8vIERhdGEgY29udmVydGVycwoJCS8vIEtleXMgc2VwYXJhdGUgc291cmNlIChvciBjYXRjaGFsbCAiKiIpIGFuZCBkZXN0aW5hdGlvbiB0eXBlcyB3aXRoIGEgc2luZ2xlIHNwYWNlCgkJY29udmVydGVyczogewoKCQkJLy8gQ29udmVydCBhbnl0aGluZyB0byB0ZXh0CgkJCSIqIHRleHQiOiBTdHJpbmcsCgoJCQkvLyBUZXh0IHRvIGh0bWwgKHRydWUgPSBubyB0cmFuc2Zvcm1hdGlvbikKCQkJInRleHQgaHRtbCI6IHRydWUsCgoJCQkvLyBFdmFsdWF0ZSB0ZXh0IGFzIGEganNvbiBleHByZXNzaW9uCgkJCSJ0ZXh0IGpzb24iOiBqUXVlcnkucGFyc2VKU09OLAoKCQkJLy8gUGFyc2UgdGV4dCBhcyB4bWwKCQkJInRleHQgeG1sIjogalF1ZXJ5LnBhcnNlWE1MCgkJfSwKCgkJLy8gRm9yIG9wdGlvbnMgdGhhdCBzaG91bGRuJ3QgYmUgZGVlcCBleHRlbmRlZDoKCQkvLyB5b3UgY2FuIGFkZCB5b3VyIG93biBjdXN0b20gb3B0aW9ucyBoZXJlIGlmCgkJLy8gYW5kIHdoZW4geW91IGNyZWF0ZSBvbmUgdGhhdCBzaG91bGRuJ3QgYmUKCQkvLyBkZWVwIGV4dGVuZGVkIChzZWUgYWpheEV4dGVuZCkKCQlmbGF0T3B0aW9uczogewoJCQl1cmw6IHRydWUsCgkJCWNvbnRleHQ6IHRydWUKCQl9Cgl9LAoKCS8vIENyZWF0ZXMgYSBmdWxsIGZsZWRnZWQgc2V0dGluZ3Mgb2JqZWN0IGludG8gdGFyZ2V0CgkvLyB3aXRoIGJvdGggYWpheFNldHRpbmdzIGFuZCBzZXR0aW5ncyBmaWVsZHMuCgkvLyBJZiB0YXJnZXQgaXMgb21pdHRlZCwgd3JpdGVzIGludG8gYWpheFNldHRpbmdzLgoJYWpheFNldHVwOiBmdW5jdGlvbiggdGFyZ2V0LCBzZXR0aW5ncyApIHsKCQlyZXR1cm4gc2V0dGluZ3MgPwoKCQkJLy8gQnVpbGRpbmcgYSBzZXR0aW5ncyBvYmplY3QKCQkJYWpheEV4dGVuZCggYWpheEV4dGVuZCggdGFyZ2V0LCBqUXVlcnkuYWpheFNldHRpbmdzICksIHNldHRpbmdzICkgOgoKCQkJLy8gRXh0ZW5kaW5nIGFqYXhTZXR0aW5ncwoJCQlhamF4RXh0ZW5kKCBqUXVlcnkuYWpheFNldHRpbmdzLCB0YXJnZXQgKTsKCX0sCgoJYWpheFByZWZpbHRlcjogYWRkVG9QcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBwcmVmaWx0ZXJzICksCglhamF4VHJhbnNwb3J0OiBhZGRUb1ByZWZpbHRlcnNPclRyYW5zcG9ydHMoIHRyYW5zcG9ydHMgKSwKCgkvLyBNYWluIG1ldGhvZAoJYWpheDogZnVuY3Rpb24oIHVybCwgb3B0aW9ucyApIHsKCgkJLy8gSWYgdXJsIGlzIGFuIG9iamVjdCwgc2ltdWxhdGUgcHJlLTEuNSBzaWduYXR1cmUKCQlpZiAoIHR5cGVvZiB1cmwgPT09ICJvYmplY3QiICkgewoJCQlvcHRpb25zID0gdXJsOwoJCQl1cmwgPSB1bmRlZmluZWQ7CgkJfQoKCQkvLyBGb3JjZSBvcHRpb25zIHRvIGJlIGFuIG9iamVjdAoJCW9wdGlvbnMgPSBvcHRpb25zIHx8IHt9OwoKCQl2YXIgdHJhbnNwb3J0LAoJCQkvLyBVUkwgd2l0aG91dCBhbnRpLWNhY2hlIHBhcmFtCgkJCWNhY2hlVVJMLAoJCQkvLyBSZXNwb25zZSBoZWFkZXJzCgkJCXJlc3BvbnNlSGVhZGVyc1N0cmluZywKCQkJcmVzcG9uc2VIZWFkZXJzLAoJCQkvLyB0aW1lb3V0IGhhbmRsZQoJCQl0aW1lb3V0VGltZXIsCgkJCS8vIENyb3NzLWRvbWFpbiBkZXRlY3Rpb24gdmFycwoJCQlwYXJ0cywKCQkJLy8gVG8ga25vdyBpZiBnbG9iYWwgZXZlbnRzIGFyZSB0byBiZSBkaXNwYXRjaGVkCgkJCWZpcmVHbG9iYWxzLAoJCQkvLyBMb29wIHZhcmlhYmxlCgkJCWksCgkJCS8vIENyZWF0ZSB0aGUgZmluYWwgb3B0aW9ucyBvYmplY3QKCQkJcyA9IGpRdWVyeS5hamF4U2V0dXAoIHt9LCBvcHRpb25zICksCgkJCS8vIENhbGxiYWNrcyBjb250ZXh0CgkJCWNhbGxiYWNrQ29udGV4dCA9IHMuY29udGV4dCB8fCBzLAoJCQkvLyBDb250ZXh0IGZvciBnbG9iYWwgZXZlbnRzIGlzIGNhbGxiYWNrQ29udGV4dCBpZiBpdCBpcyBhIERPTSBub2RlIG9yIGpRdWVyeSBjb2xsZWN0aW9uCgkJCWdsb2JhbEV2ZW50Q29udGV4dCA9IHMuY29udGV4dCAmJiAoIGNhbGxiYWNrQ29udGV4dC5ub2RlVHlwZSB8fCBjYWxsYmFja0NvbnRleHQuanF1ZXJ5ICkgPwoJCQkJalF1ZXJ5KCBjYWxsYmFja0NvbnRleHQgKSA6CgkJCQlqUXVlcnkuZXZlbnQsCgkJCS8vIERlZmVycmVkcwoJCQlkZWZlcnJlZCA9IGpRdWVyeS5EZWZlcnJlZCgpLAoJCQljb21wbGV0ZURlZmVycmVkID0galF1ZXJ5LkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwKCQkJLy8gU3RhdHVzLWRlcGVuZGVudCBjYWxsYmFja3MKCQkJc3RhdHVzQ29kZSA9IHMuc3RhdHVzQ29kZSB8fCB7fSwKCQkJLy8gSGVhZGVycyAodGhleSBhcmUgc2VudCBhbGwgYXQgb25jZSkKCQkJcmVxdWVzdEhlYWRlcnMgPSB7fSwKCQkJcmVxdWVzdEhlYWRlcnNOYW1lcyA9IHt9LAoJCQkvLyBUaGUganFYSFIgc3RhdGUKCQkJc3RhdGUgPSAwLAoJCQkvLyBEZWZhdWx0IGFib3J0IG1lc3NhZ2UKCQkJc3RyQWJvcnQgPSAiY2FuY2VsZWQiLAoJCQkvLyBGYWtlIHhocgoJCQlqcVhIUiA9IHsKCQkJCXJlYWR5U3RhdGU6IDAsCgoJCQkJLy8gQnVpbGRzIGhlYWRlcnMgaGFzaHRhYmxlIGlmIG5lZWRlZAoJCQkJZ2V0UmVzcG9uc2VIZWFkZXI6IGZ1bmN0aW9uKCBrZXkgKSB7CgkJCQkJdmFyIG1hdGNoOwoJCQkJCWlmICggc3RhdGUgPT09IDIgKSB7CgkJCQkJCWlmICggIXJlc3BvbnNlSGVhZGVycyApIHsKCQkJCQkJCXJlc3BvbnNlSGVhZGVycyA9IHt9OwoJCQkJCQkJd2hpbGUgKCAobWF0Y2ggPSByaGVhZGVycy5leGVjKCByZXNwb25zZUhlYWRlcnNTdHJpbmcgKSkgKSB7CgkJCQkJCQkJcmVzcG9uc2VIZWFkZXJzWyBtYXRjaFsxXS50b0xvd2VyQ2FzZSgpIF0gPSBtYXRjaFsgMiBdOwoJCQkJCQkJfQoJCQkJCQl9CgkJCQkJCW1hdGNoID0gcmVzcG9uc2VIZWFkZXJzWyBrZXkudG9Mb3dlckNhc2UoKSBdOwoJCQkJCX0KCQkJCQlyZXR1cm4gbWF0Y2ggPT0gbnVsbCA/IG51bGwgOiBtYXRjaDsKCQkJCX0sCgoJCQkJLy8gUmF3IHN0cmluZwoJCQkJZ2V0QWxsUmVzcG9uc2VIZWFkZXJzOiBmdW5jdGlvbigpIHsKCQkJCQlyZXR1cm4gc3RhdGUgPT09IDIgPyByZXNwb25zZUhlYWRlcnNTdHJpbmcgOiBudWxsOwoJCQkJfSwKCgkJCQkvLyBDYWNoZXMgdGhlIGhlYWRlcgoJCQkJc2V0UmVxdWVzdEhlYWRlcjogZnVuY3Rpb24oIG5hbWUsIHZhbHVlICkgewoJCQkJCXZhciBsbmFtZSA9IG5hbWUudG9Mb3dlckNhc2UoKTsKCQkJCQlpZiAoICFzdGF0ZSApIHsKCQkJCQkJbmFtZSA9IHJlcXVlc3RIZWFkZXJzTmFtZXNbIGxuYW1lIF0gPSByZXF1ZXN0SGVhZGVyc05hbWVzWyBsbmFtZSBdIHx8IG5hbWU7CgkJCQkJCXJlcXVlc3RIZWFkZXJzWyBuYW1lIF0gPSB2YWx1ZTsKCQkJCQl9CgkJCQkJcmV0dXJuIHRoaXM7CgkJCQl9LAoKCQkJCS8vIE92ZXJyaWRlcyByZXNwb25zZSBjb250ZW50LXR5cGUgaGVhZGVyCgkJCQlvdmVycmlkZU1pbWVUeXBlOiBmdW5jdGlvbiggdHlwZSApIHsKCQkJCQlpZiAoICFzdGF0ZSApIHsKCQkJCQkJcy5taW1lVHlwZSA9IHR5cGU7CgkJCQkJfQoJCQkJCXJldHVybiB0aGlzOwoJCQkJfSwKCgkJCQkvLyBTdGF0dXMtZGVwZW5kZW50IGNhbGxiYWNrcwoJCQkJc3RhdHVzQ29kZTogZnVuY3Rpb24oIG1hcCApIHsKCQkJCQl2YXIgY29kZTsKCQkJCQlpZiAoIG1hcCApIHsKCQkJCQkJaWYgKCBzdGF0ZSA8IDIgKSB7CgkJCQkJCQlmb3IgKCBjb2RlIGluIG1hcCApIHsKCQkJCQkJCQkvLyBMYXp5LWFkZCB0aGUgbmV3IGNhbGxiYWNrIGluIGEgd2F5IHRoYXQgcHJlc2VydmVzIG9sZCBvbmVzCgkJCQkJCQkJc3RhdHVzQ29kZVsgY29kZSBdID0gWyBzdGF0dXNDb2RlWyBjb2RlIF0sIG1hcFsgY29kZSBdIF07CgkJCQkJCQl9CgkJCQkJCX0gZWxzZSB7CgkJCQkJCQkvLyBFeGVjdXRlIHRoZSBhcHByb3ByaWF0ZSBjYWxsYmFja3MKCQkJCQkJCWpxWEhSLmFsd2F5cyggbWFwWyBqcVhIUi5zdGF0dXMgXSApOwoJCQkJCQl9CgkJCQkJfQoJCQkJCXJldHVybiB0aGlzOwoJCQkJfSwKCgkJCQkvLyBDYW5jZWwgdGhlIHJlcXVlc3QKCQkJCWFib3J0OiBmdW5jdGlvbiggc3RhdHVzVGV4dCApIHsKCQkJCQl2YXIgZmluYWxUZXh0ID0gc3RhdHVzVGV4dCB8fCBzdHJBYm9ydDsKCQkJCQlpZiAoIHRyYW5zcG9ydCApIHsKCQkJCQkJdHJhbnNwb3J0LmFib3J0KCBmaW5hbFRleHQgKTsKCQkJCQl9CgkJCQkJZG9uZSggMCwgZmluYWxUZXh0ICk7CgkJCQkJcmV0dXJuIHRoaXM7CgkJCQl9CgkJCX07CgoJCS8vIEF0dGFjaCBkZWZlcnJlZHMKCQlkZWZlcnJlZC5wcm9taXNlKCBqcVhIUiApLmNvbXBsZXRlID0gY29tcGxldGVEZWZlcnJlZC5hZGQ7CgkJanFYSFIuc3VjY2VzcyA9IGpxWEhSLmRvbmU7CgkJanFYSFIuZXJyb3IgPSBqcVhIUi5mYWlsOwoKCQkvLyBSZW1vdmUgaGFzaCBjaGFyYWN0ZXIgKCM3NTMxOiBhbmQgc3RyaW5nIHByb21vdGlvbikKCQkvLyBBZGQgcHJvdG9jb2wgaWYgbm90IHByb3ZpZGVkIChwcmVmaWx0ZXJzIG1pZ2h0IGV4cGVjdCBpdCkKCQkvLyBIYW5kbGUgZmFsc3kgdXJsIGluIHRoZSBzZXR0aW5ncyBvYmplY3QgKCMxMDA5MzogY29uc2lzdGVuY3kgd2l0aCBvbGQgc2lnbmF0dXJlKQoJCS8vIFdlIGFsc28gdXNlIHRoZSB1cmwgcGFyYW1ldGVyIGlmIGF2YWlsYWJsZQoJCXMudXJsID0gKCAoIHVybCB8fCBzLnVybCB8fCBhamF4TG9jYXRpb24gKSArICIiICkucmVwbGFjZSggcmhhc2gsICIiICkKCQkJLnJlcGxhY2UoIHJwcm90b2NvbCwgYWpheExvY1BhcnRzWyAxIF0gKyAiLy8iICk7CgoJCS8vIEFsaWFzIG1ldGhvZCBvcHRpb24gdG8gdHlwZSBhcyBwZXIgdGlja2V0ICMxMjAwNAoJCXMudHlwZSA9IG9wdGlvbnMubWV0aG9kIHx8IG9wdGlvbnMudHlwZSB8fCBzLm1ldGhvZCB8fCBzLnR5cGU7CgoJCS8vIEV4dHJhY3QgZGF0YVR5cGVzIGxpc3QKCQlzLmRhdGFUeXBlcyA9IGpRdWVyeS50cmltKCBzLmRhdGFUeXBlIHx8ICIqIiApLnRvTG93ZXJDYXNlKCkubWF0Y2goIHJub3R3aGl0ZSApIHx8IFsgIiIgXTsKCgkJLy8gQSBjcm9zcy1kb21haW4gcmVxdWVzdCBpcyBpbiBvcmRlciB3aGVuIHdlIGhhdmUgYSBwcm90b2NvbDpob3N0OnBvcnQgbWlzbWF0Y2gKCQlpZiAoIHMuY3Jvc3NEb21haW4gPT0gbnVsbCApIHsKCQkJcGFydHMgPSBydXJsLmV4ZWMoIHMudXJsLnRvTG93ZXJDYXNlKCkgKTsKCQkJcy5jcm9zc0RvbWFpbiA9ICEhKCBwYXJ0cyAmJgoJCQkJKCBwYXJ0c1sgMSBdICE9PSBhamF4TG9jUGFydHNbIDEgXSB8fCBwYXJ0c1sgMiBdICE9PSBhamF4TG9jUGFydHNbIDIgXSB8fAoJCQkJCSggcGFydHNbIDMgXSB8fCAoIHBhcnRzWyAxIF0gPT09ICJodHRwOiIgPyAiODAiIDogIjQ0MyIgKSApICE9PQoJCQkJCQkoIGFqYXhMb2NQYXJ0c1sgMyBdIHx8ICggYWpheExvY1BhcnRzWyAxIF0gPT09ICJodHRwOiIgPyAiODAiIDogIjQ0MyIgKSApICkKCQkJKTsKCQl9CgoJCS8vIENvbnZlcnQgZGF0YSBpZiBub3QgYWxyZWFkeSBhIHN0cmluZwoJCWlmICggcy5kYXRhICYmIHMucHJvY2Vzc0RhdGEgJiYgdHlwZW9mIHMuZGF0YSAhPT0gInN0cmluZyIgKSB7CgkJCXMuZGF0YSA9IGpRdWVyeS5wYXJhbSggcy5kYXRhLCBzLnRyYWRpdGlvbmFsICk7CgkJfQoKCQkvLyBBcHBseSBwcmVmaWx0ZXJzCgkJaW5zcGVjdFByZWZpbHRlcnNPclRyYW5zcG9ydHMoIHByZWZpbHRlcnMsIHMsIG9wdGlvbnMsIGpxWEhSICk7CgoJCS8vIElmIHJlcXVlc3Qgd2FzIGFib3J0ZWQgaW5zaWRlIGEgcHJlZmlsdGVyLCBzdG9wIHRoZXJlCgkJaWYgKCBzdGF0ZSA9PT0gMiApIHsKCQkJcmV0dXJuIGpxWEhSOwoJCX0KCgkJLy8gV2UgY2FuIGZpcmUgZ2xvYmFsIGV2ZW50cyBhcyBvZiBub3cgaWYgYXNrZWQgdG8KCQlmaXJlR2xvYmFscyA9IHMuZ2xvYmFsOwoKCQkvLyBXYXRjaCBmb3IgYSBuZXcgc2V0IG9mIHJlcXVlc3RzCgkJaWYgKCBmaXJlR2xvYmFscyAmJiBqUXVlcnkuYWN0aXZlKysgPT09IDAgKSB7CgkJCWpRdWVyeS5ldmVudC50cmlnZ2VyKCJhamF4U3RhcnQiKTsKCQl9CgoJCS8vIFVwcGVyY2FzZSB0aGUgdHlwZQoJCXMudHlwZSA9IHMudHlwZS50b1VwcGVyQ2FzZSgpOwoKCQkvLyBEZXRlcm1pbmUgaWYgcmVxdWVzdCBoYXMgY29udGVudAoJCXMuaGFzQ29udGVudCA9ICFybm9Db250ZW50LnRlc3QoIHMudHlwZSApOwoKCQkvLyBTYXZlIHRoZSBVUkwgaW4gY2FzZSB3ZSdyZSB0b3lpbmcgd2l0aCB0aGUgSWYtTW9kaWZpZWQtU2luY2UKCQkvLyBhbmQvb3IgSWYtTm9uZS1NYXRjaCBoZWFkZXIgbGF0ZXIgb24KCQljYWNoZVVSTCA9IHMudXJsOwoKCQkvLyBNb3JlIG9wdGlvbnMgaGFuZGxpbmcgZm9yIHJlcXVlc3RzIHdpdGggbm8gY29udGVudAoJCWlmICggIXMuaGFzQ29udGVudCApIHsKCgkJCS8vIElmIGRhdGEgaXMgYXZhaWxhYmxlLCBhcHBlbmQgZGF0YSB0byB1cmwKCQkJaWYgKCBzLmRhdGEgKSB7CgkJCQljYWNoZVVSTCA9ICggcy51cmwgKz0gKCBycXVlcnkudGVzdCggY2FjaGVVUkwgKSA/ICImIiA6ICI/IiApICsgcy5kYXRhICk7CgkJCQkvLyAjOTY4MjogcmVtb3ZlIGRhdGEgc28gdGhhdCBpdCdzIG5vdCB1c2VkIGluIGFuIGV2ZW50dWFsIHJldHJ5CgkJCQlkZWxldGUgcy5kYXRhOwoJCQl9CgoJCQkvLyBBZGQgYW50aS1jYWNoZSBpbiB1cmwgaWYgbmVlZGVkCgkJCWlmICggcy5jYWNoZSA9PT0gZmFsc2UgKSB7CgkJCQlzLnVybCA9IHJ0cy50ZXN0KCBjYWNoZVVSTCApID8KCgkJCQkJLy8gSWYgdGhlcmUgaXMgYWxyZWFkeSBhICdfJyBwYXJhbWV0ZXIsIHNldCBpdHMgdmFsdWUKCQkJCQljYWNoZVVSTC5yZXBsYWNlKCBydHMsICIkMV89IiArIG5vbmNlKysgKSA6CgoJCQkJCS8vIE90aGVyd2lzZSBhZGQgb25lIHRvIHRoZSBlbmQKCQkJCQljYWNoZVVSTCArICggcnF1ZXJ5LnRlc3QoIGNhY2hlVVJMICkgPyAiJiIgOiAiPyIgKSArICJfPSIgKyBub25jZSsrOwoJCQl9CgkJfQoKCQkvLyBTZXQgdGhlIElmLU1vZGlmaWVkLVNpbmNlIGFuZC9vciBJZi1Ob25lLU1hdGNoIGhlYWRlciwgaWYgaW4gaWZNb2RpZmllZCBtb2RlLgoJCWlmICggcy5pZk1vZGlmaWVkICkgewoJCQlpZiAoIGpRdWVyeS5sYXN0TW9kaWZpZWRbIGNhY2hlVVJMIF0gKSB7CgkJCQlqcVhIUi5zZXRSZXF1ZXN0SGVhZGVyKCAiSWYtTW9kaWZpZWQtU2luY2UiLCBqUXVlcnkubGFzdE1vZGlmaWVkWyBjYWNoZVVSTCBdICk7CgkJCX0KCQkJaWYgKCBqUXVlcnkuZXRhZ1sgY2FjaGVVUkwgXSApIHsKCQkJCWpxWEhSLnNldFJlcXVlc3RIZWFkZXIoICJJZi1Ob25lLU1hdGNoIiwgalF1ZXJ5LmV0YWdbIGNhY2hlVVJMIF0gKTsKCQkJfQoJCX0KCgkJLy8gU2V0IHRoZSBjb3JyZWN0IGhlYWRlciwgaWYgZGF0YSBpcyBiZWluZyBzZW50CgkJaWYgKCBzLmRhdGEgJiYgcy5oYXNDb250ZW50ICYmIHMuY29udGVudFR5cGUgIT09IGZhbHNlIHx8IG9wdGlvbnMuY29udGVudFR5cGUgKSB7CgkJCWpxWEhSLnNldFJlcXVlc3RIZWFkZXIoICJDb250ZW50LVR5cGUiLCBzLmNvbnRlbnRUeXBlICk7CgkJfQoKCQkvLyBTZXQgdGhlIEFjY2VwdHMgaGVhZGVyIGZvciB0aGUgc2VydmVyLCBkZXBlbmRpbmcgb24gdGhlIGRhdGFUeXBlCgkJanFYSFIuc2V0UmVxdWVzdEhlYWRlcigKCQkJIkFjY2VwdCIsCgkJCXMuZGF0YVR5cGVzWyAwIF0gJiYgcy5hY2NlcHRzWyBzLmRhdGFUeXBlc1swXSBdID8KCQkJCXMuYWNjZXB0c1sgcy5kYXRhVHlwZXNbMF0gXSArICggcy5kYXRhVHlwZXNbIDAgXSAhPT0gIioiID8gIiwgIiArIGFsbFR5cGVzICsgIjsgcT0wLjAxIiA6ICIiICkgOgoJCQkJcy5hY2NlcHRzWyAiKiIgXQoJCSk7CgoJCS8vIENoZWNrIGZvciBoZWFkZXJzIG9wdGlvbgoJCWZvciAoIGkgaW4gcy5oZWFkZXJzICkgewoJCQlqcVhIUi5zZXRSZXF1ZXN0SGVhZGVyKCBpLCBzLmhlYWRlcnNbIGkgXSApOwoJCX0KCgkJLy8gQWxsb3cgY3VzdG9tIGhlYWRlcnMvbWltZXR5cGVzIGFuZCBlYXJseSBhYm9ydAoJCWlmICggcy5iZWZvcmVTZW5kICYmICggcy5iZWZvcmVTZW5kLmNhbGwoIGNhbGxiYWNrQ29udGV4dCwganFYSFIsIHMgKSA9PT0gZmFsc2UgfHwgc3RhdGUgPT09IDIgKSApIHsKCQkJLy8gQWJvcnQgaWYgbm90IGRvbmUgYWxyZWFkeSBhbmQgcmV0dXJuCgkJCXJldHVybiBqcVhIUi5hYm9ydCgpOwoJCX0KCgkJLy8gYWJvcnRpbmcgaXMgbm8gbG9uZ2VyIGEgY2FuY2VsbGF0aW9uCgkJc3RyQWJvcnQgPSAiYWJvcnQiOwoKCQkvLyBJbnN0YWxsIGNhbGxiYWNrcyBvbiBkZWZlcnJlZHMKCQlmb3IgKCBpIGluIHsgc3VjY2VzczogMSwgZXJyb3I6IDEsIGNvbXBsZXRlOiAxIH0gKSB7CgkJCWpxWEhSWyBpIF0oIHNbIGkgXSApOwoJCX0KCgkJLy8gR2V0IHRyYW5zcG9ydAoJCXRyYW5zcG9ydCA9IGluc3BlY3RQcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCB0cmFuc3BvcnRzLCBzLCBvcHRpb25zLCBqcVhIUiApOwoKCQkvLyBJZiBubyB0cmFuc3BvcnQsIHdlIGF1dG8tYWJvcnQKCQlpZiAoICF0cmFuc3BvcnQgKSB7CgkJCWRvbmUoIC0xLCAiTm8gVHJhbnNwb3J0IiApOwoJCX0gZWxzZSB7CgkJCWpxWEhSLnJlYWR5U3RhdGUgPSAxOwoKCQkJLy8gU2VuZCBnbG9iYWwgZXZlbnQKCQkJaWYgKCBmaXJlR2xvYmFscyApIHsKCQkJCWdsb2JhbEV2ZW50Q29udGV4dC50cmlnZ2VyKCAiYWpheFNlbmQiLCBbIGpxWEhSLCBzIF0gKTsKCQkJfQoJCQkvLyBUaW1lb3V0CgkJCWlmICggcy5hc3luYyAmJiBzLnRpbWVvdXQgPiAwICkgewoJCQkJdGltZW91dFRpbWVyID0gc2V0VGltZW91dChmdW5jdGlvbigpIHsKCQkJCQlqcVhIUi5hYm9ydCgidGltZW91dCIpOwoJCQkJfSwgcy50aW1lb3V0ICk7CgkJCX0KCgkJCXRyeSB7CgkJCQlzdGF0ZSA9IDE7CgkJCQl0cmFuc3BvcnQuc2VuZCggcmVxdWVzdEhlYWRlcnMsIGRvbmUgKTsKCQkJfSBjYXRjaCAoIGUgKSB7CgkJCQkvLyBQcm9wYWdhdGUgZXhjZXB0aW9uIGFzIGVycm9yIGlmIG5vdCBkb25lCgkJCQlpZiAoIHN0YXRlIDwgMiApIHsKCQkJCQlkb25lKCAtMSwgZSApOwoJCQkJLy8gU2ltcGx5IHJldGhyb3cgb3RoZXJ3aXNlCgkJCQl9IGVsc2UgewoJCQkJCXRocm93IGU7CgkJCQl9CgkJCX0KCQl9CgoJCS8vIENhbGxiYWNrIGZvciB3aGVuIGV2ZXJ5dGhpbmcgaXMgZG9uZQoJCWZ1bmN0aW9uIGRvbmUoIHN0YXR1cywgbmF0aXZlU3RhdHVzVGV4dCwgcmVzcG9uc2VzLCBoZWFkZXJzICkgewoJCQl2YXIgaXNTdWNjZXNzLCBzdWNjZXNzLCBlcnJvciwgcmVzcG9uc2UsIG1vZGlmaWVkLAoJCQkJc3RhdHVzVGV4dCA9IG5hdGl2ZVN0YXR1c1RleHQ7CgoJCQkvLyBDYWxsZWQgb25jZQoJCQlpZiAoIHN0YXRlID09PSAyICkgewoJCQkJcmV0dXJuOwoJCQl9CgoJCQkvLyBTdGF0ZSBpcyAiZG9uZSIgbm93CgkJCXN0YXRlID0gMjsKCgkJCS8vIENsZWFyIHRpbWVvdXQgaWYgaXQgZXhpc3RzCgkJCWlmICggdGltZW91dFRpbWVyICkgewoJCQkJY2xlYXJUaW1lb3V0KCB0aW1lb3V0VGltZXIgKTsKCQkJfQoKCQkJLy8gRGVyZWZlcmVuY2UgdHJhbnNwb3J0IGZvciBlYXJseSBnYXJiYWdlIGNvbGxlY3Rpb24KCQkJLy8gKG5vIG1hdHRlciBob3cgbG9uZyB0aGUganFYSFIgb2JqZWN0IHdpbGwgYmUgdXNlZCkKCQkJdHJhbnNwb3J0ID0gdW5kZWZpbmVkOwoKCQkJLy8gQ2FjaGUgcmVzcG9uc2UgaGVhZGVycwoJCQlyZXNwb25zZUhlYWRlcnNTdHJpbmcgPSBoZWFkZXJzIHx8ICIiOwoKCQkJLy8gU2V0IHJlYWR5U3RhdGUKCQkJanFYSFIucmVhZHlTdGF0ZSA9IHN0YXR1cyA+IDAgPyA0IDogMDsKCgkJCS8vIERldGVybWluZSBpZiBzdWNjZXNzZnVsCgkJCWlzU3VjY2VzcyA9IHN0YXR1cyA+PSAyMDAgJiYgc3RhdHVzIDwgMzAwIHx8IHN0YXR1cyA9PT0gMzA0OwoKCQkJLy8gR2V0IHJlc3BvbnNlIGRhdGEKCQkJaWYgKCByZXNwb25zZXMgKSB7CgkJCQlyZXNwb25zZSA9IGFqYXhIYW5kbGVSZXNwb25zZXMoIHMsIGpxWEhSLCByZXNwb25zZXMgKTsKCQkJfQoKCQkJLy8gQ29udmVydCBubyBtYXR0ZXIgd2hhdCAodGhhdCB3YXkgcmVzcG9uc2VYWFggZmllbGRzIGFyZSBhbHdheXMgc2V0KQoJCQlyZXNwb25zZSA9IGFqYXhDb252ZXJ0KCBzLCByZXNwb25zZSwganFYSFIsIGlzU3VjY2VzcyApOwoKCQkJLy8gSWYgc3VjY2Vzc2Z1bCwgaGFuZGxlIHR5cGUgY2hhaW5pbmcKCQkJaWYgKCBpc1N1Y2Nlc3MgKSB7CgoJCQkJLy8gU2V0IHRoZSBJZi1Nb2RpZmllZC1TaW5jZSBhbmQvb3IgSWYtTm9uZS1NYXRjaCBoZWFkZXIsIGlmIGluIGlmTW9kaWZpZWQgbW9kZS4KCQkJCWlmICggcy5pZk1vZGlmaWVkICkgewoJCQkJCW1vZGlmaWVkID0ganFYSFIuZ2V0UmVzcG9uc2VIZWFkZXIoIkxhc3QtTW9kaWZpZWQiKTsKCQkJCQlpZiAoIG1vZGlmaWVkICkgewoJCQkJCQlqUXVlcnkubGFzdE1vZGlmaWVkWyBjYWNoZVVSTCBdID0gbW9kaWZpZWQ7CgkJCQkJfQoJCQkJCW1vZGlmaWVkID0ganFYSFIuZ2V0UmVzcG9uc2VIZWFkZXIoImV0YWciKTsKCQkJCQlpZiAoIG1vZGlmaWVkICkgewoJCQkJCQlqUXVlcnkuZXRhZ1sgY2FjaGVVUkwgXSA9IG1vZGlmaWVkOwoJCQkJCX0KCQkJCX0KCgkJCQkvLyBpZiBubyBjb250ZW50CgkJCQlpZiAoIHN0YXR1cyA9PT0gMjA0IHx8IHMudHlwZSA9PT0gIkhFQUQiICkgewoJCQkJCXN0YXR1c1RleHQgPSAibm9jb250ZW50IjsKCgkJCQkvLyBpZiBub3QgbW9kaWZpZWQKCQkJCX0gZWxzZSBpZiAoIHN0YXR1cyA9PT0gMzA0ICkgewoJCQkJCXN0YXR1c1RleHQgPSAibm90bW9kaWZpZWQiOwoKCQkJCS8vIElmIHdlIGhhdmUgZGF0YSwgbGV0J3MgY29udmVydCBpdAoJCQkJfSBlbHNlIHsKCQkJCQlzdGF0dXNUZXh0ID0gcmVzcG9uc2Uuc3RhdGU7CgkJCQkJc3VjY2VzcyA9IHJlc3BvbnNlLmRhdGE7CgkJCQkJZXJyb3IgPSByZXNwb25zZS5lcnJvcjsKCQkJCQlpc1N1Y2Nlc3MgPSAhZXJyb3I7CgkJCQl9CgkJCX0gZWxzZSB7CgkJCQkvLyBXZSBleHRyYWN0IGVycm9yIGZyb20gc3RhdHVzVGV4dAoJCQkJLy8gdGhlbiBub3JtYWxpemUgc3RhdHVzVGV4dCBhbmQgc3RhdHVzIGZvciBub24tYWJvcnRzCgkJCQllcnJvciA9IHN0YXR1c1RleHQ7CgkJCQlpZiAoIHN0YXR1cyB8fCAhc3RhdHVzVGV4dCApIHsKCQkJCQlzdGF0dXNUZXh0ID0gImVycm9yIjsKCQkJCQlpZiAoIHN0YXR1cyA8IDAgKSB7CgkJCQkJCXN0YXR1cyA9IDA7CgkJCQkJfQoJCQkJfQoJCQl9CgoJCQkvLyBTZXQgZGF0YSBmb3IgdGhlIGZha2UgeGhyIG9iamVjdAoJCQlqcVhIUi5zdGF0dXMgPSBzdGF0dXM7CgkJCWpxWEhSLnN0YXR1c1RleHQgPSAoIG5hdGl2ZVN0YXR1c1RleHQgfHwgc3RhdHVzVGV4dCApICsgIiI7CgoJCQkvLyBTdWNjZXNzL0Vycm9yCgkJCWlmICggaXNTdWNjZXNzICkgewoJCQkJZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGNhbGxiYWNrQ29udGV4dCwgWyBzdWNjZXNzLCBzdGF0dXNUZXh0LCBqcVhIUiBdICk7CgkJCX0gZWxzZSB7CgkJCQlkZWZlcnJlZC5yZWplY3RXaXRoKCBjYWxsYmFja0NvbnRleHQsIFsganFYSFIsIHN0YXR1c1RleHQsIGVycm9yIF0gKTsKCQkJfQoKCQkJLy8gU3RhdHVzLWRlcGVuZGVudCBjYWxsYmFja3MKCQkJanFYSFIuc3RhdHVzQ29kZSggc3RhdHVzQ29kZSApOwoJCQlzdGF0dXNDb2RlID0gdW5kZWZpbmVkOwoKCQkJaWYgKCBmaXJlR2xvYmFscyApIHsKCQkJCWdsb2JhbEV2ZW50Q29udGV4dC50cmlnZ2VyKCBpc1N1Y2Nlc3MgPyAiYWpheFN1Y2Nlc3MiIDogImFqYXhFcnJvciIsCgkJCQkJWyBqcVhIUiwgcywgaXNTdWNjZXNzID8gc3VjY2VzcyA6IGVycm9yIF0gKTsKCQkJfQoKCQkJLy8gQ29tcGxldGUKCQkJY29tcGxldGVEZWZlcnJlZC5maXJlV2l0aCggY2FsbGJhY2tDb250ZXh0LCBbIGpxWEhSLCBzdGF0dXNUZXh0IF0gKTsKCgkJCWlmICggZmlyZUdsb2JhbHMgKSB7CgkJCQlnbG9iYWxFdmVudENvbnRleHQudHJpZ2dlciggImFqYXhDb21wbGV0ZSIsIFsganFYSFIsIHMgXSApOwoJCQkJLy8gSGFuZGxlIHRoZSBnbG9iYWwgQUpBWCBjb3VudGVyCgkJCQlpZiAoICEoIC0talF1ZXJ5LmFjdGl2ZSApICkgewoJCQkJCWpRdWVyeS5ldmVudC50cmlnZ2VyKCJhamF4U3RvcCIpOwoJCQkJfQoJCQl9CgkJfQoKCQlyZXR1cm4ganFYSFI7Cgl9LAoKCWdldEpTT046IGZ1bmN0aW9uKCB1cmwsIGRhdGEsIGNhbGxiYWNrICkgewoJCXJldHVybiBqUXVlcnkuZ2V0KCB1cmwsIGRhdGEsIGNhbGxiYWNrLCAianNvbiIgKTsKCX0sCgoJZ2V0U2NyaXB0OiBmdW5jdGlvbiggdXJsLCBjYWxsYmFjayApIHsKCQlyZXR1cm4galF1ZXJ5LmdldCggdXJsLCB1bmRlZmluZWQsIGNhbGxiYWNrLCAic2NyaXB0IiApOwoJfQp9KTsKCmpRdWVyeS5lYWNoKCBbICJnZXQiLCAicG9zdCIgXSwgZnVuY3Rpb24oIGksIG1ldGhvZCApIHsKCWpRdWVyeVsgbWV0aG9kIF0gPSBmdW5jdGlvbiggdXJsLCBkYXRhLCBjYWxsYmFjaywgdHlwZSApIHsKCQkvLyBzaGlmdCBhcmd1bWVudHMgaWYgZGF0YSBhcmd1bWVudCB3YXMgb21pdHRlZAoJCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIGRhdGEgKSApIHsKCQkJdHlwZSA9IHR5cGUgfHwgY2FsbGJhY2s7CgkJCWNhbGxiYWNrID0gZGF0YTsKCQkJZGF0YSA9IHVuZGVmaW5lZDsKCQl9CgoJCXJldHVybiBqUXVlcnkuYWpheCh7CgkJCXVybDogdXJsLAoJCQl0eXBlOiBtZXRob2QsCgkJCWRhdGFUeXBlOiB0eXBlLAoJCQlkYXRhOiBkYXRhLAoJCQlzdWNjZXNzOiBjYWxsYmFjawoJCX0pOwoJfTsKfSk7CgovLyBBdHRhY2ggYSBidW5jaCBvZiBmdW5jdGlvbnMgZm9yIGhhbmRsaW5nIGNvbW1vbiBBSkFYIGV2ZW50cwpqUXVlcnkuZWFjaCggWyAiYWpheFN0YXJ0IiwgImFqYXhTdG9wIiwgImFqYXhDb21wbGV0ZSIsICJhamF4RXJyb3IiLCAiYWpheFN1Y2Nlc3MiLCAiYWpheFNlbmQiIF0sIGZ1bmN0aW9uKCBpLCB0eXBlICkgewoJalF1ZXJ5LmZuWyB0eXBlIF0gPSBmdW5jdGlvbiggZm4gKSB7CgkJcmV0dXJuIHRoaXMub24oIHR5cGUsIGZuICk7Cgl9Owp9KTsKCgpqUXVlcnkuX2V2YWxVcmwgPSBmdW5jdGlvbiggdXJsICkgewoJcmV0dXJuIGpRdWVyeS5hamF4KHsKCQl1cmw6IHVybCwKCQl0eXBlOiAiR0VUIiwKCQlkYXRhVHlwZTogInNjcmlwdCIsCgkJYXN5bmM6IGZhbHNlLAoJCWdsb2JhbDogZmFsc2UsCgkJInRocm93cyI6IHRydWUKCX0pOwp9OwoKCmpRdWVyeS5mbi5leHRlbmQoewoJd3JhcEFsbDogZnVuY3Rpb24oIGh0bWwgKSB7CgkJdmFyIHdyYXA7CgoJCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIGh0bWwgKSApIHsKCQkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiggaSApIHsKCQkJCWpRdWVyeSggdGhpcyApLndyYXBBbGwoIGh0bWwuY2FsbCh0aGlzLCBpKSApOwoJCQl9KTsKCQl9CgoJCWlmICggdGhpc1sgMCBdICkgewoKCQkJLy8gVGhlIGVsZW1lbnRzIHRvIHdyYXAgdGhlIHRhcmdldCBhcm91bmQKCQkJd3JhcCA9IGpRdWVyeSggaHRtbCwgdGhpc1sgMCBdLm93bmVyRG9jdW1lbnQgKS5lcSggMCApLmNsb25lKCB0cnVlICk7CgoJCQlpZiAoIHRoaXNbIDAgXS5wYXJlbnROb2RlICkgewoJCQkJd3JhcC5pbnNlcnRCZWZvcmUoIHRoaXNbIDAgXSApOwoJCQl9CgoJCQl3cmFwLm1hcChmdW5jdGlvbigpIHsKCQkJCXZhciBlbGVtID0gdGhpczsKCgkJCQl3aGlsZSAoIGVsZW0uZmlyc3RFbGVtZW50Q2hpbGQgKSB7CgkJCQkJZWxlbSA9IGVsZW0uZmlyc3RFbGVtZW50Q2hpbGQ7CgkJCQl9CgoJCQkJcmV0dXJuIGVsZW07CgkJCX0pLmFwcGVuZCggdGhpcyApOwoJCX0KCgkJcmV0dXJuIHRoaXM7Cgl9LAoKCXdyYXBJbm5lcjogZnVuY3Rpb24oIGh0bWwgKSB7CgkJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggaHRtbCApICkgewoJCQlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCBpICkgewoJCQkJalF1ZXJ5KCB0aGlzICkud3JhcElubmVyKCBodG1sLmNhbGwodGhpcywgaSkgKTsKCQkJfSk7CgkJfQoKCQlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkgewoJCQl2YXIgc2VsZiA9IGpRdWVyeSggdGhpcyApLAoJCQkJY29udGVudHMgPSBzZWxmLmNvbnRlbnRzKCk7CgoJCQlpZiAoIGNvbnRlbnRzLmxlbmd0aCApIHsKCQkJCWNvbnRlbnRzLndyYXBBbGwoIGh0bWwgKTsKCgkJCX0gZWxzZSB7CgkJCQlzZWxmLmFwcGVuZCggaHRtbCApOwoJCQl9CgkJfSk7Cgl9LAoKCXdyYXA6IGZ1bmN0aW9uKCBodG1sICkgewoJCXZhciBpc0Z1bmN0aW9uID0galF1ZXJ5LmlzRnVuY3Rpb24oIGh0bWwgKTsKCgkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiggaSApIHsKCQkJalF1ZXJ5KCB0aGlzICkud3JhcEFsbCggaXNGdW5jdGlvbiA/IGh0bWwuY2FsbCh0aGlzLCBpKSA6IGh0bWwgKTsKCQl9KTsKCX0sCgoJdW53cmFwOiBmdW5jdGlvbigpIHsKCQlyZXR1cm4gdGhpcy5wYXJlbnQoKS5lYWNoKGZ1bmN0aW9uKCkgewoJCQlpZiAoICFqUXVlcnkubm9kZU5hbWUoIHRoaXMsICJib2R5IiApICkgewoJCQkJalF1ZXJ5KCB0aGlzICkucmVwbGFjZVdpdGgoIHRoaXMuY2hpbGROb2RlcyApOwoJCQl9CgkJfSkuZW5kKCk7Cgl9Cn0pOwoKCmpRdWVyeS5leHByLmZpbHRlcnMuaGlkZGVuID0gZnVuY3Rpb24oIGVsZW0gKSB7CgkvLyBTdXBwb3J0OiBPcGVyYSA8PSAxMi4xMgoJLy8gT3BlcmEgcmVwb3J0cyBvZmZzZXRXaWR0aHMgYW5kIG9mZnNldEhlaWdodHMgbGVzcyB0aGFuIHplcm8gb24gc29tZSBlbGVtZW50cwoJcmV0dXJuIGVsZW0ub2Zmc2V0V2lkdGggPD0gMCAmJiBlbGVtLm9mZnNldEhlaWdodCA8PSAwOwp9OwpqUXVlcnkuZXhwci5maWx0ZXJzLnZpc2libGUgPSBmdW5jdGlvbiggZWxlbSApIHsKCXJldHVybiAhalF1ZXJ5LmV4cHIuZmlsdGVycy5oaWRkZW4oIGVsZW0gKTsKfTsKCgoKCnZhciByMjAgPSAvJTIwL2csCglyYnJhY2tldCA9IC9cW1xdJC8sCglyQ1JMRiA9IC9ccj9cbi9nLAoJcnN1Ym1pdHRlclR5cGVzID0gL14oPzpzdWJtaXR8YnV0dG9ufGltYWdlfHJlc2V0fGZpbGUpJC9pLAoJcnN1Ym1pdHRhYmxlID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8a2V5Z2VuKS9pOwoKZnVuY3Rpb24gYnVpbGRQYXJhbXMoIHByZWZpeCwgb2JqLCB0cmFkaXRpb25hbCwgYWRkICkgewoJdmFyIG5hbWU7CgoJaWYgKCBqUXVlcnkuaXNBcnJheSggb2JqICkgKSB7CgkJLy8gU2VyaWFsaXplIGFycmF5IGl0ZW0uCgkJalF1ZXJ5LmVhY2goIG9iaiwgZnVuY3Rpb24oIGksIHYgKSB7CgkJCWlmICggdHJhZGl0aW9uYWwgfHwgcmJyYWNrZXQudGVzdCggcHJlZml4ICkgKSB7CgkJCQkvLyBUcmVhdCBlYWNoIGFycmF5IGl0ZW0gYXMgYSBzY2FsYXIuCgkJCQlhZGQoIHByZWZpeCwgdiApOwoKCQkJfSBlbHNlIHsKCQkJCS8vIEl0ZW0gaXMgbm9uLXNjYWxhciAoYXJyYXkgb3Igb2JqZWN0KSwgZW5jb2RlIGl0cyBudW1lcmljIGluZGV4LgoJCQkJYnVpbGRQYXJhbXMoIHByZWZpeCArICJbIiArICggdHlwZW9mIHYgPT09ICJvYmplY3QiID8gaSA6ICIiICkgKyAiXSIsIHYsIHRyYWRpdGlvbmFsLCBhZGQgKTsKCQkJfQoJCX0pOwoKCX0gZWxzZSBpZiAoICF0cmFkaXRpb25hbCAmJiBqUXVlcnkudHlwZSggb2JqICkgPT09ICJvYmplY3QiICkgewoJCS8vIFNlcmlhbGl6ZSBvYmplY3QgaXRlbS4KCQlmb3IgKCBuYW1lIGluIG9iaiApIHsKCQkJYnVpbGRQYXJhbXMoIHByZWZpeCArICJbIiArIG5hbWUgKyAiXSIsIG9ialsgbmFtZSBdLCB0cmFkaXRpb25hbCwgYWRkICk7CgkJfQoKCX0gZWxzZSB7CgkJLy8gU2VyaWFsaXplIHNjYWxhciBpdGVtLgoJCWFkZCggcHJlZml4LCBvYmogKTsKCX0KfQoKLy8gU2VyaWFsaXplIGFuIGFycmF5IG9mIGZvcm0gZWxlbWVudHMgb3IgYSBzZXQgb2YKLy8ga2V5L3ZhbHVlcyBpbnRvIGEgcXVlcnkgc3RyaW5nCmpRdWVyeS5wYXJhbSA9IGZ1bmN0aW9uKCBhLCB0cmFkaXRpb25hbCApIHsKCXZhciBwcmVmaXgsCgkJcyA9IFtdLAoJCWFkZCA9IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkgewoJCQkvLyBJZiB2YWx1ZSBpcyBhIGZ1bmN0aW9uLCBpbnZva2UgaXQgYW5kIHJldHVybiBpdHMgdmFsdWUKCQkJdmFsdWUgPSBqUXVlcnkuaXNGdW5jdGlvbiggdmFsdWUgKSA/IHZhbHVlKCkgOiAoIHZhbHVlID09IG51bGwgPyAiIiA6IHZhbHVlICk7CgkJCXNbIHMubGVuZ3RoIF0gPSBlbmNvZGVVUklDb21wb25lbnQoIGtleSApICsgIj0iICsgZW5jb2RlVVJJQ29tcG9uZW50KCB2YWx1ZSApOwoJCX07CgoJLy8gU2V0IHRyYWRpdGlvbmFsIHRvIHRydWUgZm9yIGpRdWVyeSA8PSAxLjMuMiBiZWhhdmlvci4KCWlmICggdHJhZGl0aW9uYWwgPT09IHVuZGVmaW5lZCApIHsKCQl0cmFkaXRpb25hbCA9IGpRdWVyeS5hamF4U2V0dGluZ3MgJiYgalF1ZXJ5LmFqYXhTZXR0aW5ncy50cmFkaXRpb25hbDsKCX0KCgkvLyBJZiBhbiBhcnJheSB3YXMgcGFzc2VkIGluLCBhc3N1bWUgdGhhdCBpdCBpcyBhbiBhcnJheSBvZiBmb3JtIGVsZW1lbnRzLgoJaWYgKCBqUXVlcnkuaXNBcnJheSggYSApIHx8ICggYS5qcXVlcnkgJiYgIWpRdWVyeS5pc1BsYWluT2JqZWN0KCBhICkgKSApIHsKCQkvLyBTZXJpYWxpemUgdGhlIGZvcm0gZWxlbWVudHMKCQlqUXVlcnkuZWFjaCggYSwgZnVuY3Rpb24oKSB7CgkJCWFkZCggdGhpcy5uYW1lLCB0aGlzLnZhbHVlICk7CgkJfSk7CgoJfSBlbHNlIHsKCQkvLyBJZiB0cmFkaXRpb25hbCwgZW5jb2RlIHRoZSAib2xkIiB3YXkgKHRoZSB3YXkgMS4zLjIgb3Igb2xkZXIKCQkvLyBkaWQgaXQpLCBvdGhlcndpc2UgZW5jb2RlIHBhcmFtcyByZWN1cnNpdmVseS4KCQlmb3IgKCBwcmVmaXggaW4gYSApIHsKCQkJYnVpbGRQYXJhbXMoIHByZWZpeCwgYVsgcHJlZml4IF0sIHRyYWRpdGlvbmFsLCBhZGQgKTsKCQl9Cgl9CgoJLy8gUmV0dXJuIHRoZSByZXN1bHRpbmcgc2VyaWFsaXphdGlvbgoJcmV0dXJuIHMuam9pbiggIiYiICkucmVwbGFjZSggcjIwLCAiKyIgKTsKfTsKCmpRdWVyeS5mbi5leHRlbmQoewoJc2VyaWFsaXplOiBmdW5jdGlvbigpIHsKCQlyZXR1cm4galF1ZXJ5LnBhcmFtKCB0aGlzLnNlcmlhbGl6ZUFycmF5KCkgKTsKCX0sCglzZXJpYWxpemVBcnJheTogZnVuY3Rpb24oKSB7CgkJcmV0dXJuIHRoaXMubWFwKGZ1bmN0aW9uKCkgewoJCQkvLyBDYW4gYWRkIHByb3BIb29rIGZvciAiZWxlbWVudHMiIHRvIGZpbHRlciBvciBhZGQgZm9ybSBlbGVtZW50cwoJCQl2YXIgZWxlbWVudHMgPSBqUXVlcnkucHJvcCggdGhpcywgImVsZW1lbnRzIiApOwoJCQlyZXR1cm4gZWxlbWVudHMgPyBqUXVlcnkubWFrZUFycmF5KCBlbGVtZW50cyApIDogdGhpczsKCQl9KQoJCS5maWx0ZXIoZnVuY3Rpb24oKSB7CgkJCXZhciB0eXBlID0gdGhpcy50eXBlOwoKCQkJLy8gVXNlIC5pcyggIjpkaXNhYmxlZCIgKSBzbyB0aGF0IGZpZWxkc2V0W2Rpc2FibGVkXSB3b3JrcwoJCQlyZXR1cm4gdGhpcy5uYW1lICYmICFqUXVlcnkoIHRoaXMgKS5pcyggIjpkaXNhYmxlZCIgKSAmJgoJCQkJcnN1Ym1pdHRhYmxlLnRlc3QoIHRoaXMubm9kZU5hbWUgKSAmJiAhcnN1Ym1pdHRlclR5cGVzLnRlc3QoIHR5cGUgKSAmJgoJCQkJKCB0aGlzLmNoZWNrZWQgfHwgIXJjaGVja2FibGVUeXBlLnRlc3QoIHR5cGUgKSApOwoJCX0pCgkJLm1hcChmdW5jdGlvbiggaSwgZWxlbSApIHsKCQkJdmFyIHZhbCA9IGpRdWVyeSggdGhpcyApLnZhbCgpOwoKCQkJcmV0dXJuIHZhbCA9PSBudWxsID8KCQkJCW51bGwgOgoJCQkJalF1ZXJ5LmlzQXJyYXkoIHZhbCApID8KCQkJCQlqUXVlcnkubWFwKCB2YWwsIGZ1bmN0aW9uKCB2YWwgKSB7CgkJCQkJCXJldHVybiB7IG5hbWU6IGVsZW0ubmFtZSwgdmFsdWU6IHZhbC5yZXBsYWNlKCByQ1JMRiwgIlxyXG4iICkgfTsKCQkJCQl9KSA6CgkJCQkJeyBuYW1lOiBlbGVtLm5hbWUsIHZhbHVlOiB2YWwucmVwbGFjZSggckNSTEYsICJcclxuIiApIH07CgkJfSkuZ2V0KCk7Cgl9Cn0pOwoKCmpRdWVyeS5hamF4U2V0dGluZ3MueGhyID0gZnVuY3Rpb24oKSB7Cgl0cnkgewoJCXJldHVybiBuZXcgWE1MSHR0cFJlcXVlc3QoKTsKCX0gY2F0Y2goIGUgKSB7fQp9OwoKdmFyIHhocklkID0gMCwKCXhockNhbGxiYWNrcyA9IHt9LAoJeGhyU3VjY2Vzc1N0YXR1cyA9IHsKCQkvLyBmaWxlIHByb3RvY29sIGFsd2F5cyB5aWVsZHMgc3RhdHVzIGNvZGUgMCwgYXNzdW1lIDIwMAoJCTA6IDIwMCwKCQkvLyBTdXBwb3J0OiBJRTkKCQkvLyAjMTQ1MDogc29tZXRpbWVzIElFIHJldHVybnMgMTIyMyB3aGVuIGl0IHNob3VsZCBiZSAyMDQKCQkxMjIzOiAyMDQKCX0sCgl4aHJTdXBwb3J0ZWQgPSBqUXVlcnkuYWpheFNldHRpbmdzLnhocigpOwoKLy8gU3VwcG9ydDogSUU5Ci8vIE9wZW4gcmVxdWVzdHMgbXVzdCBiZSBtYW51YWxseSBhYm9ydGVkIG9uIHVubG9hZCAoIzUyODApCmlmICggd2luZG93LkFjdGl2ZVhPYmplY3QgKSB7CglqUXVlcnkoIHdpbmRvdyApLm9uKCAidW5sb2FkIiwgZnVuY3Rpb24oKSB7CgkJZm9yICggdmFyIGtleSBpbiB4aHJDYWxsYmFja3MgKSB7CgkJCXhockNhbGxiYWNrc1sga2V5IF0oKTsKCQl9Cgl9KTsKfQoKc3VwcG9ydC5jb3JzID0gISF4aHJTdXBwb3J0ZWQgJiYgKCAid2l0aENyZWRlbnRpYWxzIiBpbiB4aHJTdXBwb3J0ZWQgKTsKc3VwcG9ydC5hamF4ID0geGhyU3VwcG9ydGVkID0gISF4aHJTdXBwb3J0ZWQ7CgpqUXVlcnkuYWpheFRyYW5zcG9ydChmdW5jdGlvbiggb3B0aW9ucyApIHsKCXZhciBjYWxsYmFjazsKCgkvLyBDcm9zcyBkb21haW4gb25seSBhbGxvd2VkIGlmIHN1cHBvcnRlZCB0aHJvdWdoIFhNTEh0dHBSZXF1ZXN0CglpZiAoIHN1cHBvcnQuY29ycyB8fCB4aHJTdXBwb3J0ZWQgJiYgIW9wdGlvbnMuY3Jvc3NEb21haW4gKSB7CgkJcmV0dXJuIHsKCQkJc2VuZDogZnVuY3Rpb24oIGhlYWRlcnMsIGNvbXBsZXRlICkgewoJCQkJdmFyIGksCgkJCQkJeGhyID0gb3B0aW9ucy54aHIoKSwKCQkJCQlpZCA9ICsreGhySWQ7CgoJCQkJeGhyLm9wZW4oIG9wdGlvbnMudHlwZSwgb3B0aW9ucy51cmwsIG9wdGlvbnMuYXN5bmMsIG9wdGlvbnMudXNlcm5hbWUsIG9wdGlvbnMucGFzc3dvcmQgKTsKCgkJCQkvLyBBcHBseSBjdXN0b20gZmllbGRzIGlmIHByb3ZpZGVkCgkJCQlpZiAoIG9wdGlvbnMueGhyRmllbGRzICkgewoJCQkJCWZvciAoIGkgaW4gb3B0aW9ucy54aHJGaWVsZHMgKSB7CgkJCQkJCXhoclsgaSBdID0gb3B0aW9ucy54aHJGaWVsZHNbIGkgXTsKCQkJCQl9CgkJCQl9CgoJCQkJLy8gT3ZlcnJpZGUgbWltZSB0eXBlIGlmIG5lZWRlZAoJCQkJaWYgKCBvcHRpb25zLm1pbWVUeXBlICYmIHhoci5vdmVycmlkZU1pbWVUeXBlICkgewoJCQkJCXhoci5vdmVycmlkZU1pbWVUeXBlKCBvcHRpb25zLm1pbWVUeXBlICk7CgkJCQl9CgoJCQkJLy8gWC1SZXF1ZXN0ZWQtV2l0aCBoZWFkZXIKCQkJCS8vIEZvciBjcm9zcy1kb21haW4gcmVxdWVzdHMsIHNlZWluZyBhcyBjb25kaXRpb25zIGZvciBhIHByZWZsaWdodCBhcmUKCQkJCS8vIGFraW4gdG8gYSBqaWdzYXcgcHV6emxlLCB3ZSBzaW1wbHkgbmV2ZXIgc2V0IGl0IHRvIGJlIHN1cmUuCgkJCQkvLyAoaXQgY2FuIGFsd2F5cyBiZSBzZXQgb24gYSBwZXItcmVxdWVzdCBiYXNpcyBvciBldmVuIHVzaW5nIGFqYXhTZXR1cCkKCQkJCS8vIEZvciBzYW1lLWRvbWFpbiByZXF1ZXN0cywgd29uJ3QgY2hhbmdlIGhlYWRlciBpZiBhbHJlYWR5IHByb3ZpZGVkLgoJCQkJaWYgKCAhb3B0aW9ucy5jcm9zc0RvbWFpbiAmJiAhaGVhZGVyc1siWC1SZXF1ZXN0ZWQtV2l0aCJdICkgewoJCQkJCWhlYWRlcnNbIlgtUmVxdWVzdGVkLVdpdGgiXSA9ICJYTUxIdHRwUmVxdWVzdCI7CgkJCQl9CgoJCQkJLy8gU2V0IGhlYWRlcnMKCQkJCWZvciAoIGkgaW4gaGVhZGVycyApIHsKCQkJCQl4aHIuc2V0UmVxdWVzdEhlYWRlciggaSwgaGVhZGVyc1sgaSBdICk7CgkJCQl9CgoJCQkJLy8gQ2FsbGJhY2sKCQkJCWNhbGxiYWNrID0gZnVuY3Rpb24oIHR5cGUgKSB7CgkJCQkJcmV0dXJuIGZ1bmN0aW9uKCkgewoJCQkJCQlpZiAoIGNhbGxiYWNrICkgewoJCQkJCQkJZGVsZXRlIHhockNhbGxiYWNrc1sgaWQgXTsKCQkJCQkJCWNhbGxiYWNrID0geGhyLm9ubG9hZCA9IHhoci5vbmVycm9yID0gbnVsbDsKCgkJCQkJCQlpZiAoIHR5cGUgPT09ICJhYm9ydCIgKSB7CgkJCQkJCQkJeGhyLmFib3J0KCk7CgkJCQkJCQl9IGVsc2UgaWYgKCB0eXBlID09PSAiZXJyb3IiICkgewoJCQkJCQkJCWNvbXBsZXRlKAoJCQkJCQkJCQkvLyBmaWxlOiBwcm90b2NvbCBhbHdheXMgeWllbGRzIHN0YXR1cyAwOyBzZWUgIzg2MDUsICMxNDIwNwoJCQkJCQkJCQl4aHIuc3RhdHVzLAoJCQkJCQkJCQl4aHIuc3RhdHVzVGV4dAoJCQkJCQkJCSk7CgkJCQkJCQl9IGVsc2UgewoJCQkJCQkJCWNvbXBsZXRlKAoJCQkJCQkJCQl4aHJTdWNjZXNzU3RhdHVzWyB4aHIuc3RhdHVzIF0gfHwgeGhyLnN0YXR1cywKCQkJCQkJCQkJeGhyLnN0YXR1c1RleHQsCgkJCQkJCQkJCS8vIFN1cHBvcnQ6IElFOQoJCQkJCQkJCQkvLyBBY2Nlc3NpbmcgYmluYXJ5LWRhdGEgcmVzcG9uc2VUZXh0IHRocm93cyBhbiBleGNlcHRpb24KCQkJCQkJCQkJLy8gKCMxMTQyNikKCQkJCQkJCQkJdHlwZW9mIHhoci5yZXNwb25zZVRleHQgPT09ICJzdHJpbmciID8gewoJCQkJCQkJCQkJdGV4dDogeGhyLnJlc3BvbnNlVGV4dAoJCQkJCQkJCQl9IDogdW5kZWZpbmVkLAoJCQkJCQkJCQl4aHIuZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCkKCQkJCQkJCQkpOwoJCQkJCQkJfQoJCQkJCQl9CgkJCQkJfTsKCQkJCX07CgoJCQkJLy8gTGlzdGVuIHRvIGV2ZW50cwoJCQkJeGhyLm9ubG9hZCA9IGNhbGxiYWNrKCk7CgkJCQl4aHIub25lcnJvciA9IGNhbGxiYWNrKCJlcnJvciIpOwoKCQkJCS8vIENyZWF0ZSB0aGUgYWJvcnQgY2FsbGJhY2sKCQkJCWNhbGxiYWNrID0geGhyQ2FsbGJhY2tzWyBpZCBdID0gY2FsbGJhY2soImFib3J0Iik7CgoJCQkJdHJ5IHsKCQkJCQkvLyBEbyBzZW5kIHRoZSByZXF1ZXN0ICh0aGlzIG1heSByYWlzZSBhbiBleGNlcHRpb24pCgkJCQkJeGhyLnNlbmQoIG9wdGlvbnMuaGFzQ29udGVudCAmJiBvcHRpb25zLmRhdGEgfHwgbnVsbCApOwoJCQkJfSBjYXRjaCAoIGUgKSB7CgkJCQkJLy8gIzE0NjgzOiBPbmx5IHJldGhyb3cgaWYgdGhpcyBoYXNuJ3QgYmVlbiBub3RpZmllZCBhcyBhbiBlcnJvciB5ZXQKCQkJCQlpZiAoIGNhbGxiYWNrICkgewoJCQkJCQl0aHJvdyBlOwoJCQkJCX0KCQkJCX0KCQkJfSwKCgkJCWFib3J0OiBmdW5jdGlvbigpIHsKCQkJCWlmICggY2FsbGJhY2sgKSB7CgkJCQkJY2FsbGJhY2soKTsKCQkJCX0KCQkJfQoJCX07Cgl9Cn0pOwoKCgoKLy8gSW5zdGFsbCBzY3JpcHQgZGF0YVR5cGUKalF1ZXJ5LmFqYXhTZXR1cCh7CglhY2NlcHRzOiB7CgkJc2NyaXB0OiAidGV4dC9qYXZhc2NyaXB0LCBhcHBsaWNhdGlvbi9qYXZhc2NyaXB0LCBhcHBsaWNhdGlvbi9lY21hc2NyaXB0LCBhcHBsaWNhdGlvbi94LWVjbWFzY3JpcHQiCgl9LAoJY29udGVudHM6IHsKCQlzY3JpcHQ6IC8oPzpqYXZhfGVjbWEpc2NyaXB0LwoJfSwKCWNvbnZlcnRlcnM6IHsKCQkidGV4dCBzY3JpcHQiOiBmdW5jdGlvbiggdGV4dCApIHsKCQkJalF1ZXJ5Lmdsb2JhbEV2YWwoIHRleHQgKTsKCQkJcmV0dXJuIHRleHQ7CgkJfQoJfQp9KTsKCi8vIEhhbmRsZSBjYWNoZSdzIHNwZWNpYWwgY2FzZSBhbmQgY3Jvc3NEb21haW4KalF1ZXJ5LmFqYXhQcmVmaWx0ZXIoICJzY3JpcHQiLCBmdW5jdGlvbiggcyApIHsKCWlmICggcy5jYWNoZSA9PT0gdW5kZWZpbmVkICkgewoJCXMuY2FjaGUgPSBmYWxzZTsKCX0KCWlmICggcy5jcm9zc0RvbWFpbiApIHsKCQlzLnR5cGUgPSAiR0VUIjsKCX0KfSk7CgovLyBCaW5kIHNjcmlwdCB0YWcgaGFjayB0cmFuc3BvcnQKalF1ZXJ5LmFqYXhUcmFuc3BvcnQoICJzY3JpcHQiLCBmdW5jdGlvbiggcyApIHsKCS8vIFRoaXMgdHJhbnNwb3J0IG9ubHkgZGVhbHMgd2l0aCBjcm9zcyBkb21haW4gcmVxdWVzdHMKCWlmICggcy5jcm9zc0RvbWFpbiApIHsKCQl2YXIgc2NyaXB0LCBjYWxsYmFjazsKCQlyZXR1cm4gewoJCQlzZW5kOiBmdW5jdGlvbiggXywgY29tcGxldGUgKSB7CgkJCQlzY3JpcHQgPSBqUXVlcnkoIjxzY3JpcHQ+IikucHJvcCh7CgkJCQkJYXN5bmM6IHRydWUsCgkJCQkJY2hhcnNldDogcy5zY3JpcHRDaGFyc2V0LAoJCQkJCXNyYzogcy51cmwKCQkJCX0pLm9uKAoJCQkJCSJsb2FkIGVycm9yIiwKCQkJCQljYWxsYmFjayA9IGZ1bmN0aW9uKCBldnQgKSB7CgkJCQkJCXNjcmlwdC5yZW1vdmUoKTsKCQkJCQkJY2FsbGJhY2sgPSBudWxsOwoJCQkJCQlpZiAoIGV2dCApIHsKCQkJCQkJCWNvbXBsZXRlKCBldnQudHlwZSA9PT0gImVycm9yIiA/IDQwNCA6IDIwMCwgZXZ0LnR5cGUgKTsKCQkJCQkJfQoJCQkJCX0KCQkJCSk7CgkJCQlkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKCBzY3JpcHRbIDAgXSApOwoJCQl9LAoJCQlhYm9ydDogZnVuY3Rpb24oKSB7CgkJCQlpZiAoIGNhbGxiYWNrICkgewoJCQkJCWNhbGxiYWNrKCk7CgkJCQl9CgkJCX0KCQl9OwoJfQp9KTsKCgoKCnZhciBvbGRDYWxsYmFja3MgPSBbXSwKCXJqc29ucCA9IC8oPSlcPyg/PSZ8JCl8XD9cPy87CgovLyBEZWZhdWx0IGpzb25wIHNldHRpbmdzCmpRdWVyeS5hamF4U2V0dXAoewoJanNvbnA6ICJjYWxsYmFjayIsCglqc29ucENhbGxiYWNrOiBmdW5jdGlvbigpIHsKCQl2YXIgY2FsbGJhY2sgPSBvbGRDYWxsYmFja3MucG9wKCkgfHwgKCBqUXVlcnkuZXhwYW5kbyArICJfIiArICggbm9uY2UrKyApICk7CgkJdGhpc1sgY2FsbGJhY2sgXSA9IHRydWU7CgkJcmV0dXJuIGNhbGxiYWNrOwoJfQp9KTsKCi8vIERldGVjdCwgbm9ybWFsaXplIG9wdGlvbnMgYW5kIGluc3RhbGwgY2FsbGJhY2tzIGZvciBqc29ucCByZXF1ZXN0cwpqUXVlcnkuYWpheFByZWZpbHRlciggImpzb24ganNvbnAiLCBmdW5jdGlvbiggcywgb3JpZ2luYWxTZXR0aW5ncywganFYSFIgKSB7CgoJdmFyIGNhbGxiYWNrTmFtZSwgb3ZlcndyaXR0ZW4sIHJlc3BvbnNlQ29udGFpbmVyLAoJCWpzb25Qcm9wID0gcy5qc29ucCAhPT0gZmFsc2UgJiYgKCByanNvbnAudGVzdCggcy51cmwgKSA/CgkJCSJ1cmwiIDoKCQkJdHlwZW9mIHMuZGF0YSA9PT0gInN0cmluZyIgJiYgISggcy5jb250ZW50VHlwZSB8fCAiIiApLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpICYmIHJqc29ucC50ZXN0KCBzLmRhdGEgKSAmJiAiZGF0YSIKCQkpOwoKCS8vIEhhbmRsZSBpZmYgdGhlIGV4cGVjdGVkIGRhdGEgdHlwZSBpcyAianNvbnAiIG9yIHdlIGhhdmUgYSBwYXJhbWV0ZXIgdG8gc2V0CglpZiAoIGpzb25Qcm9wIHx8IHMuZGF0YVR5cGVzWyAwIF0gPT09ICJqc29ucCIgKSB7CgoJCS8vIEdldCBjYWxsYmFjayBuYW1lLCByZW1lbWJlcmluZyBwcmVleGlzdGluZyB2YWx1ZSBhc3NvY2lhdGVkIHdpdGggaXQKCQljYWxsYmFja05hbWUgPSBzLmpzb25wQ2FsbGJhY2sgPSBqUXVlcnkuaXNGdW5jdGlvbiggcy5qc29ucENhbGxiYWNrICkgPwoJCQlzLmpzb25wQ2FsbGJhY2soKSA6CgkJCXMuanNvbnBDYWxsYmFjazsKCgkJLy8gSW5zZXJ0IGNhbGxiYWNrIGludG8gdXJsIG9yIGZvcm0gZGF0YQoJCWlmICgganNvblByb3AgKSB7CgkJCXNbIGpzb25Qcm9wIF0gPSBzWyBqc29uUHJvcCBdLnJlcGxhY2UoIHJqc29ucCwgIiQxIiArIGNhbGxiYWNrTmFtZSApOwoJCX0gZWxzZSBpZiAoIHMuanNvbnAgIT09IGZhbHNlICkgewoJCQlzLnVybCArPSAoIHJxdWVyeS50ZXN0KCBzLnVybCApID8gIiYiIDogIj8iICkgKyBzLmpzb25wICsgIj0iICsgY2FsbGJhY2tOYW1lOwoJCX0KCgkJLy8gVXNlIGRhdGEgY29udmVydGVyIHRvIHJldHJpZXZlIGpzb24gYWZ0ZXIgc2NyaXB0IGV4ZWN1dGlvbgoJCXMuY29udmVydGVyc1sic2NyaXB0IGpzb24iXSA9IGZ1bmN0aW9uKCkgewoJCQlpZiAoICFyZXNwb25zZUNvbnRhaW5lciApIHsKCQkJCWpRdWVyeS5lcnJvciggY2FsbGJhY2tOYW1lICsgIiB3YXMgbm90IGNhbGxlZCIgKTsKCQkJfQoJCQlyZXR1cm4gcmVzcG9uc2VDb250YWluZXJbIDAgXTsKCQl9OwoKCQkvLyBmb3JjZSBqc29uIGRhdGFUeXBlCgkJcy5kYXRhVHlwZXNbIDAgXSA9ICJqc29uIjsKCgkJLy8gSW5zdGFsbCBjYWxsYmFjawoJCW92ZXJ3cml0dGVuID0gd2luZG93WyBjYWxsYmFja05hbWUgXTsKCQl3aW5kb3dbIGNhbGxiYWNrTmFtZSBdID0gZnVuY3Rpb24oKSB7CgkJCXJlc3BvbnNlQ29udGFpbmVyID0gYXJndW1lbnRzOwoJCX07CgoJCS8vIENsZWFuLXVwIGZ1bmN0aW9uIChmaXJlcyBhZnRlciBjb252ZXJ0ZXJzKQoJCWpxWEhSLmFsd2F5cyhmdW5jdGlvbigpIHsKCQkJLy8gUmVzdG9yZSBwcmVleGlzdGluZyB2YWx1ZQoJCQl3aW5kb3dbIGNhbGxiYWNrTmFtZSBdID0gb3ZlcndyaXR0ZW47CgoJCQkvLyBTYXZlIGJhY2sgYXMgZnJlZQoJCQlpZiAoIHNbIGNhbGxiYWNrTmFtZSBdICkgewoJCQkJLy8gbWFrZSBzdXJlIHRoYXQgcmUtdXNpbmcgdGhlIG9wdGlvbnMgZG9lc24ndCBzY3JldyB0aGluZ3MgYXJvdW5kCgkJCQlzLmpzb25wQ2FsbGJhY2sgPSBvcmlnaW5hbFNldHRpbmdzLmpzb25wQ2FsbGJhY2s7CgoJCQkJLy8gc2F2ZSB0aGUgY2FsbGJhY2sgbmFtZSBmb3IgZnV0dXJlIHVzZQoJCQkJb2xkQ2FsbGJhY2tzLnB1c2goIGNhbGxiYWNrTmFtZSApOwoJCQl9CgoJCQkvLyBDYWxsIGlmIGl0IHdhcyBhIGZ1bmN0aW9uIGFuZCB3ZSBoYXZlIGEgcmVzcG9uc2UKCQkJaWYgKCByZXNwb25zZUNvbnRhaW5lciAmJiBqUXVlcnkuaXNGdW5jdGlvbiggb3ZlcndyaXR0ZW4gKSApIHsKCQkJCW92ZXJ3cml0dGVuKCByZXNwb25zZUNvbnRhaW5lclsgMCBdICk7CgkJCX0KCgkJCXJlc3BvbnNlQ29udGFpbmVyID0gb3ZlcndyaXR0ZW4gPSB1bmRlZmluZWQ7CgkJfSk7CgoJCS8vIERlbGVnYXRlIHRvIHNjcmlwdAoJCXJldHVybiAic2NyaXB0IjsKCX0KfSk7CgoKCgovLyBkYXRhOiBzdHJpbmcgb2YgaHRtbAovLyBjb250ZXh0IChvcHRpb25hbCk6IElmIHNwZWNpZmllZCwgdGhlIGZyYWdtZW50IHdpbGwgYmUgY3JlYXRlZCBpbiB0aGlzIGNvbnRleHQsIGRlZmF1bHRzIHRvIGRvY3VtZW50Ci8vIGtlZXBTY3JpcHRzIChvcHRpb25hbCk6IElmIHRydWUsIHdpbGwgaW5jbHVkZSBzY3JpcHRzIHBhc3NlZCBpbiB0aGUgaHRtbCBzdHJpbmcKalF1ZXJ5LnBhcnNlSFRNTCA9IGZ1bmN0aW9uKCBkYXRhLCBjb250ZXh0LCBrZWVwU2NyaXB0cyApIHsKCWlmICggIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09ICJzdHJpbmciICkgewoJCXJldHVybiBudWxsOwoJfQoJaWYgKCB0eXBlb2YgY29udGV4dCA9PT0gImJvb2xlYW4iICkgewoJCWtlZXBTY3JpcHRzID0gY29udGV4dDsKCQljb250ZXh0ID0gZmFsc2U7Cgl9Cgljb250ZXh0ID0gY29udGV4dCB8fCBkb2N1bWVudDsKCgl2YXIgcGFyc2VkID0gcnNpbmdsZVRhZy5leGVjKCBkYXRhICksCgkJc2NyaXB0cyA9ICFrZWVwU2NyaXB0cyAmJiBbXTsKCgkvLyBTaW5nbGUgdGFnCglpZiAoIHBhcnNlZCApIHsKCQlyZXR1cm4gWyBjb250ZXh0LmNyZWF0ZUVsZW1lbnQoIHBhcnNlZFsxXSApIF07Cgl9CgoJcGFyc2VkID0galF1ZXJ5LmJ1aWxkRnJhZ21lbnQoIFsgZGF0YSBdLCBjb250ZXh0LCBzY3JpcHRzICk7CgoJaWYgKCBzY3JpcHRzICYmIHNjcmlwdHMubGVuZ3RoICkgewoJCWpRdWVyeSggc2NyaXB0cyApLnJlbW92ZSgpOwoJfQoKCXJldHVybiBqUXVlcnkubWVyZ2UoIFtdLCBwYXJzZWQuY2hpbGROb2RlcyApOwp9OwoKCi8vIEtlZXAgYSBjb3B5IG9mIHRoZSBvbGQgbG9hZCBtZXRob2QKdmFyIF9sb2FkID0galF1ZXJ5LmZuLmxvYWQ7CgovKioKICogTG9hZCBhIHVybCBpbnRvIGEgcGFnZQogKi8KalF1ZXJ5LmZuLmxvYWQgPSBmdW5jdGlvbiggdXJsLCBwYXJhbXMsIGNhbGxiYWNrICkgewoJaWYgKCB0eXBlb2YgdXJsICE9PSAic3RyaW5nIiAmJiBfbG9hZCApIHsKCQlyZXR1cm4gX2xvYWQuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApOwoJfQoKCXZhciBzZWxlY3RvciwgdHlwZSwgcmVzcG9uc2UsCgkJc2VsZiA9IHRoaXMsCgkJb2ZmID0gdXJsLmluZGV4T2YoIiAiKTsKCglpZiAoIG9mZiA+PSAwICkgewoJCXNlbGVjdG9yID0galF1ZXJ5LnRyaW0oIHVybC5zbGljZSggb2ZmICkgKTsKCQl1cmwgPSB1cmwuc2xpY2UoIDAsIG9mZiApOwoJfQoKCS8vIElmIGl0J3MgYSBmdW5jdGlvbgoJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggcGFyYW1zICkgKSB7CgoJCS8vIFdlIGFzc3VtZSB0aGF0IGl0J3MgdGhlIGNhbGxiYWNrCgkJY2FsbGJhY2sgPSBwYXJhbXM7CgkJcGFyYW1zID0gdW5kZWZpbmVkOwoKCS8vIE90aGVyd2lzZSwgYnVpbGQgYSBwYXJhbSBzdHJpbmcKCX0gZWxzZSBpZiAoIHBhcmFtcyAmJiB0eXBlb2YgcGFyYW1zID09PSAib2JqZWN0IiApIHsKCQl0eXBlID0gIlBPU1QiOwoJfQoKCS8vIElmIHdlIGhhdmUgZWxlbWVudHMgdG8gbW9kaWZ5LCBtYWtlIHRoZSByZXF1ZXN0CglpZiAoIHNlbGYubGVuZ3RoID4gMCApIHsKCQlqUXVlcnkuYWpheCh7CgkJCXVybDogdXJsLAoKCQkJLy8gaWYgInR5cGUiIHZhcmlhYmxlIGlzIHVuZGVmaW5lZCwgdGhlbiAiR0VUIiBtZXRob2Qgd2lsbCBiZSB1c2VkCgkJCXR5cGU6IHR5cGUsCgkJCWRhdGFUeXBlOiAiaHRtbCIsCgkJCWRhdGE6IHBhcmFtcwoJCX0pLmRvbmUoZnVuY3Rpb24oIHJlc3BvbnNlVGV4dCApIHsKCgkJCS8vIFNhdmUgcmVzcG9uc2UgZm9yIHVzZSBpbiBjb21wbGV0ZSBjYWxsYmFjawoJCQlyZXNwb25zZSA9IGFyZ3VtZW50czsKCgkJCXNlbGYuaHRtbCggc2VsZWN0b3IgPwoKCQkJCS8vIElmIGEgc2VsZWN0b3Igd2FzIHNwZWNpZmllZCwgbG9jYXRlIHRoZSByaWdodCBlbGVtZW50cyBpbiBhIGR1bW15IGRpdgoJCQkJLy8gRXhjbHVkZSBzY3JpcHRzIHRvIGF2b2lkIElFICdQZXJtaXNzaW9uIERlbmllZCcgZXJyb3JzCgkJCQlqUXVlcnkoIjxkaXY+IikuYXBwZW5kKCBqUXVlcnkucGFyc2VIVE1MKCByZXNwb25zZVRleHQgKSApLmZpbmQoIHNlbGVjdG9yICkgOgoKCQkJCS8vIE90aGVyd2lzZSB1c2UgdGhlIGZ1bGwgcmVzdWx0CgkJCQlyZXNwb25zZVRleHQgKTsKCgkJfSkuY29tcGxldGUoIGNhbGxiYWNrICYmIGZ1bmN0aW9uKCBqcVhIUiwgc3RhdHVzICkgewoJCQlzZWxmLmVhY2goIGNhbGxiYWNrLCByZXNwb25zZSB8fCBbIGpxWEhSLnJlc3BvbnNlVGV4dCwgc3RhdHVzLCBqcVhIUiBdICk7CgkJfSk7Cgl9CgoJcmV0dXJuIHRoaXM7Cn07CgoKCgpqUXVlcnkuZXhwci5maWx0ZXJzLmFuaW1hdGVkID0gZnVuY3Rpb24oIGVsZW0gKSB7CglyZXR1cm4galF1ZXJ5LmdyZXAoalF1ZXJ5LnRpbWVycywgZnVuY3Rpb24oIGZuICkgewoJCXJldHVybiBlbGVtID09PSBmbi5lbGVtOwoJfSkubGVuZ3RoOwp9OwoKCgoKdmFyIGRvY0VsZW0gPSB3aW5kb3cuZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50OwoKLyoqCiAqIEdldHMgYSB3aW5kb3cgZnJvbSBhbiBlbGVtZW50CiAqLwpmdW5jdGlvbiBnZXRXaW5kb3coIGVsZW0gKSB7CglyZXR1cm4galF1ZXJ5LmlzV2luZG93KCBlbGVtICkgPyBlbGVtIDogZWxlbS5ub2RlVHlwZSA9PT0gOSAmJiBlbGVtLmRlZmF1bHRWaWV3Owp9CgpqUXVlcnkub2Zmc2V0ID0gewoJc2V0T2Zmc2V0OiBmdW5jdGlvbiggZWxlbSwgb3B0aW9ucywgaSApIHsKCQl2YXIgY3VyUG9zaXRpb24sIGN1ckxlZnQsIGN1ckNTU1RvcCwgY3VyVG9wLCBjdXJPZmZzZXQsIGN1ckNTU0xlZnQsIGNhbGN1bGF0ZVBvc2l0aW9uLAoJCQlwb3NpdGlvbiA9IGpRdWVyeS5jc3MoIGVsZW0sICJwb3NpdGlvbiIgKSwKCQkJY3VyRWxlbSA9IGpRdWVyeSggZWxlbSApLAoJCQlwcm9wcyA9IHt9OwoKCQkvLyBTZXQgcG9zaXRpb24gZmlyc3QsIGluLWNhc2UgdG9wL2xlZnQgYXJlIHNldCBldmVuIG9uIHN0YXRpYyBlbGVtCgkJaWYgKCBwb3NpdGlvbiA9PT0gInN0YXRpYyIgKSB7CgkJCWVsZW0uc3R5bGUucG9zaXRpb24gPSAicmVsYXRpdmUiOwoJCX0KCgkJY3VyT2Zmc2V0ID0gY3VyRWxlbS5vZmZzZXQoKTsKCQljdXJDU1NUb3AgPSBqUXVlcnkuY3NzKCBlbGVtLCAidG9wIiApOwoJCWN1ckNTU0xlZnQgPSBqUXVlcnkuY3NzKCBlbGVtLCAibGVmdCIgKTsKCQljYWxjdWxhdGVQb3NpdGlvbiA9ICggcG9zaXRpb24gPT09ICJhYnNvbHV0ZSIgfHwgcG9zaXRpb24gPT09ICJmaXhlZCIgKSAmJgoJCQkoIGN1ckNTU1RvcCArIGN1ckNTU0xlZnQgKS5pbmRleE9mKCJhdXRvIikgPiAtMTsKCgkJLy8gTmVlZCB0byBiZSBhYmxlIHRvIGNhbGN1bGF0ZSBwb3NpdGlvbiBpZiBlaXRoZXIgdG9wIG9yIGxlZnQgaXMgYXV0byBhbmQgcG9zaXRpb24gaXMgZWl0aGVyIGFic29sdXRlIG9yIGZpeGVkCgkJaWYgKCBjYWxjdWxhdGVQb3NpdGlvbiApIHsKCQkJY3VyUG9zaXRpb24gPSBjdXJFbGVtLnBvc2l0aW9uKCk7CgkJCWN1clRvcCA9IGN1clBvc2l0aW9uLnRvcDsKCQkJY3VyTGVmdCA9IGN1clBvc2l0aW9uLmxlZnQ7CgoJCX0gZWxzZSB7CgkJCWN1clRvcCA9IHBhcnNlRmxvYXQoIGN1ckNTU1RvcCApIHx8IDA7CgkJCWN1ckxlZnQgPSBwYXJzZUZsb2F0KCBjdXJDU1NMZWZ0ICkgfHwgMDsKCQl9CgoJCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIG9wdGlvbnMgKSApIHsKCQkJb3B0aW9ucyA9IG9wdGlvbnMuY2FsbCggZWxlbSwgaSwgY3VyT2Zmc2V0ICk7CgkJfQoKCQlpZiAoIG9wdGlvbnMudG9wICE9IG51bGwgKSB7CgkJCXByb3BzLnRvcCA9ICggb3B0aW9ucy50b3AgLSBjdXJPZmZzZXQudG9wICkgKyBjdXJUb3A7CgkJfQoJCWlmICggb3B0aW9ucy5sZWZ0ICE9IG51bGwgKSB7CgkJCXByb3BzLmxlZnQgPSAoIG9wdGlvbnMubGVmdCAtIGN1ck9mZnNldC5sZWZ0ICkgKyBjdXJMZWZ0OwoJCX0KCgkJaWYgKCAidXNpbmciIGluIG9wdGlvbnMgKSB7CgkJCW9wdGlvbnMudXNpbmcuY2FsbCggZWxlbSwgcHJvcHMgKTsKCgkJfSBlbHNlIHsKCQkJY3VyRWxlbS5jc3MoIHByb3BzICk7CgkJfQoJfQp9OwoKalF1ZXJ5LmZuLmV4dGVuZCh7CglvZmZzZXQ6IGZ1bmN0aW9uKCBvcHRpb25zICkgewoJCWlmICggYXJndW1lbnRzLmxlbmd0aCApIHsKCQkJcmV0dXJuIG9wdGlvbnMgPT09IHVuZGVmaW5lZCA/CgkJCQl0aGlzIDoKCQkJCXRoaXMuZWFjaChmdW5jdGlvbiggaSApIHsKCQkJCQlqUXVlcnkub2Zmc2V0LnNldE9mZnNldCggdGhpcywgb3B0aW9ucywgaSApOwoJCQkJfSk7CgkJfQoKCQl2YXIgZG9jRWxlbSwgd2luLAoJCQllbGVtID0gdGhpc1sgMCBdLAoJCQlib3ggPSB7IHRvcDogMCwgbGVmdDogMCB9LAoJCQlkb2MgPSBlbGVtICYmIGVsZW0ub3duZXJEb2N1bWVudDsKCgkJaWYgKCAhZG9jICkgewoJCQlyZXR1cm47CgkJfQoKCQlkb2NFbGVtID0gZG9jLmRvY3VtZW50RWxlbWVudDsKCgkJLy8gTWFrZSBzdXJlIGl0J3Mgbm90IGEgZGlzY29ubmVjdGVkIERPTSBub2RlCgkJaWYgKCAhalF1ZXJ5LmNvbnRhaW5zKCBkb2NFbGVtLCBlbGVtICkgKSB7CgkJCXJldHVybiBib3g7CgkJfQoKCQkvLyBJZiB3ZSBkb24ndCBoYXZlIGdCQ1IsIGp1c3QgdXNlIDAsMCByYXRoZXIgdGhhbiBlcnJvcgoJCS8vIEJsYWNrQmVycnkgNSwgaU9TIDMgKG9yaWdpbmFsIGlQaG9uZSkKCQlpZiAoIHR5cGVvZiBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCAhPT0gc3RydW5kZWZpbmVkICkgewoJCQlib3ggPSBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwoJCX0KCQl3aW4gPSBnZXRXaW5kb3coIGRvYyApOwoJCXJldHVybiB7CgkJCXRvcDogYm94LnRvcCArIHdpbi5wYWdlWU9mZnNldCAtIGRvY0VsZW0uY2xpZW50VG9wLAoJCQlsZWZ0OiBib3gubGVmdCArIHdpbi5wYWdlWE9mZnNldCAtIGRvY0VsZW0uY2xpZW50TGVmdAoJCX07Cgl9LAoKCXBvc2l0aW9uOiBmdW5jdGlvbigpIHsKCQlpZiAoICF0aGlzWyAwIF0gKSB7CgkJCXJldHVybjsKCQl9CgoJCXZhciBvZmZzZXRQYXJlbnQsIG9mZnNldCwKCQkJZWxlbSA9IHRoaXNbIDAgXSwKCQkJcGFyZW50T2Zmc2V0ID0geyB0b3A6IDAsIGxlZnQ6IDAgfTsKCgkJLy8gRml4ZWQgZWxlbWVudHMgYXJlIG9mZnNldCBmcm9tIHdpbmRvdyAocGFyZW50T2Zmc2V0ID0ge3RvcDowLCBsZWZ0OiAwfSwgYmVjYXVzZSBpdCBpcyBpdHMgb25seSBvZmZzZXQgcGFyZW50CgkJaWYgKCBqUXVlcnkuY3NzKCBlbGVtLCAicG9zaXRpb24iICkgPT09ICJmaXhlZCIgKSB7CgkJCS8vIFdlIGFzc3VtZSB0aGF0IGdldEJvdW5kaW5nQ2xpZW50UmVjdCBpcyBhdmFpbGFibGUgd2hlbiBjb21wdXRlZCBwb3NpdGlvbiBpcyBmaXhlZAoJCQlvZmZzZXQgPSBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwoKCQl9IGVsc2UgewoJCQkvLyBHZXQgKnJlYWwqIG9mZnNldFBhcmVudAoJCQlvZmZzZXRQYXJlbnQgPSB0aGlzLm9mZnNldFBhcmVudCgpOwoKCQkJLy8gR2V0IGNvcnJlY3Qgb2Zmc2V0cwoJCQlvZmZzZXQgPSB0aGlzLm9mZnNldCgpOwoJCQlpZiAoICFqUXVlcnkubm9kZU5hbWUoIG9mZnNldFBhcmVudFsgMCBdLCAiaHRtbCIgKSApIHsKCQkJCXBhcmVudE9mZnNldCA9IG9mZnNldFBhcmVudC5vZmZzZXQoKTsKCQkJfQoKCQkJLy8gQWRkIG9mZnNldFBhcmVudCBib3JkZXJzCgkJCXBhcmVudE9mZnNldC50b3AgKz0galF1ZXJ5LmNzcyggb2Zmc2V0UGFyZW50WyAwIF0sICJib3JkZXJUb3BXaWR0aCIsIHRydWUgKTsKCQkJcGFyZW50T2Zmc2V0LmxlZnQgKz0galF1ZXJ5LmNzcyggb2Zmc2V0UGFyZW50WyAwIF0sICJib3JkZXJMZWZ0V2lkdGgiLCB0cnVlICk7CgkJfQoKCQkvLyBTdWJ0cmFjdCBwYXJlbnQgb2Zmc2V0cyBhbmQgZWxlbWVudCBtYXJnaW5zCgkJcmV0dXJuIHsKCQkJdG9wOiBvZmZzZXQudG9wIC0gcGFyZW50T2Zmc2V0LnRvcCAtIGpRdWVyeS5jc3MoIGVsZW0sICJtYXJnaW5Ub3AiLCB0cnVlICksCgkJCWxlZnQ6IG9mZnNldC5sZWZ0IC0gcGFyZW50T2Zmc2V0LmxlZnQgLSBqUXVlcnkuY3NzKCBlbGVtLCAibWFyZ2luTGVmdCIsIHRydWUgKQoJCX07Cgl9LAoKCW9mZnNldFBhcmVudDogZnVuY3Rpb24oKSB7CgkJcmV0dXJuIHRoaXMubWFwKGZ1bmN0aW9uKCkgewoJCQl2YXIgb2Zmc2V0UGFyZW50ID0gdGhpcy5vZmZzZXRQYXJlbnQgfHwgZG9jRWxlbTsKCgkJCXdoaWxlICggb2Zmc2V0UGFyZW50ICYmICggIWpRdWVyeS5ub2RlTmFtZSggb2Zmc2V0UGFyZW50LCAiaHRtbCIgKSAmJiBqUXVlcnkuY3NzKCBvZmZzZXRQYXJlbnQsICJwb3NpdGlvbiIgKSA9PT0gInN0YXRpYyIgKSApIHsKCQkJCW9mZnNldFBhcmVudCA9IG9mZnNldFBhcmVudC5vZmZzZXRQYXJlbnQ7CgkJCX0KCgkJCXJldHVybiBvZmZzZXRQYXJlbnQgfHwgZG9jRWxlbTsKCQl9KTsKCX0KfSk7CgovLyBDcmVhdGUgc2Nyb2xsTGVmdCBhbmQgc2Nyb2xsVG9wIG1ldGhvZHMKalF1ZXJ5LmVhY2goIHsgc2Nyb2xsTGVmdDogInBhZ2VYT2Zmc2V0Iiwgc2Nyb2xsVG9wOiAicGFnZVlPZmZzZXQiIH0sIGZ1bmN0aW9uKCBtZXRob2QsIHByb3AgKSB7Cgl2YXIgdG9wID0gInBhZ2VZT2Zmc2V0IiA9PT0gcHJvcDsKCglqUXVlcnkuZm5bIG1ldGhvZCBdID0gZnVuY3Rpb24oIHZhbCApIHsKCQlyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggZWxlbSwgbWV0aG9kLCB2YWwgKSB7CgkJCXZhciB3aW4gPSBnZXRXaW5kb3coIGVsZW0gKTsKCgkJCWlmICggdmFsID09PSB1bmRlZmluZWQgKSB7CgkJCQlyZXR1cm4gd2luID8gd2luWyBwcm9wIF0gOiBlbGVtWyBtZXRob2QgXTsKCQkJfQoKCQkJaWYgKCB3aW4gKSB7CgkJCQl3aW4uc2Nyb2xsVG8oCgkJCQkJIXRvcCA/IHZhbCA6IHdpbmRvdy5wYWdlWE9mZnNldCwKCQkJCQl0b3AgPyB2YWwgOiB3aW5kb3cucGFnZVlPZmZzZXQKCQkJCSk7CgoJCQl9IGVsc2UgewoJCQkJZWxlbVsgbWV0aG9kIF0gPSB2YWw7CgkJCX0KCQl9LCBtZXRob2QsIHZhbCwgYXJndW1lbnRzLmxlbmd0aCwgbnVsbCApOwoJfTsKfSk7CgovLyBBZGQgdGhlIHRvcC9sZWZ0IGNzc0hvb2tzIHVzaW5nIGpRdWVyeS5mbi5wb3NpdGlvbgovLyBXZWJraXQgYnVnOiBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MjkwODQKLy8gZ2V0Q29tcHV0ZWRTdHlsZSByZXR1cm5zIHBlcmNlbnQgd2hlbiBzcGVjaWZpZWQgZm9yIHRvcC9sZWZ0L2JvdHRvbS9yaWdodAovLyByYXRoZXIgdGhhbiBtYWtlIHRoZSBjc3MgbW9kdWxlIGRlcGVuZCBvbiB0aGUgb2Zmc2V0IG1vZHVsZSwgd2UganVzdCBjaGVjayBmb3IgaXQgaGVyZQpqUXVlcnkuZWFjaCggWyAidG9wIiwgImxlZnQiIF0sIGZ1bmN0aW9uKCBpLCBwcm9wICkgewoJalF1ZXJ5LmNzc0hvb2tzWyBwcm9wIF0gPSBhZGRHZXRIb29rSWYoIHN1cHBvcnQucGl4ZWxQb3NpdGlvbiwKCQlmdW5jdGlvbiggZWxlbSwgY29tcHV0ZWQgKSB7CgkJCWlmICggY29tcHV0ZWQgKSB7CgkJCQljb21wdXRlZCA9IGN1ckNTUyggZWxlbSwgcHJvcCApOwoJCQkJLy8gaWYgY3VyQ1NTIHJldHVybnMgcGVyY2VudGFnZSwgZmFsbGJhY2sgdG8gb2Zmc2V0CgkJCQlyZXR1cm4gcm51bW5vbnB4LnRlc3QoIGNvbXB1dGVkICkgPwoJCQkJCWpRdWVyeSggZWxlbSApLnBvc2l0aW9uKClbIHByb3AgXSArICJweCIgOgoJCQkJCWNvbXB1dGVkOwoJCQl9CgkJfQoJKTsKfSk7CgoKLy8gQ3JlYXRlIGlubmVySGVpZ2h0LCBpbm5lcldpZHRoLCBoZWlnaHQsIHdpZHRoLCBvdXRlckhlaWdodCBhbmQgb3V0ZXJXaWR0aCBtZXRob2RzCmpRdWVyeS5lYWNoKCB7IEhlaWdodDogImhlaWdodCIsIFdpZHRoOiAid2lkdGgiIH0sIGZ1bmN0aW9uKCBuYW1lLCB0eXBlICkgewoJalF1ZXJ5LmVhY2goIHsgcGFkZGluZzogImlubmVyIiArIG5hbWUsIGNvbnRlbnQ6IHR5cGUsICIiOiAib3V0ZXIiICsgbmFtZSB9LCBmdW5jdGlvbiggZGVmYXVsdEV4dHJhLCBmdW5jTmFtZSApIHsKCQkvLyBtYXJnaW4gaXMgb25seSBmb3Igb3V0ZXJIZWlnaHQsIG91dGVyV2lkdGgKCQlqUXVlcnkuZm5bIGZ1bmNOYW1lIF0gPSBmdW5jdGlvbiggbWFyZ2luLCB2YWx1ZSApIHsKCQkJdmFyIGNoYWluYWJsZSA9IGFyZ3VtZW50cy5sZW5ndGggJiYgKCBkZWZhdWx0RXh0cmEgfHwgdHlwZW9mIG1hcmdpbiAhPT0gImJvb2xlYW4iICksCgkJCQlleHRyYSA9IGRlZmF1bHRFeHRyYSB8fCAoIG1hcmdpbiA9PT0gdHJ1ZSB8fCB2YWx1ZSA9PT0gdHJ1ZSA/ICJtYXJnaW4iIDogImJvcmRlciIgKTsKCgkJCXJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCBlbGVtLCB0eXBlLCB2YWx1ZSApIHsKCQkJCXZhciBkb2M7CgoJCQkJaWYgKCBqUXVlcnkuaXNXaW5kb3coIGVsZW0gKSApIHsKCQkJCQkvLyBBcyBvZiA1LzgvMjAxMiB0aGlzIHdpbGwgeWllbGQgaW5jb3JyZWN0IHJlc3VsdHMgZm9yIE1vYmlsZSBTYWZhcmksIGJ1dCB0aGVyZQoJCQkJCS8vIGlzbid0IGEgd2hvbGUgbG90IHdlIGNhbiBkby4gU2VlIHB1bGwgcmVxdWVzdCBhdCB0aGlzIFVSTCBmb3IgZGlzY3Vzc2lvbjoKCQkJCQkvLyBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L2pxdWVyeS9wdWxsLzc2NAoJCQkJCXJldHVybiBlbGVtLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudFsgImNsaWVudCIgKyBuYW1lIF07CgkJCQl9CgoJCQkJLy8gR2V0IGRvY3VtZW50IHdpZHRoIG9yIGhlaWdodAoJCQkJaWYgKCBlbGVtLm5vZGVUeXBlID09PSA5ICkgewoJCQkJCWRvYyA9IGVsZW0uZG9jdW1lbnRFbGVtZW50OwoKCQkJCQkvLyBFaXRoZXIgc2Nyb2xsW1dpZHRoL0hlaWdodF0gb3Igb2Zmc2V0W1dpZHRoL0hlaWdodF0gb3IgY2xpZW50W1dpZHRoL0hlaWdodF0sCgkJCQkJLy8gd2hpY2hldmVyIGlzIGdyZWF0ZXN0CgkJCQkJcmV0dXJuIE1hdGgubWF4KAoJCQkJCQllbGVtLmJvZHlbICJzY3JvbGwiICsgbmFtZSBdLCBkb2NbICJzY3JvbGwiICsgbmFtZSBdLAoJCQkJCQllbGVtLmJvZHlbICJvZmZzZXQiICsgbmFtZSBdLCBkb2NbICJvZmZzZXQiICsgbmFtZSBdLAoJCQkJCQlkb2NbICJjbGllbnQiICsgbmFtZSBdCgkJCQkJKTsKCQkJCX0KCgkJCQlyZXR1cm4gdmFsdWUgPT09IHVuZGVmaW5lZCA/CgkJCQkJLy8gR2V0IHdpZHRoIG9yIGhlaWdodCBvbiB0aGUgZWxlbWVudCwgcmVxdWVzdGluZyBidXQgbm90IGZvcmNpbmcgcGFyc2VGbG9hdAoJCQkJCWpRdWVyeS5jc3MoIGVsZW0sIHR5cGUsIGV4dHJhICkgOgoKCQkJCQkvLyBTZXQgd2lkdGggb3IgaGVpZ2h0IG9uIHRoZSBlbGVtZW50CgkJCQkJalF1ZXJ5LnN0eWxlKCBlbGVtLCB0eXBlLCB2YWx1ZSwgZXh0cmEgKTsKCQkJfSwgdHlwZSwgY2hhaW5hYmxlID8gbWFyZ2luIDogdW5kZWZpbmVkLCBjaGFpbmFibGUsIG51bGwgKTsKCQl9OwoJfSk7Cn0pOwoKCi8vIFRoZSBudW1iZXIgb2YgZWxlbWVudHMgY29udGFpbmVkIGluIHRoZSBtYXRjaGVkIGVsZW1lbnQgc2V0CmpRdWVyeS5mbi5zaXplID0gZnVuY3Rpb24oKSB7CglyZXR1cm4gdGhpcy5sZW5ndGg7Cn07CgpqUXVlcnkuZm4uYW5kU2VsZiA9IGpRdWVyeS5mbi5hZGRCYWNrOwoKCgoKLy8gUmVnaXN0ZXIgYXMgYSBuYW1lZCBBTUQgbW9kdWxlLCBzaW5jZSBqUXVlcnkgY2FuIGJlIGNvbmNhdGVuYXRlZCB3aXRoIG90aGVyCi8vIGZpbGVzIHRoYXQgbWF5IHVzZSBkZWZpbmUsIGJ1dCBub3QgdmlhIGEgcHJvcGVyIGNvbmNhdGVuYXRpb24gc2NyaXB0IHRoYXQKLy8gdW5kZXJzdGFuZHMgYW5vbnltb3VzIEFNRCBtb2R1bGVzLiBBIG5hbWVkIEFNRCBpcyBzYWZlc3QgYW5kIG1vc3Qgcm9idXN0Ci8vIHdheSB0byByZWdpc3Rlci4gTG93ZXJjYXNlIGpxdWVyeSBpcyB1c2VkIGJlY2F1c2UgQU1EIG1vZHVsZSBuYW1lcyBhcmUKLy8gZGVyaXZlZCBmcm9tIGZpbGUgbmFtZXMsIGFuZCBqUXVlcnkgaXMgbm9ybWFsbHkgZGVsaXZlcmVkIGluIGEgbG93ZXJjYXNlCi8vIGZpbGUgbmFtZS4gRG8gdGhpcyBhZnRlciBjcmVhdGluZyB0aGUgZ2xvYmFsIHNvIHRoYXQgaWYgYW4gQU1EIG1vZHVsZSB3YW50cwovLyB0byBjYWxsIG5vQ29uZmxpY3QgdG8gaGlkZSB0aGlzIHZlcnNpb24gb2YgalF1ZXJ5LCBpdCB3aWxsIHdvcmsuCgovLyBOb3RlIHRoYXQgZm9yIG1heGltdW0gcG9ydGFiaWxpdHksIGxpYnJhcmllcyB0aGF0IGFyZSBub3QgalF1ZXJ5IHNob3VsZAovLyBkZWNsYXJlIHRoZW1zZWx2ZXMgYXMgYW5vbnltb3VzIG1vZHVsZXMsIGFuZCBhdm9pZCBzZXR0aW5nIGEgZ2xvYmFsIGlmIGFuCi8vIEFNRCBsb2FkZXIgaXMgcHJlc2VudC4galF1ZXJ5IGlzIGEgc3BlY2lhbCBjYXNlLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiwgc2VlCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9qcmJ1cmtlL3JlcXVpcmVqcy93aWtpL1VwZGF0aW5nLWV4aXN0aW5nLWxpYnJhcmllcyN3aWtpLWFub24KCmlmICggdHlwZW9mIGRlZmluZSA9PT0gImZ1bmN0aW9uIiAmJiBkZWZpbmUuYW1kICkgewoJZGVmaW5lKCAianF1ZXJ5IiwgW10sIGZ1bmN0aW9uKCkgewoJCXJldHVybiBqUXVlcnk7Cgl9KTsKfQoKCgoKdmFyCgkvLyBNYXAgb3ZlciBqUXVlcnkgaW4gY2FzZSBvZiBvdmVyd3JpdGUKCV9qUXVlcnkgPSB3aW5kb3cualF1ZXJ5LAoKCS8vIE1hcCBvdmVyIHRoZSAkIGluIGNhc2Ugb2Ygb3ZlcndyaXRlCglfJCA9IHdpbmRvdy4kOwoKalF1ZXJ5Lm5vQ29uZmxpY3QgPSBmdW5jdGlvbiggZGVlcCApIHsKCWlmICggd2luZG93LiQgPT09IGpRdWVyeSApIHsKCQl3aW5kb3cuJCA9IF8kOwoJfQoKCWlmICggZGVlcCAmJiB3aW5kb3cualF1ZXJ5ID09PSBqUXVlcnkgKSB7CgkJd2luZG93LmpRdWVyeSA9IF9qUXVlcnk7Cgl9CgoJcmV0dXJuIGpRdWVyeTsKfTsKCi8vIEV4cG9zZSBqUXVlcnkgYW5kICQgaWRlbnRpZmllcnMsIGV2ZW4gaW4KLy8gQU1EICgjNzEwMiNjb21tZW50OjEwLCBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L2pxdWVyeS9wdWxsLzU1NykKLy8gYW5kIENvbW1vbkpTIGZvciBicm93c2VyIGVtdWxhdG9ycyAoIzEzNTY2KQppZiAoIHR5cGVvZiBub0dsb2JhbCA9PT0gc3RydW5kZWZpbmVkICkgewoJd2luZG93LmpRdWVyeSA9IHdpbmRvdy4kID0galF1ZXJ5Owp9CgoKCgpyZXR1cm4galF1ZXJ5OwoKfSkpOwoKfSx7fV0sMjpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7CnZhciAkLCBhZGRUb2dnbGUsIHRvYzsKCiQgPSByZXF1aXJlKCdqcXVlcnknKTsKCnRvYyA9IHJlcXVpcmUoJy4vdG9jJyk7CgphZGRUb2dnbGUgPSBmdW5jdGlvbihjbGFzc05hbWUsIG5hbWUsIGFkZGl0aW9uYWxDbGFzc2VzKSB7CiAgdmFyIHRvZ2dsZU1haW5hOwogIHRvZ2dsZU1haW5hID0gZnVuY3Rpb24oKSB7CiAgICB2YXIgZXh0cmFDbGFzc2VzLCB0aGVUb2dnbGluZywgdG9nZ2xlYWJsZTsKICAgIHRvZ2dsZWFibGUgPSAkKHRoaXMpOwogICAgZXh0cmFDbGFzc2VzID0gYWRkaXRpb25hbENsYXNzZXMgIT0gbnVsbCA/IGFkZGl0aW9uYWxDbGFzc2VzIDogewogICAgICBhZGRpdGlvbmFsQ2xhc3NlczogJycKICAgIH07CiAgICB0aGVUb2dnbGluZyA9IGZ1bmN0aW9uKGV2dCkgewogICAgICB0b2dnbGVhYmxlLnRvZ2dsZSgpOwogICAgICByZXR1cm4gZXZ0LnByZXZlbnREZWZhdWx0KCk7CiAgICB9OwogICAgdG9nZ2xlYWJsZS5hZGRDbGFzcygicGFuZWwtYm9keSIpLndyYXAoJzxkaXYgY2xhc3M9InBhbmVsIHBhbmVsLWRlZmF1bHQgI3tleHRyYUNsYXNzZXN9Ij48L2Rpdj4nKS5oaWRlKCk7CiAgICByZXR1cm4gJCgiPGEgaHJlZj1cImphdmFzY3JpcHQ6dm9pZCAwXCI+PGRpdiBjbGFzcz1cInBhbmVsLWhlYWRpbmdcIj48aDU+ICIgKyBuYW1lICsgIiAoY2xpY2sgdG8gcmV2ZWFsKTwvaDU+PC9kaXY+PC9hPiIpLmluc2VydEJlZm9yZSh0b2dnbGVhYmxlKS5jbGljayh0aGVUb2dnbGluZyk7CiAgfTsKICByZXR1cm4gJCgiLiIgKyBjbGFzc05hbWUpLmVhY2godG9nZ2xlTWFpbmEpOwp9OwoKJChmdW5jdGlvbigpIHsKICB0b2MuaW5pdCgnLnRvYy10b2dnbGUnLCAnLmNvdmVyLW5vdGVzLC50b2MtY29udGVudHMnKTsKICBhZGRUb2dnbGUoJ3NvbHV0aW9uJywgJ1NvbHV0aW9uJyk7Cn0pOwoKCgp9LHsiLi90b2MiOjMsImpxdWVyeSI6MX1dLDM6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpewp2YXIgJCwgaW5pdDsKCiQgPSByZXF1aXJlKCdqcXVlcnknKTsKCmluaXQgPSBmdW5jdGlvbih0b2dnbGUsIHRvYykgewogIHRvZ2dsZSA9ICQodG9nZ2xlKTsKICB0b2MgPSAkKHRvYyk7CiAgdG9nZ2xlLm9uKCdjbGljaycsIGZ1bmN0aW9uKGV2dCkgewogICAgdG9jLnNsaWRlRG93bigpOwogICAgdG9nZ2xlLnJlbW92ZSgpOwogIH0pOwp9OwoKbW9kdWxlLmV4cG9ydHMgPSB7CiAgaW5pdDogaW5pdAp9OwoKCgp9LHsianF1ZXJ5IjoxfV19LHt9LFsyXSk7Cg=="></script>
</head>
<body>
<header class="hero">
<div class="container">
<div class="hero-text">
<h1 class="title">
The Type Astronaut’s Guide to Shapeless
</h1>
<h3 class="author">Dave Gurnell</h3>
<p class="date">January 2017</p>
<img class="brand-logo" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMjcycHgiIGhlaWdodD0iMTIwcHgiIHZpZXdCb3g9IjAgMCAyNzIgMTIwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyNzIgMTIwIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnIGlkPSJCRyI+DQo8L2c+DQo8ZyBpZD0iTG9nb18xXyI+DQoJPGcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAgICAiPg0KCQk8cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMTguMzA5LDg5LjE0NHYxNi4xNjRjMCwxLjU1NCwwLjM1OSwyLjc1NiwxLjA3OSwzLjYwNmMwLjcxOSwwLjg1MiwxLjc5NywxLjI3NywzLjIzNSwxLjI3Nw0KCQkJYzEuMDU4LDAsMi4wNDktMC4yMzUsMi45NzUtMC43MDdjMC45MjUtMC40NzEsMS44MDEtMS4xMTksMi42MjctMS45NDVWODkuMTQ0aDYuMTI0djI1LjQzNmgtMy43NDQNCgkJCWMtMC43OTMsMC0xLjMxMy0wLjM3Mi0xLjU2Mi0xLjExNWwtMC40MjEtMi4wMzNjLTAuNTI5LDAuNTI5LTEuMDc1LDEuMDEzLTEuNjM2LDEuNDVjLTAuNTYyLDAuNDM4LTEuMTYxLDAuODEtMS43OTcsMS4xMTUNCgkJCWMtMC42MzYsMC4zMDctMS4zMjIsMC41NDYtMi4wNTgsMC43MmMtMC43MzUsMC4xNzMtMS41MjQsMC4yNi0yLjM2OCwwLjI2Yy0xLjM4OCwwLTIuNjE1LTAuMjM1LTMuNjgxLTAuNzA2DQoJCQljLTEuMDY2LTAuNDcyLTEuOTYzLTEuMTM3LTIuNjktMS45OTZjLTAuNzI4LTAuODU5LTEuMjc2LTEuODgtMS42NDgtMy4wNjJzLTAuNTU4LTIuNDgyLTAuNTU4LTMuOTA0Vjg5LjE0NEgxOC4zMDl6Ii8+DQoJCTxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik00MC44OTMsMTE0LjU3OVY4OS4xNDRoMy43NDNjMC43OTMsMCwxLjMxNCwwLjM3MiwxLjU2MiwxLjExNmwwLjQyMSwyLjAwOA0KCQkJYzAuNTEyLTAuNTI4LDEuMDU0LTEuMDA4LDEuNjI0LTEuNDM4YzAuNTctMC40MywxLjE3My0wLjgwMiwxLjgxLTEuMTE2YzAuNjM2LTAuMzEzLDEuMzE3LTAuNTUzLDIuMDQ1LTAuNzE5DQoJCQljMC43MjctMC4xNjUsMS41MjEtMC4yNDgsMi4zOC0wLjI0OGMxLjM4OCwwLDIuNjIsMC4yMzUsMy42OTQsMC43MDdjMS4wNzQsMC40NzEsMS45NzEsMS4xMzIsMi42OSwxLjk4Mw0KCQkJYzAuNzE5LDAuODUxLDEuMjY0LDEuODY3LDEuNjM2LDMuMDQ5YzAuMzcyLDEuMTgyLDAuNTU4LDIuNDgzLDAuNTU4LDMuOTA0djE2LjE4OGgtNi4xMjNWOTguMzkxYzAtMS41NTMtMC4zNi0yLjc1Ni0xLjA3OS0zLjYwNg0KCQkJYy0wLjcxOS0wLjg1Mi0xLjc5Ny0xLjI3Ny0zLjIzNS0xLjI3N2MtMS4wNTgsMC0yLjA0OSwwLjI0LTIuOTc1LDAuNzE5Yy0wLjkyNiwwLjQ4LTEuODAyLDEuMTMzLTIuNjI4LDEuOTU5djE4LjM5NUg0MC44OTN6Ii8+DQoJCTxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik04Ni45NzgsMTE0LjU3OWMtMC43OTMsMC0xLjMxMy0wLjM3Mi0xLjU2Mi0xLjExNWwtMC40OTYtMi40NTVjLTAuNTI5LDAuNTk2LTEuMDgzLDEuMTMzLTEuNjYxLDEuNjEyDQoJCQljLTAuNTc5LDAuNDc5LTEuMjAzLDAuODkyLTEuODcyLDEuMjM5Yy0wLjY2OSwwLjM0Ny0xLjM4OSwwLjYxNS0yLjE1NywwLjgwNmMtMC43NjksMC4xODktMS41OTksMC4yODUtMi40OTIsMC4yODUNCgkJCWMtMS4zODgsMC0yLjY2MS0wLjI5LTMuODE4LTAuODY4cy0yLjE1My0xLjQxNy0yLjk4Ny0yLjUxNmMtMC44MzQtMS4xLTEuNDc5LTIuNDU4LTEuOTM0LTQuMDc4cy0wLjY4Mi0zLjQ3MS0wLjY4Mi01LjU1NA0KCQkJYzAtMS44ODQsMC4yNTYtMy42MzYsMC43NjktNS4yNTVjMC41MTItMS42MiwxLjI0OC0zLjAyNCwyLjIwNy00LjIxNWMwLjk1OC0xLjE4OSwyLjEwNy0yLjExOSwzLjQ0Ni0yLjc4OQ0KCQkJYzEuMzM4LTAuNjY5LDIuODQyLTEuMDA0LDQuNTEyLTEuMDA0YzEuNDIxLDAsMi42MzYsMC4yMjgsMy42NDQsMC42ODJjMS4wMDgsMC40NTUsMS45MDksMS4wNjIsMi43MDIsMS44MjJWNzcuNzRoNi4xMjR2MzYuODM5DQoJCQlIODYuOTc4eiBNNzguODIyLDExMC4wOTJjMS4yNzIsMCwyLjM1NS0wLjI2NCwzLjI0OC0wLjc5M3MxLjczNS0xLjI4LDIuNTI4LTIuMjU2Vjk1LjYzOWMtMC42OTQtMC44NDMtMS40NS0xLjQzOC0yLjI2OC0xLjc4NA0KCQkJYy0wLjgxOC0wLjM0OC0xLjY5OC0wLjUyMS0yLjY0LTAuNTIxYy0wLjkyNiwwLTEuNzY1LDAuMTczLTIuNTE2LDAuNTIxYy0wLjc1MiwwLjM0Ny0xLjM4OSwwLjg3Mi0xLjkwOSwxLjU3NA0KCQkJcy0wLjkyMSwxLjU5NS0xLjIwMiwyLjY3N2MtMC4yODEsMS4wODMtMC40MjEsMi4zNTktMC40MjEsMy44M2MwLDEuNDg4LDAuMTIsMi43NDgsMC4zNTksMy43ODENCgkJCWMwLjIzOSwxLjAzMywwLjU4MywxLjg3NiwxLjAyOSwyLjUyOGMwLjQ0NiwwLjY1MywwLjk5MiwxLjEyNCwxLjYzNiwxLjQxM1M3OC4wMjksMTEwLjA5Miw3OC44MjIsMTEwLjA5MnoiLz4NCgkJPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTEwNy44NTIsODguNzQ3YzEuNjAzLDAsMy4wNzgsMC4yNTcsNC40MjUsMC43NjljMS4zNDcsMC41MTMsMi41MDgsMS4yNjEsMy40ODMsMi4yNDQNCgkJCWMwLjk3NSwwLjk4MywxLjczNSwyLjE4OSwyLjI4MSwzLjYxOXMwLjgxOCwzLjA2MiwwLjgxOCw0Ljg5NmMwLDAuNDYzLTAuMDIxLDAuODQ3LTAuMDYyLDEuMTUyDQoJCQljLTAuMDQyLDAuMzA2LTAuMTE2LDAuNTQ1LTAuMjIzLDAuNzE5cy0wLjI1MiwwLjI5OC0wLjQzNCwwLjM3MmMtMC4xODIsMC4wNzQtMC40MTQsMC4xMTEtMC42OTQsMC4xMTFoLTE1LjcxNw0KCQkJYzAuMTgyLDIuNjExLDAuODg0LDQuNTI4LDIuMTA3LDUuNzUyYzEuMjIzLDEuMjIzLDIuODQyLDEuODM0LDQuODU5LDEuODM0YzAuOTkyLDAsMS44NDctMC4xMTUsMi41NjYtMC4zNDcNCgkJCWMwLjcxOS0wLjIzMSwxLjM0Ny0wLjQ4NywxLjg4NC0wLjc2OXMxLjAwOC0wLjUzNywxLjQxMy0wLjc2OWMwLjQwNS0wLjIzMSwwLjc5Ny0wLjM0OCwxLjE3OC0wLjM0OA0KCQkJYzAuMjQ4LDAsMC40NjIsMC4wNSwwLjY0NSwwLjE0OWMwLjE4MiwwLjA5OSwwLjMzOCwwLjIzOSwwLjQ3MSwwLjQyMWwxLjc4NSwyLjIzMWMtMC42NzgsMC43OTMtMS40MzgsMS40NTktMi4yODEsMS45OTYNCgkJCXMtMS43MjMsMC45NjctMi42NCwxLjI4OWMtMC45MTcsMC4zMjItMS44NTEsMC41NDktMi44MDEsMC42ODJjLTAuOTUxLDAuMTMyLTEuODcyLDAuMTk4LTIuNzY0LDAuMTk4DQoJCQljLTEuNzY5LDAtMy40MTMtMC4yOTQtNC45MzMtMC44OGMtMS41MjEtMC41ODctMi44NDMtMS40NTQtMy45NjctMi42MDRjLTEuMTI0LTEuMTQ4LTIuMDA4LTIuNTY5LTIuNjUyLTQuMjY0DQoJCQlzLTAuOTY3LTMuNjU3LTAuOTY3LTUuODg4YzAtMS43MzUsMC4yODEtMy4zNjcsMC44NDMtNC44OTZjMC41NjItMS41MjgsMS4zNjctMi44NTksMi40MTctMy45OTENCgkJCWMxLjA0OS0xLjEzMiwyLjMzLTIuMDI4LDMuODQyLTIuNjg5QzEwNC4yNDUsODkuMDc4LDEwNS45NTEsODguNzQ3LDEwNy44NTIsODguNzQ3eiBNMTA3Ljk3Niw5My4xMzYNCgkJCWMtMS43ODUsMC0zLjE4MiwwLjUwNC00LjE5LDEuNTEyYy0xLjAwOCwxLjAwOS0xLjY1MywyLjQzOC0xLjkzNCw0LjI4OWgxMS41MDNjMC0wLjc5NC0wLjEwOC0xLjU0MS0wLjMyMi0yLjI0NA0KCQkJYy0wLjIxNS0wLjcwMi0wLjU0NS0xLjMxNy0wLjk5Mi0xLjg0N2MtMC40NDYtMC41MjgtMS4wMDgtMC45NDUtMS42ODYtMS4yNTJDMTA5LjY3Nyw5My4yODgsMTA4Ljg4NCw5My4xMzYsMTA3Ljk3Niw5My4xMzZ6Ii8+DQoJCTxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0xMjMuODQxLDExNC41NzlWODkuMTQ0aDMuNTk1YzAuNjI4LDAsMS4wNjYsMC4xMTYsMS4zMTMsMC4zNDhjMC4yNDgsMC4yMzEsMC40MTMsMC42MjgsMC40OTYsMS4xODkNCgkJCWwwLjM3MiwzLjA3NGMwLjkwOS0xLjU2OSwxLjk3NS0yLjgxLDMuMTk4LTMuNzE5YzEuMjIzLTAuOTA4LDIuNTk0LTEuMzYzLDQuMTE1LTEuMzYzYzEuMjU2LDAsMi4yOTcsMC4yODksMy4xMjQsMC44NjgNCgkJCWwtMC43OTQsNC41ODZjLTAuMDQ5LDAuMjk4LTAuMTU2LDAuNTA4LTAuMzIyLDAuNjMyYy0wLjE2NCwwLjEyNC0wLjM4OCwwLjE4Ny0wLjY2OCwwLjE4N2MtMC4yNDgsMC0wLjU4OC0wLjA1OC0xLjAxOC0wLjE3NA0KCQkJYy0wLjQzLTAuMTE1LTEtMC4xNzQtMS43MS0wLjE3NGMtMS4yNzMsMC0yLjM2NCwwLjM1Mi0zLjI3MiwxLjA1NGMtMC45MDksMC43MDMtMS42NzgsMS43MzEtMi4zMDYsMy4wODd2MTUuODQxSDEyMy44NDF6Ii8+DQoJCTxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0xNTkuMTkxLDk0LjEwM2MtMC4xNjUsMC4yNjQtMC4zMzksMC40NS0wLjUyMSwwLjU1OGMtMC4xODMsMC4xMDctMC40MTMsMC4xNjEtMC42OTQsMC4xNjENCgkJCWMtMC4yOTcsMC0wLjYxNS0wLjA4My0wLjk1NC0wLjI0OHMtMC43MzEtMC4zNTEtMS4xNzgtMC41NThzLTAuOTU0LTAuMzkzLTEuNTI0LTAuNTU4cy0xLjI0NC0wLjI0OC0yLjAyMS0wLjI0OA0KCQkJYy0xLjIwNiwwLTIuMTU3LDAuMjU2LTIuODUxLDAuNzY5Yy0wLjY5NCwwLjUxMi0xLjA0MSwxLjE4Mi0xLjA0MSwyLjAwOGMwLDAuNTQ1LDAuMTc3LDEuMDA0LDAuNTMzLDEuMzc2DQoJCQljMC4zNTQsMC4zNzIsMC44MjYsMC42OTgsMS40MTIsMC45NzljMC41ODcsMC4yODEsMS4yNTIsMC41MzMsMS45OTYsMC43NTdjMC43NDQsMC4yMjMsMS41MDQsMC40NjcsMi4yOCwwLjczMQ0KCQkJczEuNTM3LDAuNTY2LDIuMjgsMC45MDRjMC43NDQsMC4zMzksMS40MSwwLjc2OSwxLjk5NiwxLjI4OWMwLjU4NywwLjUyMSwxLjA1OCwxLjE0NSwxLjQxMywxLjg3MnMwLjUzMywxLjYwNCwwLjUzMywyLjYyOA0KCQkJYzAsMS4yMjMtMC4yMjQsMi4zNTEtMC42NjksMy4zODRjLTAuNDQ3LDEuMDMzLTEuMSwxLjkyNi0xLjk1OSwyLjY3N2MtMC44NTksMC43NTMtMS45MjEsMS4zMzktMy4xODYsMS43NjENCgkJCWMtMS4yNjQsMC40MjEtMi43MTUsMC42MzItNC4zNTEsMC42MzJjLTAuODc2LDAtMS43MzEtMC4wNzgtMi41NjUtMC4yMzVjLTAuODM1LTAuMTU3LTEuNjM3LTAuMzc2LTIuNDA1LTAuNjU3DQoJCQljLTAuNzY5LTAuMjgtMS40NzktMC42MTEtMi4xMzItMC45OTFjLTAuNjUzLTAuMzgtMS4yMjctMC43OTMtMS43MjMtMS4yMzlsMS40MTItMi4zMzFjMC4xODItMC4yOCwwLjM5Ny0wLjQ5NSwwLjY0NS0wLjY0NQ0KCQkJYzAuMjQ4LTAuMTQ4LDAuNTYyLTAuMjIzLDAuOTQzLTAuMjIzYzAuMzc5LDAsMC43MzgsMC4xMDcsMS4wNzgsMC4zMjJjMC4zMzgsMC4yMTUsMC43MywwLjQ0NiwxLjE3OCwwLjY5NA0KCQkJYzAuNDQ1LDAuMjQ4LDAuOTcxLDAuNDc5LDEuNTc0LDAuNjkzYzAuNjAzLDAuMjE2LDEuMzY3LDAuMzIyLDIuMjkzLDAuMzIyYzAuNzI3LDAsMS4zNTEtMC4wODYsMS44NzEtMC4yNg0KCQkJYzAuNTIxLTAuMTc0LDAuOTUtMC40LDEuMjg5LTAuNjgyczAuNTg2LTAuNjA3LDAuNzQ0LTAuOTc5YzAuMTU2LTAuMzcyLDAuMjM1LTAuNzU2LDAuMjM1LTEuMTUyYzAtMC41OTYtMC4xNzgtMS4wODMtMC41MzMtMS40NjMNCgkJCXMtMC44MjctMC43MTEtMS40MTMtMC45OTFjLTAuNTg2LTAuMjgxLTEuMjU2LTAuNTMzLTIuMDA4LTAuNzU3Yy0wLjc1Mi0wLjIyMy0xLjUyMS0wLjQ2Ny0yLjMwNi0wLjczMQ0KCQkJYy0wLjc4NS0wLjI2NC0xLjU1NC0wLjU3My0yLjMwNi0wLjkzYy0wLjc1Mi0wLjM1NC0xLjQyMi0wLjgwNi0yLjAwOC0xLjM1MWMtMC41ODctMC41NDYtMS4wNTgtMS4yMTUtMS40MTMtMi4wMDgNCgkJCWMtMC4zNTUtMC43OTQtMC41MzItMS43NTItMC41MzItMi44NzZjMC0xLjA0MSwwLjIwNS0yLjAzMywwLjYxOS0yLjk3NWMwLjQxMi0wLjk0MiwxLjAyLTEuNzY1LDEuODIyLTIuNDY3DQoJCQljMC44MDEtMC43MDIsMS44MDEtMS4yNjUsMy0xLjY4NmMxLjE5Ny0wLjQyMiwyLjU4Mi0wLjYzMyw0LjE1Mi0wLjYzM2MxLjc1MSwwLDMuMzQ2LDAuMjksNC43ODQsMC44NjgNCgkJCWMxLjQzOCwwLjU3OCwyLjYzNiwxLjMzOSwzLjU5NSwyLjI4TDE1OS4xOTEsOTQuMTAzeiIvPg0KCQk8cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMTgzLjYzNSw5NC41MjNjLTAuMTgyLDAuMjMxLTAuMzU5LDAuNDEzLTAuNTMzLDAuNTQ2Yy0wLjE3NCwwLjEzMi0wLjQyNiwwLjE5OC0wLjc1NiwwLjE5OA0KCQkJYy0wLjMxNCwwLTAuNjItMC4wOTYtMC45MTgtMC4yODVjLTAuMjk3LTAuMTktMC42NTItMC40MDUtMS4wNjUtMC42NDVzLTAuOTA1LTAuNDU1LTEuNDc2LTAuNjQ1DQoJCQljLTAuNTctMC4xOS0xLjI3Ni0wLjI4NS0yLjExOS0wLjI4NWMtMS4wNzQsMC0yLjAxNywwLjE5NC0yLjgyNiwwLjU4MmMtMC44MTEsMC4zODktMS40ODMsMC45NDYtMi4wMjEsMS42NzQNCgkJCXMtMC45MzgsMS42MDctMS4yMDIsMi42NGMtMC4yNjUsMS4wMzMtMC4zOTYsMi4yMDMtMC4zOTYsMy41MDhjMCwxLjM1NSwwLjE0NSwyLjU2MiwwLjQzNCwzLjYyczAuNzA3LDEuOTQ2LDEuMjUyLDIuNjY1DQoJCQlzMS4yMDYsMS4yNjQsMS45ODMsMS42MzZjMC43NzYsMC4zNzIsMS42NTIsMC41NTgsMi42MjgsMC41NThjMC45NzUsMCwxLjc2NC0wLjExOSwyLjM2Ny0wLjM1OQ0KCQkJYzAuNjA0LTAuMjM5LDEuMTExLTAuNTA0LDEuNTI1LTAuNzkzYzAuNDEyLTAuMjg5LDAuNzcxLTAuNTU0LDEuMDc4LTAuNzkzYzAuMzA1LTAuMjQsMC42NDgtMC4zNiwxLjAyOC0wLjM2DQoJCQljMC40OTYsMCwwLjg2OCwwLjE5LDEuMTE2LDAuNTdsMS43NiwyLjIzMWMtMC42NzgsMC43OTMtMS40MTMsMS40NTktMi4yMDcsMS45OTZjLTAuNzkzLDAuNTM3LTEuNjE1LDAuOTY3LTIuNDY3LDEuMjg5DQoJCQljLTAuODUxLDAuMzIyLTEuNzMsMC41NDktMi42NCwwLjY4MmMtMC45MDksMC4xMzItMS44MSwwLjE5OC0yLjcwMiwwLjE5OGMtMS41NywwLTMuMDQ5LTAuMjk0LTQuNDM4LTAuODgNCgkJCWMtMS4zODktMC41ODctMi42LTEuNDQyLTMuNjMyLTIuNTY2Yy0xLjAzMy0xLjEyMy0xLjg1MS0yLjQ5OS0yLjQ1NC00LjEyN3MtMC45MDQtMy40ODMtMC45MDQtNS41NjYNCgkJCWMwLTEuODY3LDAuMjY4LTMuNTk4LDAuODA1LTUuMTkzYzAuNTM3LTEuNTk1LDEuMzI2LTIuOTc1LDIuMzY3LTQuMTRjMS4wNDItMS4xNjUsMi4zMzEtMi4wNzgsMy44NjgtMi43MzkNCgkJCWMxLjUzNi0wLjY2MSwzLjMwNi0wLjk5Miw1LjMwNi0wLjk5MmMxLjg5OSwwLDMuNTY0LDAuMzA3LDQuOTk0LDAuOTE4czIuNzE1LDEuNDg3LDMuODU1LDIuNjI3TDE4My42MzUsOTQuNTIzeiIvPg0KCQk8cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMjAwLjI2OSw4OC43NDdjMS45LDAsMy42MjQsMC4zMDcsNS4xNjksMC45MThzMi44NjMsMS40NzksMy45NTQsMi42MDNzMS45MzQsMi40OTYsMi41MjgsNC4xMTUNCgkJCWMwLjU5NiwxLjYyLDAuODkzLDMuNDMsMC44OTMsNS40MjljMCwyLjAxNy0wLjI5NywzLjgzNS0wLjg5Myw1LjQ1NGMtMC41OTUsMS42Mi0xLjQzOCwzLTIuNTI4LDQuMTQxDQoJCQljLTEuMDkxLDEuMTQtMi40MDksMi4wMTctMy45NTQsMi42MjhjLTEuNTQ1LDAuNjEtMy4yNjksMC45MTctNS4xNjksMC45MTdzLTMuNjI4LTAuMzA3LTUuMTgxLTAuOTE3DQoJCQljLTEuNTU1LTAuNjExLTIuODgxLTEuNDg4LTMuOTc5LTIuNjI4Yy0xLjEtMS4xNDEtMS45NTEtMi41MjEtMi41NTUtNC4xNDFjLTAuNjA0LTEuNjE5LTAuOTA0LTMuNDM4LTAuOTA0LTUuNDU0DQoJCQljMC0xLjk5OSwwLjMwMS0zLjgwOSwwLjkwNC01LjQyOWMwLjYwNC0xLjYxOSwxLjQ1NS0yLjk5MSwyLjU1NS00LjExNWMxLjA5OC0xLjEyNCwyLjQyNC0xLjk5MSwzLjk3OS0yLjYwMw0KCQkJQzE5Ni42NDEsODkuMDU0LDE5OC4zNjgsODguNzQ3LDIwMC4yNjksODguNzQ3eiBNMjAwLjI2OSwxMTAuMjQxYzIuMTE2LDAsMy42ODItMC43MTEsNC42OTgtMi4xMzMNCgkJCWMxLjAxNi0xLjQyMSwxLjUyNC0zLjUwMywxLjUyNC02LjI0N2MwLTIuNzQzLTAuNTA5LTQuODM0LTEuNTI0LTYuMjcxYy0xLjAxNy0xLjQzOC0yLjU4Mi0yLjE1Ny00LjY5OC0yLjE1Nw0KCQkJYy0yLjE0OCwwLTMuNzM1LDAuNzI0LTQuNzYsMi4xNjljLTEuMDI0LDEuNDQ2LTEuNTM2LDMuNTMzLTEuNTM2LDYuMjZjMCwyLjcyOCwwLjUxMiw0LjgwNiwxLjUzNiw2LjIzNQ0KCQkJUzE5OC4xMiwxMTAuMjQxLDIwMC4yNjksMTEwLjI0MXoiLz4NCgkJPHBhdGggZmlsbD0iI0ZGRkZGRiIgZD0iTTIxNy41OTgsMTE0LjU3OVY4OS4xNDRoMy41OTRjMC42MjksMCwxLjA2NiwwLjExNiwxLjMxNCwwLjM0OHMwLjQxMiwwLjYyOCwwLjQ5NiwxLjE4OWwwLjM3MSwzLjA3NA0KCQkJYzAuOTA5LTEuNTY5LDEuOTc1LTIuODEsMy4xOTgtMy43MTljMS4yMjMtMC45MDgsMi41OTUtMS4zNjMsNC4xMTQtMS4zNjNjMS4yNTYsMCwyLjI5OSwwLjI4OSwzLjEyNSwwLjg2OGwtMC43OTMsNC41ODYNCgkJCWMtMC4wNTEsMC4yOTgtMC4xNTgsMC41MDgtMC4zMjIsMC42MzJjLTAuMTY2LDAuMTI0LTAuMzg5LDAuMTg3LTAuNjcsMC4xODdjLTAuMjQ4LDAtMC41ODgtMC4wNTgtMS4wMTgtMC4xNzQNCgkJCWMtMC40My0wLjExNS0wLjk5OS0wLjE3NC0xLjcwOS0wLjE3NGMtMS4yNzMsMC0yLjM2NCwwLjM1Mi0zLjI3MywxLjA1NGMtMC45MDgsMC43MDMtMS42NzgsMS43MzEtMi4zMDUsMy4wODd2MTUuODQxSDIxNy41OTh6Ii8+DQoJCTxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0yNDguMzYxLDg4Ljc0N2MxLjYwNCwwLDMuMDc4LDAuMjU3LDQuNDI2LDAuNzY5YzEuMzQ3LDAuNTEzLDIuNTA4LDEuMjYxLDMuNDgyLDIuMjQ0DQoJCQljMC45NzYsMC45ODMsMS43MzUsMi4xODksMi4yODEsMy42MTljMC41NDUsMS40MywwLjgxOCwzLjA2MiwwLjgxOCw0Ljg5NmMwLDAuNDYzLTAuMDIxLDAuODQ3LTAuMDYyLDEuMTUyDQoJCQlzLTAuMTE2LDAuNTQ1LTAuMjIzLDAuNzE5Yy0wLjEwOCwwLjE3NC0wLjI1MywwLjI5OC0wLjQzNSwwLjM3MnMtMC40MTMsMC4xMTEtMC42OTMsMC4xMTFoLTE1LjcxOA0KCQkJYzAuMTgyLDIuNjExLDAuODg0LDQuNTI4LDIuMTA3LDUuNzUyYzEuMjIzLDEuMjIzLDIuODQzLDEuODM0LDQuODU4LDEuODM0YzAuOTkyLDAsMS44NDgtMC4xMTUsMi41NjYtMC4zNDcNCgkJCXMxLjM0Ny0wLjQ4NywxLjg4NC0wLjc2OXMxLjAwOC0wLjUzNywxLjQxMy0wLjc2OXMwLjc5Ny0wLjM0OCwxLjE3OC0wLjM0OGMwLjI0OCwwLDAuNDYzLDAuMDUsMC42NDUsMC4xNDkNCgkJCWMwLjE4MiwwLjA5OSwwLjMzOSwwLjIzOSwwLjQ3MSwwLjQyMWwxLjc4NSwyLjIzMWMtMC42NzgsMC43OTMtMS40MzgsMS40NTktMi4yOCwxLjk5NmMtMC44NDQsMC41MzctMS43MjQsMC45NjctMi42NDEsMS4yODkNCgkJCXMtMS44NTIsMC41NDktMi44MDIsMC42ODJjLTAuOTUsMC4xMzItMS44NzEsMC4xOTgtMi43NjQsMC4xOThjLTEuNzY5LDAtMy40MTMtMC4yOTQtNC45MzQtMC44OA0KCQkJYy0xLjUyMS0wLjU4Ny0yLjg0My0xLjQ1NC0zLjk2Ni0yLjYwNGMtMS4xMjUtMS4xNDgtMi4wMDktMi41NjktMi42NTMtNC4yNjRzLTAuOTY3LTMuNjU3LTAuOTY3LTUuODg4DQoJCQljMC0xLjczNSwwLjI4MS0zLjM2NywwLjg0My00Ljg5NmMwLjU2Mi0xLjUyOCwxLjM2OC0yLjg1OSwyLjQxNy0zLjk5MWMxLjA1LTEuMTMyLDIuMzMxLTIuMDI4LDMuODQzLTIuNjg5DQoJCQlDMjQ0Ljc1NSw4OS4wNzgsMjQ2LjQ2MSw4OC43NDcsMjQ4LjM2MSw4OC43NDd6IE0yNDguNDg1LDkzLjEzNmMtMS43ODQsMC0zLjE4MiwwLjUwNC00LjE4OSwxLjUxMg0KCQkJYy0xLjAwOCwxLjAwOS0xLjY1MiwyLjQzOC0xLjkzNCw0LjI4OWgxMS41MDNjMC0wLjc5NC0wLjEwNy0xLjU0MS0wLjMyMi0yLjI0NGMtMC4yMTUtMC43MDItMC41NDYtMS4zMTctMC45OTEtMS44NDcNCgkJCWMtMC40NDYtMC41MjgtMS4wMDktMC45NDUtMS42ODctMS4yNTJDMjUwLjE4OCw5My4yODgsMjQ5LjM5NSw5My4xMzYsMjQ4LjQ4NSw5My4xMzZ6Ii8+DQoJPC9nPg0KCTxwYXRoIGlkPSJJY29uIiBmaWxsPSIjRkZGRkZGIiBkPSJNMTcxLjkyNiwxOS43MDdjLTAuNTAyLTYuNjM5LTYuOTQzLTEyLjYxOC0xNC4wMjktMTMuMDZjLTE1LjA5Mi0wLjg1OS0zMC4xODQtMC44NTktNDUuMjc0LDANCgkJYy03LjA4NywwLjQ0Mi0xMy41MjksNi40MjEtMTQuMDMyLDEzLjA2MWMtMC45MDksMTMuMTI0LTAuOTA5LDI2LjI0OCwwLDM5LjM3MmMwLjUwMyw2LjY0MSw2Ljk0NSwxMi42MTgsMTQuMDMyLDEzLjA2MQ0KCQljMTUuMDkyLDAuODU4LDMwLjE4MywwLjg1OCw0NS4yNzQsMGM3LjA4Ni0wLjQ0MSwxMy41MjctNi40MiwxNC4wMjktMTMuMDYxQzE3Mi44MzUsNDUuOTU0LDE3Mi44MzUsMzIuODMsMTcxLjkyNiwxOS43MDd6DQoJCSBNMTM4Ljg0OCw1Ni43MDNoLTI0Ljc3MXYtNC42OTloMjQuNzcxVjU2LjcwM3ogTTE1NS42MzUsNTYuMTg2Yy0wLjM2NywwLjM2Ny0wLjc5NCwwLjY1NC0xLjI3OSwwLjg1OQ0KCQljLTAuNDg4LDAuMjA0LTEuMDAyLDAuMzA4LTEuNTQxLDAuMzA4Yy0wLjU0MSwwLTEuMDQ5LTAuMTA0LTEuNTIzLTAuMzA4Yy0wLjQ3Ny0wLjIwNS0wLjg5Ni0wLjQ5Mi0xLjI2NC0wLjg1OQ0KCQljLTAuMzY5LTAuMzY3LTAuNjUzLTAuNzg5LTAuODU4LTEuMjYyYy0wLjIwNi0wLjQ3OC0wLjMxLTAuOTg2LTAuMzEtMS41MjdjMC0wLjUzOSwwLjEwNC0xLjA1MywwLjMxLTEuNTM5DQoJCWMwLjIwNS0wLjQ4NiwwLjQ4OS0wLjkxMywwLjg1OC0xLjI4YzAuNzU2LTAuNzU4LDEuNjg3LTEuMTM1LDIuNzg3LTEuMTM1YzAuNTM5LDAsMS4wNTMsMC4wOTgsMS41NDEsMC4yOTMNCgkJYzAuNDg1LDAuMTk0LDAuOTEyLDAuNDc1LDEuMjc5LDAuODQyYzAuNzU2LDAuNzU3LDEuMTM1LDEuNjk2LDEuMTM1LDIuODE5QzE1Ni43Nyw1NC41LDE1Ni4zOTEsNTUuNDMxLDE1NS42MzUsNTYuMTg2eiIvPg0KPC9nPg0KPC9zdmc+DQo=" alt="Underscore">
</div>
</div>
</div>
</header>
<div class="container">
<nav class="toc">
<div class="toc-contents">
<p class="text-center">The Type Astronaut’s Guide to Shapeless</p>
<p class="text-center">Copyright 2016-17 Dave Gurnell.</p>
<p class="text-center">Published by <a href="http://underscore.io">Underscore Consulting LLP</a>, Brighton, UK.</p>
<hr>
<h1>Contents</h1>
<ul>
<li><a href="#avant-propos">Avant-propos</a></li>
<li><a href="#introduction"><span class="toc-section-number">1</span> Introduction</a><ul>
<li><a href="#la-programmation-générique-quest-ce-que-cest"><span class="toc-section-number">1.1</span> La programmation générique, qu’est-ce que c’est ?</a></li>
<li><a href="#sec:intro:about-this-book"><span class="toc-section-number">1.2</span> À propos du livre</a></li>
<li><a href="#sec:intro:source-code"><span class="toc-section-number">1.3</span> Code source et exemples</a></li>
<li><a href="#remerciements"><span class="toc-section-number">1.4</span> Remerciements</a></li>
</ul></li>
<li><a href="#sec:representations"><span class="toc-section-number">2</span> Type de données algébriques et représentation générique</a><ul>
<li><a href="#rappel-types-de-données-algébriques"><span class="toc-section-number">2.1</span> Rappel: types de données algébriques</a><ul>
<li><a href="#les-écritures-alternatives"><span class="toc-section-number">2.1.1</span> Les écritures alternatives</a></li>
</ul></li>
<li><a href="#écriture-générique-pour-les-produits"><span class="toc-section-number">2.2</span> Écriture générique pour les produits</a><ul>
<li><a href="#changer-de-représentation-en-utilisant-generic"><span class="toc-section-number">2.2.1</span> Changer de représentation en utilisant <em>Generic</em></a></li>
</ul></li>
<li><a href="#coproduit-générique"><span class="toc-section-number">2.3</span> Coproduit générique</a><ul>
<li><a href="#échanger-les-encodages-à-laide-de-generic"><span class="toc-section-number">2.3.1</span> Échanger les encodages à l’aide de <em>Generic</em></a></li>
</ul></li>
<li><a href="#résumé"><span class="toc-section-number">2.4</span> Résumé</a></li>
</ul></li>
<li><a href="#sec:generic"><span class="toc-section-number">3</span> Déduire automatiquement les instances de <em>type class</em></a><ul>
<li><a href="#sec:generic:type-classes"><span class="toc-section-number">3.1</span> Bref rappel : les type classes</a><ul>
<li><a href="#résoudre-les-instances"><span class="toc-section-number">3.1.1</span> Résoudre les instances</a></li>
<li><a href="#sec:generic:idiomatic-style"><span class="toc-section-number">3.1.2</span> Les définitions de <em>type class</em> idiomatique</a></li>
</ul></li>
<li><a href="#sec:generic:products"><span class="toc-section-number">3.2</span> Déduire des instances pour les produits</a><ul>
<li><a href="#les-instances-de-hlists"><span class="toc-section-number">3.2.1</span> Les instances de <em>HLists</em></a></li>
<li><a href="#sec:generic:product-generic"><span class="toc-section-number">3.2.2</span> Des instance pour nos produits</a></li>
<li><a href="#alors-quels-en-sont-les-inconvénients"><span class="toc-section-number">3.2.3</span> Alors quels en sont les inconvénients ?</a></li>
</ul></li>
<li><a href="#sec:generic:coproducts"><span class="toc-section-number">3.3</span> Déduire les instances pour les coproduits</a><ul>
<li><a href="#aligner-les-colonnes-dans-la-sortie-csv"><span class="toc-section-number">3.3.1</span> Aligner les colonnes dans la sortie CSV</a></li>
</ul></li>
<li><a href="#la-déduction-dinstance-pour-les-type-récursif."><span class="toc-section-number">3.4</span> La déduction d’instance pour les type récursif.</a><ul>
<li><a href="#les-divergences-dimplicits"><span class="toc-section-number">3.4.1</span> Les divergences d’implicits</a></li>
<li><a href="#lazy"><span class="toc-section-number">3.4.2</span> <em>Lazy</em></a></li>
</ul></li>
<li><a href="#sec:generic:debugging"><span class="toc-section-number">3.5</span> Débugger les résolutions d’implicites</a><ul>
<li><a href="#débugger-en-utilisant-implicitly"><span class="toc-section-number">3.5.1</span> Débugger en utilisant <em>implicitly</em></a></li>
<li><a href="#debugger-en-utilisant-reify"><span class="toc-section-number">3.5.2</span> Debugger en utilisant <em>reify</em></a></li>
</ul></li>
<li><a href="#en-résumé"><span class="toc-section-number">3.6</span> En résumé</a></li>
</ul></li>
<li><a href="#sec:type-level-programming"><span class="toc-section-number">4</span> Travailler avec les types et les implicites</a><ul>
<li><a href="#types-dépendants"><span class="toc-section-number">4.1</span> Types dépendants</a></li>
<li><a href="#sec:type-level-programming:depfun"><span class="toc-section-number">4.2</span> Fonctions à type dépendant</a></li>
<li><a href="#sec:type-level-programming:chaining"><span class="toc-section-number">4.3</span> Enchaîner les fonctions dépendantes</a></li>
<li><a href="#sec:type-level-programming:summary"><span class="toc-section-number">4.4</span> Résumé</a></li>
</ul></li>
<li><a href="#sec:labelled-generic"><span class="toc-section-number">5</span> Accéder aux noms durant la déduction d’<code>implicit</code></a><ul>
<li><a href="#types-littéreaux."><span class="toc-section-number">5.1</span> Types littéreaux.</a></li>
<li><a href="#sec:labelled-generic:type-tagging"><span class="toc-section-number">5.2</span> Le type tagging et les types fantômes</a><ul>
<li><a href="#records-et-labelledgeneric"><span class="toc-section-number">5.2.1</span> Records et <em>LabelledGeneric</em></a></li>
</ul></li>
<li><a href="#déduire-linstance-dun-produit-avec-labelledgeneric"><span class="toc-section-number">5.3</span> Déduire l’instance d’un produit avec <em>LabelledGeneric</em></a><ul>
<li><a href="#les-instances-de-hlists-1"><span class="toc-section-number">5.3.1</span> Les instances de <em>HLists</em></a></li>
<li><a href="#les-instances-pour-les-produits-concrêt."><span class="toc-section-number">5.3.2</span> Les instances pour les produits concrêt.</a></li>
</ul></li>
<li><a href="#déduire-les-instances-de-coproduits-avec-labelledgeneric"><span class="toc-section-number">5.4</span> Déduire les instances de coproduits avec <em>LabelledGeneric</em></a></li>
<li><a href="#résumé-1"><span class="toc-section-number">5.5</span> Résumé</a></li>
</ul></li>
<li><a href="#sec:ops"><span class="toc-section-number">6</span> Travailler avec <em>HLists</em> et <em>Coproducts</em></a><ul>
<li><a href="#exemple-dops-simples"><span class="toc-section-number">6.1</span> Exemple d’ops simples</a></li>
<li><a href="#sec:ops:penultimate"><span class="toc-section-number">6.2</span> Faire son propre op (le patterne “lemma”)</a></li>
<li><a href="#sec:ops:migration"><span class="toc-section-number">6.3</span> Étude de cas : migration de case class</a><ul>
<li><a href="#la-type-class"><span class="toc-section-number">6.3.1</span> La <em>type class</em></a></li>
<li><a href="#étape-1.-enlever-les-champs"><span class="toc-section-number">6.3.2</span> Étape 1. Enlever les champs</a></li>
<li><a href="#etape-2.-réordonner-les-champs"><span class="toc-section-number">6.3.3</span> Etape 2. Réordonner les champs</a></li>
<li><a href="#etape-3.-ajouter-de-nouveaux-champs"><span class="toc-section-number">6.3.4</span> Etape 3. Ajouter de nouveaux champs</a></li>
</ul></li>
<li><a href="#sec:ops:record"><span class="toc-section-number">6.4</span> Record ops</a><ul>
<li><a href="#sélectionner-les-champs"><span class="toc-section-number">6.4.1</span> Sélectionner les champs</a></li>
<li><a href="#mettre-à-jour-ou-enlever-des-champs"><span class="toc-section-number">6.4.2</span> Mettre à jour ou enlever des champs</a></li>
<li><a href="#convertir-en-une-map-conventionnelle"><span class="toc-section-number">6.4.3</span> Convertir en une <em>Map</em> conventionnelle</a></li>
<li><a href="#les-autres-opérations"><span class="toc-section-number">6.4.4</span> Les autres opérations</a></li>
</ul></li>
<li><a href="#résumé-2"><span class="toc-section-number">6.5</span> Résumé</a></li>
</ul></li>
<li><a href="#sec:poly"><span class="toc-section-number">7</span> Opération fonctionnelle sur les <em>HLists</em></a><ul>
<li><a href="#motivation-mapper-sur-une-hlist"><span class="toc-section-number">7.1</span> Motivation : mapper sur une <em>HList</em></a></li>
<li><a href="#fonctions-polymorphique"><span class="toc-section-number">7.2</span> Fonctions polymorphique</a><ul>
<li><a href="#comment-poly-fonctionne"><span class="toc-section-number">7.2.1</span> Comment <em>Poly</em> fonctionne</a></li>
<li><a href="#la-syntaxe-de-poly"><span class="toc-section-number">7.2.2</span> la syntaxe de <em>Poly</em></a></li>
</ul></li>
<li><a href="#mapping-et-flatmapping-à-laide-de-poly"><span class="toc-section-number">7.3</span> Mapping et flatMapping à l’aide de <em>Poly</em></a></li>
<li><a href="#utiliser-fold-avec-poly"><span class="toc-section-number">7.4</span> Utiliser Fold avec <em>Poly</em></a></li>
<li><a href="#sec:poly:product-mapper"><span class="toc-section-number">7.5</span> Définir une type classe utilisant <em>Poly</em></a></li>
<li><a href="#résumé-3"><span class="toc-section-number">7.6</span> Résumé</a></li>
</ul></li>
<li><a href="#sec:nat"><span class="toc-section-number">8</span> Compter avec les types</a><ul>
<li><a href="#représenter-des-nombres-par-des-types."><span class="toc-section-number">8.1</span> Représenter des nombres par des types.</a></li>
<li><a href="#la-longueur-des-représentations-génériques"><span class="toc-section-number">8.2</span> La longueur des représentations génériques</a></li>
<li><a href="#étude-de-cas-générateur-de-valeur-aléatoire"><span class="toc-section-number">8.3</span> Étude de cas: générateur de valeur aléatoire</a><ul>
<li><a href="#de-simples-valeurs-aléatoires"><span class="toc-section-number">8.3.1</span> De simples valeurs aléatoires</a></li>
<li><a href="#produits-aléatoires"><span class="toc-section-number">8.3.2</span> Produits aléatoires</a></li>
<li><a href="#coproduits-aléatoires"><span class="toc-section-number">8.3.3</span> Coproduits aléatoires</a></li>
</ul></li>
<li><a href="#les-autres-opérations-impliquant-nat"><span class="toc-section-number">8.4</span> Les autres opérations impliquant <em>Nat</em></a></li>
<li><a href="#résumé-4"><span class="toc-section-number">8.5</span> Résumé</a></li>
</ul></li>
<li><a href="#préparez-vous-au-lancement">Préparez-vous au lancement!</a></li>
</ul>
</div>
<p class="toc-toggle">
<a href="javascript:void 0" class="btn btn-default btn-block">Show cover notes and table of contents</a>
</p>
</nav>
<article>
<h1 id="avant-propos" class="unnumbered">Avant-propos</h1>
<p>Début 2011, alors que j’initiais mes travaux sur la programmation générique, qui aboutiront plus tard à <em>shapeless</em>, je n’aurais alors pas pensé que cinq ans plus tard, shapeless deviendrait une librairie autant utilisée. Je suis profondément reconnaissant envers les personnes qui ont cru en moi et qui ont ajouté shapeless à leurs dépendances. Le vote d’adhésion unanime est une source d’encouragements pour perserver dans tout projet <em>open source</em>. Je suis aussi reconnaissant envers les nombreuses personnes qui ont contribué à shapeless au fil des années, quatre-vingt-une au moment où j’écris ces lignes. Sans leur aide, shapeless serait une librairie bien moins intéressante.</p>
<p>Malgré ces points positifs, shapeless a souffert d’une carence qui caractérise les projets <em>open source</em> : le manque de documentation compréhensible, précise et accessible. La reponsabilité me revient en partie : bien que conscient de ce problème, je n’ai jamais trouvé le temps d’y remédier. Dans une certaine mesure, shapeless a été sauvé par le travail héroïque de Travis Brown sur Stack Overflow ainsi que par de nombreuses personnes qui ont organisé des conférences et des ateliers sur shapeless (notamment l’atelier <em>Shapeless for Mortals</em> de Sam Halliday).</p>
<p>Mais Dave Gurnell est parvenu à changer cela : nous disposons maintenant de ce superbe livre qui traite de manière approfondie de la partie la plus importante de shapeless : la déduction de <em>type class</em> par la programmation générique. Il a pour ainsi dire regroupé des fragments de folklore et de documentation, m’a poussé à la réflexion, et a transformé un enchevêtrement impénétrable en quelque chose de clair, concis et très concret. Avec un peu de chance, il sera capable de montrer comme j’essaie de le dire souvent qu’au fond shapeless est une librairie assez simple regroupant un ensemble de concepts tout aussi simples.</p>
<p>Merci Dave, tu nous rends à tous un grand service.</p>
<p>Miles Sabin<br />
Créateur de shapeless</p>
<h1 id="introduction"><span class="header-section-number">1</span> Introduction</h1>
<p>Ce livre est un guide d’utilisation de <a href="https://github.com/milessabin/shapeless"><em>shapeless</em></a>, une librairie de <em>programmation générique</em> en Scala. Shapeless est une vaste librairie ; plutôt que de tout couvrir, nous nous concentrerons sur quelques cas d’utilisation intéréssants, puis nous utiliserons ces derniers pour dresser un panorama des outils et patrons de conception existants.</p>
<p>Avant de commencer, disons deux mots sur la programmation générique et expliquons en quoi shapeless est intéressant pour les développeurs Scala.</p>
<h2 id="la-programmation-générique-quest-ce-que-cest"><span class="header-section-number">1.1</span> La programmation générique, qu’est-ce que c’est ?</h2>
<p>Les types sont utiles car ils sont spécifiques : ils nous aident a comprendre comment les différents morceaux de code s’imbriquent les uns aux autres, ils nous aident à éviter les bugs et nous conduisent vers une solution lorsque l’on code.</p>
<p>Pourtant, parfois, les types sont <em>trop</em> spécifiques. Il y a des situations où l’on veut pouvoir profiter des similarités entres les types pour éviter les répétitions. Considérons par exemple les définitions suivantes :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">case</span> <span class="kw">class</span> <span class="fu">Employee</span>(name: String, number: Int, manager: Boolean)
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">IceCream</span>(name: String, numCherries: Int, inCone: Boolean)</code></pre></div>
<p>Ces deux <em>case classes</em> représentent des données différentes mais elles on des points communs évidents : elles possèdent toutes deux des champs du même type. Supposons que nous voulons implémenter une opération générique, par exemple les sérialiser en un fichier CSV. En dépit des similarités, nous devons écrire une méthode de sérialisation pour chaque type :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> <span class="fu">employeeCsv</span>(e: Employee): List[String] =
List(e.<span class="fu">name</span>, e.<span class="fu">number</span>.<span class="fu">toString</span>, e.<span class="fu">manager</span>.<span class="fu">toString</span>)
<span class="kw">def</span> <span class="fu">iceCreamCsv</span>(c: IceCream): List[String] =
List(c.<span class="fu">name</span>, c.<span class="fu">numCherries</span>.<span class="fu">toString</span>, c.<span class="fu">inCone</span>.<span class="fu">toString</span>)</code></pre></div>
<p>La programmation générique consiste à venir à bout de ce genre de différences. Shapeless met a disposition un moyen pratique de convertir des types spécifiques en une représentation générique, qui sont ensuite manipulables avec un code commun.</p>
<p>Par exemple, nous pouvons utiliser le code suivant pour convertir les <code>Employee</code> et les <code>IceCream</code> en valeurs du même type. Ne vous inquiétez pas si vous ne comprenez pas encore cet exemple, ce sujet sera traité plus tard.</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless._</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> genericEmployee = Generic[Employee].<span class="fu">to</span>(<span class="fu">Employee</span>(<span class="st">"Dave"</span>, <span class="dv">123</span>, <span class="kw">false</span>))
<span class="co">// genericEmployee: shapeless.::[String,shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] = Dave :: 123 :: false :: HNil</span>
<span class="kw">val</span> genericIceCream = Generic[IceCream].<span class="fu">to</span>(<span class="fu">IceCream</span>(<span class="st">"Sundae"</span>, <span class="dv">1</span>, <span class="kw">false</span>))
<span class="co">// genericIceCream: shapeless.::[String,shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] = Sundae :: 1 :: false :: HNil</span></code></pre></div>
<p>Les deux valeurs sont maintenant du même type. Elle sont toutes les deux des listes hétérogènes (des <code>HList</code>s) contenant une <code>String</code>, un <code>Int</code>, et un <code>Boolean</code>. Nous jetterons bientôt un œil aux <code>HList</code>s et à l’importance de leur rôle. Pour l’instant, le plus intéressant est que nous pouvons sérialiser chaque valeur avec une seule fonction.</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> <span class="fu">genericCsv</span>(gen: String :: Int :: Boolean :: HNil): List[String] =
List(<span class="fu">gen</span>(<span class="dv">0</span>), <span class="fu">gen</span>(<span class="dv">1</span>).<span class="fu">toString</span>, <span class="fu">gen</span>(<span class="dv">2</span>).<span class="fu">toString</span>)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">genericCsv</span>(genericEmployee)
<span class="co">// res2: List[String] = List(Dave, 123, false)</span>
<span class="fu">genericCsv</span>(genericIceCream)
<span class="co">// res3: List[String] = List(Sundae, 1, false)</span></code></pre></div>
<p>Cet exemple est basique mais il pointe du doigt la nature de la programmation générique. Nous reformulons les problèmes pour pouvoir les résoudre avec des constructions génériques et ainsi écrire de petit bloc de code qui fonctionne avec une large variété de types. Programmer avec shapeless nous permet d’éliminer une grande quantité de code <em>boilerplate</em>, de rendre les applications Scala plus faciles à lire, écrire et maintenir.</p>
<p>Votre curiosité a été piquée ? Alors c’est parti !</p>
<h2 id="sec:intro:about-this-book"><span class="header-section-number">1.2</span> À propos du livre</h2>
<p>Le livre est divisé en deux parties.</p>
<p>La <em>Partie I</em> introduit la déduction de <em>type class</em> (<em>type class derivation</em>), notion permettant de créer des instances de <em>type class</em> pour tous les types de données algébriques à partir de quelques règles génériques uniquement. La <em>Partie I</em> comprend quatre chapitres :</p>
<ul>
<li><p>Le <em>Chapitre 2</em> introduit les <em>generic representations</em>, mais aussi la <em>type class</em> <code>Generic</code> de shapeless, qui permet de produire un encodage générique de n’importe quelle <em>case class</em> ou <em>sealed trait</em>.</p></li>
<li><p>Le <em>Chapitre 3</em> utilise <code>Generic</code> pour déduire des instances d’une <em>type class</em> particulière. On créé un exemple de <em>type class</em> pour encoder des données Scala en <em>Comma Separated Values</em> (<em>CSV</em>), mais la technique utilisée peut être adaptée à de nombreuses situations. Le type <code>Lazy</code> de shapeless est également présenté, il permet de manipuler les types de données récursives comme les listes ou les arbres.</p></li>
<li><p>Le <em>Chapitre 4</em> présente la théorie et les patrons de conception nécessaires à la généralisation des techniques du chapitre précédent. On se penchera sur les types dépendants, les fonctions à type dépendant et la programmation au <em>type level</em>. C’est l’occasion d’utiliser des applications plus avancées de shapeless.</p></li>
<li><p>Le <em>Chapitre 5</em> présente <code>LabelledGeneric</code>, une variante de <code>Generic</code> qui divulgue les champs et les noms des types dans sa représentation générique. Davantages d’éléments théoriques sont donnés sur les <em>types littéraux</em>, les <em>types singletons</em>, les <em>types fantômes</em> et les <em>type tagging</em>. <code>LabelledGeneric</code> est illustré en créant un encodeur <em>JSON</em> qui préserve les champs et les noms des types dans sa sortie.</p></li>
</ul>
<p>La <em>Partie II</em> présente les <em>ops type classes</em> fournies dans le package <code>shapeless.ops</code>. Les <em>ops type classes</em> comprennent une gamme d’outils permettant de manipuler les représentations génériques. Plutôt que d’expliquer en détails chaque <code>op</code>, une synthèse théorique est réalisée en trois chapitres :</p>
<ul>
<li><p>Le <em>Chapitre 6</em> discute d’une présentation générale des <code>ops</code> <em>type classes</em> et fournit un exemple qui regroupe plusieurs <code>ops</code> pour former un puissant outil de « migration de case class ».</p></li>
<li><p>Le <em>Chapitre 7</em> présente <em>les fonctions polymorphiques</em>, également connues sous le nom de <code>Polys</code>, et montre comment les utiliser dans les <code>ops</code> <em>type classes</em> pour <em>mapper</em>, <em>flat mapper</em> et <em>folder</em> les représentations génériques.</p></li>
<li><p>Enfin, le Chapitre 8 présente le type <code>Nat</code> que shapeless utilise pour représenter les nombres naturels au <em>type level</em>. Plusieurs <code>ops</code> <em>type classes</em> associés sont présentés, et <code>Nat</code> est utilisé pour développer notre propre version de <code>Arbitrary</code> de <em>Scalacheck</em>.</p></li>
</ul>
<h2 id="sec:intro:source-code"><span class="header-section-number">1.3</span> Code source et exemples</h2>
<p>Ce livre est <em>open source</em>. Vous pouvez trouver <a href="https://github.com/underscoreio/shapeless-guide">les sources Markdown sur GitHub</a>. La communauté met constamment à jour ce livre, veillez donc à vérifier sur le dépôt GitHub que vous disposez de la dernière version.</p>
<p>Une copie du livre est également maintenue sur <a href="https://underscore.io/books/shapeless-guide">le site <em>web</em> Underscore</a>. En récupérant votre copie sur ce site, vous pourrez être également prévenus de la sortie d’une mise à jour.</p>
<p>Il y existe aussi des implémentations complètes des exemples principaux dans un <a href="https://github.com/underscoreio/shapeless-guide-code">dépôt annexe</a>. Consultez le README pour plus de détails sur l’installation. Les exemples utilisent <em>shapeless 2.3.2</em> et <em>Typelevel Scala 2.11.8+</em> ou <em>Lightbend Scala 2.11.9+ / 2.12.1+</em>.</p>
<p>La plupart des exemples de ce livre ont été compilés et exécutés avec la version 2.12.1 du compilateur <em>Typelevel Scala</em>. Entre autres, cette version de Scala dispose de l’impression de <em>type infix</em>, avec une sortie du <em>REPL</em> dans la console plus claire :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> repr = <span class="st">"Hello"</span> :: <span class="dv">123</span> :: <span class="kw">true</span> :: HNil
<span class="co">// repr: shapeless.::[String,shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] = Hello :: 123 :: true :: HNil</span></code></pre></div>
<p>Si vous utilisez une version antérieure de Scala vous devrez utiliser l’impression de <em>type prefix</em> ainsi :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> repr = <span class="st">"Hello"</span> :: <span class="dv">123</span> :: <span class="kw">true</span> :: HNil
<span class="co">// repr: shapeless.::[String,shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]] = "Hello" :: 123 :: true :: HNil</span></code></pre></div>
<p>Pas de panique ! Mise à part la manière d’afficher le résultat (syntaxe <em>infix</em> contre <em>prefix</em>), ces types sont les mêmes. Si vous trouvez les <em>prefix types</em> difficiles à lire, nous vous recommendons de mettre à jour Scala. Ajoutez simplement ceci au fichier <code>build.sbt</code>, ou remplacez le numéro de version de manière appropriée :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">scalaOrganization := <span class="st">"org.typelevel"</span>
scalaVersion := <span class="st">"2.12.1"</span></code></pre></div>
<p>Le paramètre <code>scalaOrganization</code> n’est supporté que dans <em>sbt 0.13.13</em> ou supérieur. Vous pouvez spécifier une version <em>sbt</em> en écrivant ceci dans <code>project/build.properties</code> (crééz le fichier si il n’est pas déjà dans votre projet) :</p>
<pre><code>sbt.version=0.13.13</code></pre>
<h2 id="remerciements"><span class="header-section-number">1.4</span> Remerciements</h2>
<p>Je remercie Miles Sabin, Richard Dallaway, Noel Welsh et Travis Brown pour leur contribution inestimable.</p>
<p>Je remercie tout particulièrement à Sam Halliday pour son excellent atelier <a href="http://fommil.com/scalax15/"><em>Shapeless for Mortals</em></a>, qui a inspiré et structuré le présent exposé, et Rob Norris et ses contributeurs pour le très pratique <a href="https://github.com/tpolecat/tut">Tut</a>, qui s’assure les exemples du livre compilent correctement.</p>
<p>Si vous constatez qu’il y a des erreurs ou si vous voyez des améliorations potentielles, n’hésitez pas à remonter une <em>issue</em> ou à nous soumettre une <em>pull request</em> sur la <a href="https://github.com/underscoreio/shapeless-guide">page GitHub</a>.</p>
<h1 id="sec:representations"><span class="header-section-number">2</span> Type de données algébriques et représentation générique</h1>
<p>La programmation générique a pour objectif principal de résoudre des problèmes pour une grande variété de types en utilisant un minimum de code générique. Shapeless fournit deux ensembles d’outils dans ce but :</p>
<ol style="list-style-type: decimal">
<li><p>Un ensemble de types de donnée générique qui peuvent être inspectés, itérés et manipulés au <code>type-level</code></p></li>
<li><p>Le mapping automatique entre <em>algebraic data types (</em>ADT<em>s)</em> (encodé en Scala par les <em>case classes</em> et les <em>sealed traits</em>) et leurs représentations génériques.</p></li>
</ol>
<p>Dans ce chapitre, nous commençons par un récapitulatif sur la théorie des types alébriques et la raison pour laquelle ils peuvent être familiers pour le développeur Scala. Puis, nous verrons les représentations génériques utilisées par shapeless et nous traiterons de la façon dont ils sont reliés aux <em>ADT</em>s concrets. Enfin, nous présenterons une type class appelée <code>Generic</code> qui fournit un mapping automatique bidirectionnel entre un <em>ADT</em> et sa représentation générique. Enfin, nous utiliserons <code>Generic</code> dans quelques exemples pour convertir des valeurs d’un type vers un autre.</p>
<h2 id="rappel-types-de-données-algébriques"><span class="header-section-number">2.1</span> Rappel: types de données algébriques</h2>
<p><em>Algebraic data types (</em>ADT<em>s)</em><a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> est un nom raffiné qui cache un concept très simple. C’est un moyen idiomatique de représenter une donnée en utilisant les « et » et « ou » logiques. Par exemple :</p>
<ul>
<li>une forme est un rectangle <strong>ou</strong> un cercle</li>
<li>un rectangle a une largeur <strong>et</strong> une hauteur</li>
<li>un cercle a un rayon</li>
</ul>
<p>Dans la terminologie des <em>ADT</em>s, les types « et » comme le rectangle et le cercle sont appelés <em>products (produits)</em>, les types « ou » comme le type forme sont appelés <em>coproducts (coproduits)</em>. En Scala, nous représentons typiquement les produits par des case class et les coproduits par des sealed traits :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">sealed</span> <span class="kw">trait</span> Shape
<span class="kw">final</span> <span class="kw">case</span> <span class="kw">class</span> Rectangle(width: Double, height: Double) <span class="kw">extends</span> Shape
<span class="kw">final</span> <span class="kw">case</span> <span class="kw">class</span> <span class="fu">Circle</span>(radius: Double) <span class="kw">extends</span> Shape
<span class="kw">val</span> rect: Shape = Rectangle(<span class="fl">3.0</span>, <span class="fl">4.0</span>)
<span class="kw">val</span> circ: Shape = <span class="fu">Circle</span>(<span class="fl">1.0</span>)</code></pre></div>
<p>Ce qui est beau avec les <em>ADT</em>s, c’est qu’ils sont complètement type safe. Le compilateur a une connaisence complète de l’algèbre<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a> que nous définissons, il peut donc nous aider à écrire des méthodes correctement typées avec nos types.</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> <span class="fu">area</span>(shape: Shape): Double =
shape <span class="kw">match</span> {
<span class="kw">case</span> Rectangle(w, h) => w * h
<span class="kw">case</span> <span class="fu">Circle</span>(r) => math.<span class="fu">Pi</span> * r * r
}</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">area</span>(rect)
<span class="co">// res1: Double = 12.0</span>
<span class="fu">area</span>(circ)
<span class="co">// res2: Double = 3.141592653589793</span></code></pre></div>
<h3 id="les-écritures-alternatives"><span class="header-section-number">2.1.1</span> Les écritures alternatives</h3>
<p>Les sealed traits et les <em>case classes</em> sont sans aucun doute les encodages les plus pratique des <em>ADT</em>s en Scala. Mais ce ne sont pas les <em>seules</em> possibilités d’encodage. Par exemple, la librairie standard de Scala fournit des produits génériques appelés <code>Tuples</code> ainsi qu’un coproduit générique : <code>Either</code>. Nous aurions pu choisir d’écrire notre <code>Shape</code> comme suit :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">type</span> Rectangle2 = (Double, Double)
<span class="kw">type</span> Circle2 = Double
<span class="kw">type</span> Shape2 = Either[Rectangle2, Circle2]
<span class="kw">val</span> rect2: Shape2 = <span class="fu">Left</span>((<span class="fl">3.0</span>, <span class="fl">4.0</span>))
<span class="kw">val</span> circ2: Shape2 = <span class="fu">Right</span>(<span class="fl">1.0</span>)</code></pre></div>
<p>Bien que cette écriture soit moins lisible que la précédente avec des case class, elle dispose de certaines des propriétés requises. Nous pouvons toujours écrire du code type safe avec <code>Shape2</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> <span class="fu">area2</span>(shape: Shape2): Double =
shape <span class="kw">match</span> {
<span class="kw">case</span> <span class="fu">Left</span>((w, h)) => w * h
<span class="kw">case</span> <span class="fu">Right</span>(r) => math.<span class="fu">Pi</span> * r * r
}</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">area2</span>(rect2)
<span class="co">// res4: Double = 12.0</span>
<span class="fu">area2</span>(circ2)
<span class="co">// res5: Double = 3.141592653589793</span></code></pre></div>
<p>Il est important de noter que <code>Shape2</code> est une écriture plus <em>générique</em> que <code>Shape</code><a href="#fn3" class="footnoteRef" id="fnref3"><sup>3</sup></a>. Tout code qui fonctionne avec une paire de <code>Doubles</code> fonctionnera avec <code>Rectangle2</code> et vice versa. En tant que développeur Scala nous avons tendance à préférer les types sémantiques comme <code>Rectangle</code> et <code>Circle</code> aux types génériques tels que <code>Rectangle2</code> et <code>Circle2</code>, précisément à cause de leur nature spécialisée. Toutefois, dans certain cas, la généralité est préférable. Par exemple, si l’on sérialise des données sur un disque, nous ne nous soucions pas des différences entre une paire de <code>Doubles</code> et un <code>Rectangle2</code>. On écrit seulement les nombres et rien d’autre.</p>
<p>Shapeless nous donne le meilleur des deux mondes ; nous pouvons utiliser les types sémantiques par défaut et passer aux représentations génériques lorsque le besoin d’interopérabilité se fait sentir (nous y reviendrons).</p>
<p>En revanche, au lieu d’utiliser <code>Tuples</code> et <code>Either</code>, shapeless utilise son propre type de données pour représenter les produits et coproduits génériques. Nous présenterons ces types dans la section suivante.</p>
<h2 id="écriture-générique-pour-les-produits"><span class="header-section-number">2.2</span> Écriture générique pour les produits</h2>
<p>Dans la section précédente, nous avons présenté les <em>tuples</em> comme une représentation générique des produits. Malheureusement, les <em>tuples</em> présentent deux inconvénients qui les rendent inappropriés aux besoins de shapeless.</p>
<ol style="list-style-type: decimal">
<li><p>Chaque taille de tuple est dotée d’un type différent, ces types sont indépendants les uns des autres, ce qui rend difficile l’écriture de code qui fait abstraction de la taille des produits.</p></li>
<li><p>Il n’existe pas de <em>tuples</em> de taille zero, qui sont pourtant importants pour représenter les produits sans champ. On pourrait utiliser <code>Unit</code>, mais on souhaite que chaque représentation générique ait un supertype commun et tangible. Le plus petit ancêtre commun à <code>Unit</code> et <code>Tuple2</code> est <code>Any</code>, une combinaison des deux est donc impensable.</p></li>
</ol>
<p>C’est pourquoi shapeless utilise un encodage générique différent pour les produits : <em>heterogeneous lists</em> ou <code>HList</code>s<a href="#fn4" class="footnoteRef" id="fnref4"><sup>4</sup></a>.</p>
<p>La <code>HList</code> est soit une liste vide <code>HNil</code>, soit une paire <code>::[H, T]</code> où <code>H</code> est un type arbitraire et <code>T</code> une autre <code>HList</code>. Parce que chaque <code>::</code> a son propre <code>H</code> et <code>T</code>, le type de chaque élément est encodé séparément dans le type de la liste global:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.{HList, ::, HNil}
<span class="kw">val</span> product: String :: Int :: Boolean :: HNil =
<span class="st">"Sunday"</span> :: <span class="dv">1</span> :: <span class="kw">false</span> :: HNil</code></pre></div>
<p>Le type et la valeur de la <code>HList</code> ci-dessus se reflètent. Les deux représentent les 3 membres : une <code>String</code>, un <code>Int</code>, et un <code>Boolean</code>. On peut y retrouver la <code>tête</code> et la <code>queue</code>, et le type des éléments y est préservé :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> first = product.<span class="fu">head</span>
<span class="co">// first: String = Sunday</span>
<span class="kw">val</span> second = product.<span class="fu">tail</span>.<span class="fu">head</span>
<span class="co">// second: Int = 1</span>
<span class="kw">val</span> rest = product.<span class="fu">tail</span>.<span class="fu">tail</span>
<span class="co">// rest: shapeless.::[Boolean,shapeless.HNil] = false :: HNil</span></code></pre></div>
<p>Le compilateur connaît la taille exacte de chaque <code>HList</code>, cela devient donc une erreur de compilation de demander la <code>tête</code> ou la <code>queue</code> d’une liste vide :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">product.<span class="fu">tail</span>.<span class="fu">tail</span>.<span class="fu">tail</span>.<span class="fu">head</span>
<span class="co">// <console>:15: error: could not find implicit value for parameter c: shapeless.ops.hlist.IsHCons[shapeless.HNil]</span>
<span class="co">// product.tail.tail.tail.head</span>
<span class="co">// ^</span></code></pre></div>
<p>En plus de pouvoir inspecter et itérer sur les <code>HList</code>s, on peut les manipuler et les transformer. Par exemple, on peut ajouter un élément avec la méthode <code>::</code>. Encore une fois, notez comme le type du résultat reflète le nombre des éléments de la liste.</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> newProduct: Long :: String :: Int :: Boolean :: HNil =
42L :: product</code></pre></div>
<p>Shapeless fournit aussi des outils pour effectuer des opérations plus complexes comme un mapping, un filtrage ou une concaténation de listes. On abordera cela plus en détails dans la <em>Partie II</em>.</p>
<p>Les propriétés que l’on obtient avec <code>HList</code>s ne sont pas magiques. On aurait pu obtenir ces fonctionalités en utilisant <code>(A, B)</code> et <code>Unit</code> comme alternative à <code>::</code> et <code>HNil</code>. Néanmoins, il existe un avantage à garder nos types génériques séparés de nos types sémantiques dans les applications. <code>HList</code> fournit cette séparation.</p>
<h3 id="changer-de-représentation-en-utilisant-generic"><span class="header-section-number">2.2.1</span> Changer de représentation en utilisant <em>Generic</em></h3>
<p>Shapeless fournit une type class appelée <code>Generic</code> qui permet de convertir des <em>ADT</em> concrets en représentation générique et vice versa. Il y a quelques macros en coulisses qui permettent d’invoquer des instances de <code>Generic</code> sans code <em>boilerplate</em> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.<span class="fu">Generic</span>
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">IceCream</span>(name: String, numCherries: Int, inCone: Boolean)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> iceCreamGen = Generic[IceCream]
<span class="co">// iceCreamGen: shapeless.Generic[IceCream]{type Repr = shapeless.::[String,shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]]} = anon$macro$4$1@2db79572</span></code></pre></div>
<p>Notez que les instance de <code>Generic</code> ont un membre de type <code>Repr</code> qui contient le type de sa représentation générique. Dans notre cas <code>iceCreamGen.Repr</code> est <code>String :: Int :: Boolean :: HNil</code>. Les instances de <code>Generic</code> disposent de deux méthodes : Une pour convertir vers le type <code>Repr</code> appelé <code>to</code> et la méthode inverse <code>from</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> iceCream = <span class="fu">IceCream</span>(<span class="st">"Sundae"</span>, <span class="dv">1</span>, <span class="kw">false</span>)
<span class="co">// iceCream: IceCream = IceCream(Sundae,1,false)</span>
<span class="kw">val</span> repr = iceCreamGen.<span class="fu">to</span>(iceCream)
<span class="co">// repr: iceCreamGen.Repr = Sundae :: 1 :: false :: HNil</span>
<span class="kw">val</span> iceCream2 = iceCreamGen.<span class="fu">from</span>(repr)
<span class="co">// iceCream2: IceCream = IceCream(Sundae,1,false)</span></code></pre></div>
<p>On peut convertir de l’un vers l’autre deux <em>ADT</em>s qui ont le même <code>Repr</code> en utilisant leurs <code>Generics</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">case</span> <span class="kw">class</span> <span class="fu">Employee</span>(name: String, number: Int, manager: Boolean)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="co">// Create an employee from an ice cream:</span>
<span class="kw">val</span> employee = Generic[Employee].<span class="fu">from</span>(Generic[IceCream].<span class="fu">to</span>(iceCream))
<span class="co">// employee: Employee = Employee(Sundae,1,false)</span></code></pre></div>
<div class="callout callout-info">
<p><em>Les autres types de produits</em></p>
<p>Il vaut la peine de souligner que les <em>tuples Scala</em> sont des <em>case classes</em>, donc <code>Generic</code> fonctionne très bien avec :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> tupleGen = Generic[(String, Int, Boolean)]
tupleGen.<span class="fu">to</span>((<span class="st">"Hello"</span>, <span class="dv">123</span>, <span class="kw">true</span>))
<span class="co">// res4: tupleGen.Repr = Hello :: 123 :: true :: HNil</span>
tupleGen.<span class="fu">from</span>(<span class="st">"Hello"</span> :: <span class="dv">123</span> :: <span class="kw">true</span> :: HNil)
<span class="co">// res5: (String, Int, Boolean) = (Hello,123,true)</span></code></pre></div>
<p>Cela marche aussi avec les <em>case classes</em> de plus de 22 champs:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">case</span> <span class="kw">class</span> <span class="fu">BigData</span>(
a:Int,b:Int,c:Int,d:Int,e:Int,f:Int,g:Int,h:Int,i:Int,j:Int,
k:Int,l:Int,m:Int,n:Int,o:Int,p:Int,q:Int,r:Int,s:Int,t:Int,
u:Int,v:Int,w:Int)
Generic[BigData].<span class="fu">from</span>(Generic[BigData].<span class="fu">to</span>(<span class="fu">BigData</span>(
<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>,<span class="dv">9</span>,<span class="dv">10</span>,<span class="dv">11</span>,<span class="dv">12</span>,<span class="dv">13</span>,<span class="dv">14</span>,<span class="dv">15</span>,<span class="dv">16</span>,<span class="dv">17</span>,<span class="dv">18</span>,<span class="dv">19</span>,<span class="dv">20</span>,<span class="dv">21</span>,<span class="dv">22</span>,<span class="dv">23</span>)))
<span class="co">// res6: BigData = BigData(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)</span></code></pre></div>
</div>
<h2 id="coproduit-générique"><span class="header-section-number">2.3</span> Coproduit générique</h2>
<p>Maintenant que nous savons comment Shapeless encode les types produit, qu’en est-il des coproduits ? Précédemment, nous avons abordé le <code>Either</code>, mais il souffre des mêmes inconvénients que les <em>tuples</em>. Encore une fois, shapeless fournit son propre encodage, similaire au <code>HList</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.{Coproduct, :+:, CNil, Inl, Inr}
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">Red</span>()
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">Amber</span>()
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">Green</span>()
<span class="kw">type</span> Light = Red :+: Amber :+: Green :+: CNil</code></pre></div>
<p>En général, les coproduits prennent la forme de <code>A :+: B :+: C :+: CNil</code> signifiant « A ou B ou C, » où <code>:+:</code> peut être librement interprété comme <code>Either</code>. Globalement, le type d’un coproduit encode tous les types possibles d’une disjonction, mais ces instances contiennent uniquement la valeur de l’une des possibilités. <code>:+:</code> dispose de deux sous types, <code>Inl</code> et <code>Inr</code>, qui correspondent vagument à <code>Left</code> et <code>Right</code>. On crée des instances de coproduit en imbriquant des constructeurs de <code>Inl</code> et de <code>Inr</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> red: Light = <span class="fu">Inl</span>(<span class="fu">Red</span>())
<span class="co">// red: Light = Inl(Red())</span>
<span class="kw">val</span> green: Light = <span class="fu">Inr</span>(<span class="fu">Inr</span>(<span class="fu">Inl</span>(<span class="fu">Green</span>())))
<span class="co">// green: Light = Inr(Inr(Inl(Green())))</span></code></pre></div>
<p>Chaque type de coproduit se termine par <code>CNil</code>, qui est un type inhabité (sans valeur), similaire à <code>Nothing</code>. On ne peut donc pas instancier <code>CNil</code> ou construire un <code>Coproduct</code> uniquement à partir d’instance de <code>Inr</code>. Il y a toujours exactement un <code>Inl</code> dans chaque valeur de coproduit.</p>
<p>Encore une fois, il convient de signaler que <code>Coproduct</code>s n’a rien de spécial. La fonctionnalité du dessus peut être obtenue en utilisant <code>Either</code> et <code>Nothing</code> à la place de <code>:+:</code> et <code>CNil</code>. Utiliser <code>Nothing</code> induit des difficultés techniques, mais on aurait pu utiliser n’importe quel autre type inhabité ou type singleton à la place de <code>CNil</code>.</p>
<h3 id="échanger-les-encodages-à-laide-de-generic"><span class="header-section-number">2.3.1</span> Échanger les encodages à l’aide de <em>Generic</em></h3>
<p>À première vue, les <code>Coproduct</code> sont difficiles à parser. Cependant, nous voyons comment ils s’intègrent dans le contexte plus large des écritures génériques. En plus de comprendre les <em>case classes</em> et les <em>case objects</em>, <code>Generic</code> de shapeless comprend également les <em>sealed traits</em> et les classes abstraites :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.<span class="fu">Generic</span>
<span class="kw">sealed</span> <span class="kw">trait</span> Shape
<span class="kw">final</span> <span class="kw">case</span> <span class="kw">class</span> Rectangle(width: Double, height: Double) <span class="kw">extends</span> Shape
<span class="kw">final</span> <span class="kw">case</span> <span class="kw">class</span> <span class="fu">Circle</span>(radius: Double) <span class="kw">extends</span> Shape</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> gen = Generic[Shape]
<span class="co">// gen: shapeless.Generic[Shape]{type Repr = shapeless.:+:[Rectangle,shapeless.:+:[Circle,shapeless.CNil]]} = anon$macro$1$1@1d254277</span></code></pre></div>
<p>Le <code>Repr</code> du <code>Generic</code> de <code>Shape</code> est un coproduit des sous-types de <code>Shape</code>: <code>Rectangle :+: Circle :+: CNil</code>. On peut utiliser les méthodes <code>to</code> et <code>from</code> de l’instance de <code>Generic</code> pour convertir <code>Shape</code> en <code>gen.Repr</code> et vice versa :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">gen.<span class="fu">to</span>(Rectangle(<span class="fl">3.0</span>, <span class="fl">4.0</span>))
<span class="co">// res3: gen.Repr = Inl(Rectangle(3.0,4.0))</span>
gen.<span class="fu">to</span>(<span class="fu">Circle</span>(<span class="fl">1.0</span>))
<span class="co">// res4: gen.Repr = Inr(Inl(Circle(1.0)))</span></code></pre></div>
<h2 id="résumé"><span class="header-section-number">2.4</span> Résumé</h2>
<p>Dans ce chapitre, nous avons abordé les représentations génériques que Shapeless fournit pour les types de données algébriques de Scala. <code>HList</code>s pour les types produits et <code>Coproduct</code>s pour les types coproduits. Nous avons aussi présenté la <em>type class</em> <code>Generic</code> qui fournit mapping bidirectionnel entre un <em>ADT</em> et sa représentation générique. Nous n’avons pas encore abordé ce qui rend les écritures génériques si attractives. Le cas d’utilisation que nous avons couvert (conversion entre <em>ADT</em>s) est amusant mais pas particulièrement utile.</p>
<p>La vraie puissance de <code>HList</code>s et de <code>Coproduct</code>s provient de leur structure récursive. On peut écrire du code qui traverse leur représentation et calcule des valeurs à partir des éléments qui les constituent. Dans le prochain chapitre nous verrons notre premier véritable cas d’utilisation : la déduction automatique d’instance de <em>type class</em>es.</p>
<h1 id="sec:generic"><span class="header-section-number">3</span> Déduire automatiquement les instances de <em>type class</em></h1>
<p>Dans le dernier chapitre, nous avons vu comment le type <code>Generic</code> nous permet de convertir toute instance d’un <em>ADT</em> en un encodage générique composé de <code>HList</code>s et <code>Coproduct</code>s. Dans ce chapitre, nous verrons notre premier véritable cas d’utilisation : la déduction automatique d’instances de <em>type class</em>.</p>
<h2 id="sec:generic:type-classes"><span class="header-section-number">3.1</span> Bref rappel : les type classes</h2>
<p>Avant d’entrer dans les détails de la déduction d’instance, faisons un bref rappel des aspects importants des <em>types classes</em>.</p>
<p>Les type classes sont un pattern de programmation emprunté à <em>Haskell</em> (le mot « classe » n’a rien a voir avec les classes de la programmation orientée object). Nous les écrivons en Scala avec des traits et des implicites. Une <em>type class</em> est un trait paramétré représentant une fonctionalité générale que l’on voudrait appliquer à une grande variété de types :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="co">// Turn a value of type A into a row of cells in a CSV file:</span>
<span class="kw">trait</span> CsvEncoder[A] {
<span class="kw">def</span> <span class="fu">encode</span>(value: A): List[String]
}</code></pre></div>
<p>On implémente notre type class avec une <em>instance</em> pour chaque type visé. Si nous voulons avoir l’instance dans le scope automatiquement, on peut les placer dans l’objet compagnon de la <em>type class</em>. Sinon, on peut les placer dans une objet séparé qui fera office de bibliothèque et que l’utilisateur pourra importer manuellement :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="co">// Custom data type:</span>
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">Employee</span>(name: String, number: Int, manager: Boolean)
<span class="co">// CsvEncoder instance for the custom data type:</span>
<span class="kw">implicit</span> <span class="kw">val</span> employeeEncoder: CsvEncoder[Employee] =
<span class="kw">new</span> CsvEncoder[Employee] {
<span class="kw">def</span> <span class="fu">encode</span>(e: Employee): List[String] =
List(
e.<span class="fu">name</span>,
e.<span class="fu">number</span>.<span class="fu">toString</span>,
<span class="kw">if</span>(e.<span class="fu">manager</span>) <span class="st">"yes"</span> <span class="kw">else</span> <span class="st">"no"</span>
)
}</code></pre></div>
<p>On marque chaque instance avec le mot clé <code>implicit</code>, et on définit une ou plusieurs méthodes qui acceptent le paramètre implicite du type de notre type class, elles feront office de point d’entrée :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> writeCsv[A](values: List[A])(<span class="kw">implicit</span> enc: CsvEncoder[A]): String =
values.<span class="fu">map</span>(value => enc.<span class="fu">encode</span>(value).<span class="fu">mkString</span>(<span class="st">","</span>)).<span class="fu">mkString</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span>)</code></pre></div>
<p>Testons <code>writeCsv</code> avec quelques données de test :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> employees: List[Employee] = List(
<span class="fu">Employee</span>(<span class="st">"Bill"</span>, <span class="dv">1</span>, <span class="kw">true</span>),
<span class="fu">Employee</span>(<span class="st">"Peter"</span>, <span class="dv">2</span>, <span class="kw">false</span>),
<span class="fu">Employee</span>(<span class="st">"Milton"</span>, <span class="dv">3</span>, <span class="kw">false</span>)
)</code></pre></div>
<p>Quand on appelle <code>writeCsv</code>, le compilateur calcule la valeur du paramètre de type et cherche un implicite de <code>CsvEncoder</code> du type correspondant :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(employees)
<span class="co">// res4: String =</span>
<span class="co">// Bill,1,yes</span>
<span class="co">// Peter,2,no</span>
<span class="co">// Milton,3,no</span></code></pre></div>
<p>On peut utiliser <code>writeCsv</code> avec nimporte quel type de donnée, du moment que l’on a dans le scope l’implicite de <code>CsvEncoder</code> correspondant :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">case</span> <span class="kw">class</span> <span class="fu">IceCream</span>(name: String, numCherries: Int, inCone: Boolean)
<span class="kw">implicit</span> <span class="kw">val</span> iceCreamEncoder: CsvEncoder[IceCream] =
<span class="kw">new</span> CsvEncoder[IceCream] {
<span class="kw">def</span> <span class="fu">encode</span>(i: IceCream): List[String] =
List(
i.<span class="fu">name</span>,
i.<span class="fu">numCherries</span>.<span class="fu">toString</span>,
<span class="kw">if</span>(i.<span class="fu">inCone</span>) <span class="st">"yes"</span> <span class="kw">else</span> <span class="st">"no"</span>
)
}
<span class="kw">val</span> iceCreams: List[IceCream] = List(
<span class="fu">IceCream</span>(<span class="st">"Sundae"</span>, <span class="dv">1</span>, <span class="kw">false</span>),
<span class="fu">IceCream</span>(<span class="st">"Cornetto"</span>, <span class="dv">0</span>, <span class="kw">true</span>),
<span class="fu">IceCream</span>(<span class="st">"Banana Split"</span>, <span class="dv">0</span>, <span class="kw">false</span>)
)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(iceCreams)
<span class="co">// res7: String =</span>
<span class="co">// Sundae,1,no</span>
<span class="co">// Cornetto,0,yes</span>
<span class="co">// Banana Split,0,no</span></code></pre></div>
<h3 id="résoudre-les-instances"><span class="header-section-number">3.1.1</span> Résoudre les instances</h3>
<p>Les <em>types classes</em> sont très flexibles mais elles nous imposent de définir une instance pour chaque type qui nous intéresse. Heureusement, le compilateur de Scala a plus d’un tour dans son sac, si on lui donne certaines regles, il est capable de résoudre les instances pour nous.<br />
Par exemple, on peut ecrire une règle qui créé un <code>CsvEncoder</code> pour <code>(A, B)</code> pour un <code>CsvEncoder</code> pour <code>A</code> et un pour <code>B</code> donnés :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> pairEncoder[A, B](
<span class="kw">implicit</span>
aEncoder: CsvEncoder[A],
bEncoder: CsvEncoder[B]
): CsvEncoder[(A, B)] =
<span class="kw">new</span> CsvEncoder[(A, B)] {
<span class="kw">def</span> <span class="fu">encode</span>(pair: (A, B)): List[String] = {
<span class="kw">val</span> (a, b) = pair
aEncoder.<span class="fu">encode</span>(a) ++ bEncoder.<span class="fu">encode</span>(b)
}
}</code></pre></div>
<p>Quand tous les paramètres d’un <code>implicit def</code> sont eux meme marquer <code>implicit</code>, alors le compilateur peut l’utiliser comme une règle de résolution pour crée des instance a partire d’autres instances. Par exemple, si l’on appel <code>writeCsv</code> et qu’on lui passe une <code>List[(Employee, IceCream)]</code>, le compilateur est capable de combiner <code>pairEncoder</code>, <code>employeeEncoder</code> et <code>iceCreamEncoder</code> pour produire le <code>CsvEncoder[(Employee, IceCream)]</code> requis:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(employees zip iceCreams)
<span class="co">// res8: String =</span>
<span class="co">// Bill,1,yes,Sundae,1,no</span>
<span class="co">// Peter,2,no,Cornetto,0,yes</span>
<span class="co">// Milton,3,no,Banana Split,0,no</span></code></pre></div>
<p>À partir d’une liste de règles écrites à partir d’ <code>implicit val</code>s et d’<code>implicit def</code>s, le compilateur est capable de <em>rechercher</em> les combinaisons pour retourner l’instance requise.</p>
<p>Cette fonctionalité, connue sous le nom de <em>résolution d’<code>implicit</code>s</em>, est ce qui rend le pattern des <em>types classes</em> si puissant en Scala.</p>
<p>Même avec cette puissance, le compilateur ne peut démanteler nos <em>case classes</em> et <em>sealed traits</em>. On est tenu de définir à la main les instances de nos <em>ADT</em>s. Les représentations génériques de shapeless changent la donne, car ils nous permettent de déduire automatiquement les instances de nimporte quel <em>ADT</em>.</p>
<h3 id="sec:generic:idiomatic-style"><span class="header-section-number">3.1.2</span> Les définitions de <em>type class</em> idiomatique</h3>
<p>Le style généralement accépter pour la définition d’une type classe idiomatique Il est généralement accépte d’inclure un objet compagon contenant certaines methode standar lors de la définition d’une type classe idiomatique :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">object</span> CsvEncoder {
<span class="co">// "Summoner" method</span>
<span class="kw">def</span> apply[A](<span class="kw">implicit</span> enc: CsvEncoder[A]): CsvEncoder[A] =
enc
<span class="co">// "Constructor" method</span>
<span class="kw">def</span> instance[A](func: A => List[String]): CsvEncoder[A] =
<span class="kw">new</span> CsvEncoder[A] {
<span class="kw">def</span> <span class="fu">encode</span>(value: A): List[String] =
<span class="fu">func</span>(value)
}
<span class="co">// Globally visible type class instances</span>
}</code></pre></div>
<p>La methode <code>apply</code> connue sous le nom de <em>summoner</em> ou <em>materializer</em>, nous permet d’invoquer une instance de <em>type class</em> selon un type donnée:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[IceCream]
<span class="co">// res9: CsvEncoder[IceCream] = $anon$1@1ab6e866</span></code></pre></div>
<p>Dans les cas les plus simple le <em>summoner</em> fait la meme chose que la méhode <code>implicitly</code> définie dans <code>scala.Predef</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">implicitly[CsvEncoder[IceCream]]
<span class="co">// res10: CsvEncoder[IceCream] = $anon$1@1ab6e866</span></code></pre></div>
<p>Cependant, comme nous le verrons dans la section 4.2, lors que l’on travaille avec shapeless il arrive que la methode <code>implicitly</code> n’infère pas les types correctement. On peut toujours définir une methode <em>summoner</em> pour avoir le bon comportement, donc cela vaut le coup d’en écrire une pour chaque <em>type class</em> que l’on créé. On peut aussi utiliser une methode de shapeless appelée “<code>the</code>” (nous y reviendrons):</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless._</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">the[CsvEncoder[IceCream]]
<span class="co">// res11: CsvEncoder[IceCream] = $anon$1@1ab6e866</span></code></pre></div>
<p>La methode <code>instance</code> parfois appelé <code>pure</code>, fournis une syntaxe simple pour crée de nouvelle instance de <em>type class</em>e, réduisant au passage le code <em>boilerplate</em> pour les classes anoymes:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">val</span> booleanEncoder: CsvEncoder[Boolean] =
<span class="kw">new</span> CsvEncoder[Boolean] {
<span class="kw">def</span> <span class="fu">encode</span>(b: Boolean): List[String] =
<span class="kw">if</span>(b) List(<span class="st">"yes"</span>) <span class="kw">else</span> List(<span class="st">"no"</span>)
}</code></pre></div>
<p>Est réduit en:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">val</span> booleanEncoder: CsvEncoder[Boolean] =
<span class="fu">instance</span>(b => <span class="kw">if</span>(b) List(<span class="st">"yes"</span>) <span class="kw">else</span> List(<span class="st">"no"</span>))</code></pre></div>
<p>Malheureusement, les limitations imposées par le livre nous empèchent d’écrire un grand singleton contenant beaucoup de méthodes et d’instances. Nous préférons donc décrire les définitons en dehors de leurs <em>object</em> compagnon. Ceci est à garder a l’esprit lorsque que vous lisez ce livre mais rappelez-vous que code complet se trouve dans le dépôt mentionné dans la section 1.2</p>
<h2 id="sec:generic:products"><span class="header-section-number">3.2</span> Déduire des instances pour les produits</h2>
<p>Dans cette section nous utilisons shapeless pour déduire des instances de <em>types classes</em> pour des types de produits. (<em>ie.</em> <em>case classes</em>).</p>
<p>Utilisons les deux idées suivantes :</p>
<ol style="list-style-type: decimal">
<li><p>Si l’on a une instance de type <em>class</em> pour la tête et la queue d’une <code>HList</code>, on peut en déduire l’instance de toute la <code>HList</code>.</p></li>
<li><p>Si nous avons une case class <code>A</code>, un <code>Generic[A]</code> et une instance de <em>type class</em> pour le <code>Repr</code> de ce générique, nous pouvons alors les combiner pour obtenir une instance de <code>A</code>.</p></li>
</ol>
<p>Prenons <code>CsvEncoder</code> et <code>IceCream</code> comme exemples :</p>
<ul>
<li><p><code>IceCream</code> a un <code>Repr</code> générique de type <code>String :: Int :: Boolean :: HNil</code>.</p></li>
<li><p>Le <code>Repr</code> est fait d’une <code>String</code>, d’un <code>Int</code>, d’un <code>Boolean</code> et d’une <code>HNil</code>. Si nous avons un <code>CsvEncoder</code> pour ces types alors nous disposons d’un encodeur pour le tout.</p></li>
<li><p>Si nous pouvons déduire un <code>CsvEncoder</code> pour le <code>Repr</code>, nous pouvons en créer un pour <code>IceCream</code>.</p></li>
</ul>
<h3 id="les-instances-de-hlists"><span class="header-section-number">3.2.1</span> Les instances de <em>HLists</em></h3>
<p>Commençons par définir les constructeurs d’instance de <code>CsvEncoders</code> pour <code>String</code>, <code>Int</code> et <code>Boolean</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> createEncoder[A](func: A => List[String]): CsvEncoder[A] =
<span class="kw">new</span> CsvEncoder[A] {
<span class="kw">def</span> <span class="fu">encode</span>(value: A): List[String] = <span class="fu">func</span>(value)
}
<span class="kw">implicit</span> <span class="kw">val</span> stringEncoder: CsvEncoder[String] =
<span class="fu">createEncoder</span>(str => List(str))
<span class="kw">implicit</span> <span class="kw">val</span> intEncoder: CsvEncoder[Int] =
<span class="fu">createEncoder</span>(num => List(num.<span class="fu">toString</span>))
<span class="kw">implicit</span> <span class="kw">val</span> booleanEncoder: CsvEncoder[Boolean] =
<span class="fu">createEncoder</span>(bool => List(<span class="kw">if</span>(bool) <span class="st">"yes"</span> <span class="kw">else</span> <span class="st">"no"</span>))</code></pre></div>
<p>Nous pouvons combiner ces blocs de construction pour créer un encodeur pour notre <code>HList</code>. Nous utiliserons deux règles : une pour <code>HNil</code> et une pour <code>::</code> comme illustré ci-dessous :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.{HList, ::, HNil}
<span class="kw">implicit</span> <span class="kw">val</span> hnilEncoder: CsvEncoder[HNil] =
<span class="fu">createEncoder</span>(hnil => Nil)
<span class="kw">implicit</span> <span class="kw">def</span> hlistEncoder[H, T <: HList](
<span class="kw">implicit</span>
hEncoder: CsvEncoder[H],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :: T] =
createEncoder {
<span class="kw">case</span> h :: t =>
hEncoder.<span class="fu">encode</span>(h) ++ tEncoder.<span class="fu">encode</span>(t)
}</code></pre></div>
<p>Prises toutes ensemble, ces cinq instances nous permettent d’invoquer un <code>CsvEncoders</code> pour toute <code>HList</code> impliquant <code>Strings</code>, <code>Ints</code> et <code>Booleans</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> reprEncoder: CsvEncoder[String :: Int :: Boolean :: HNil] =
implicitly</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">reprEncoder.<span class="fu">encode</span>(<span class="st">"abc"</span> :: <span class="dv">123</span> :: <span class="kw">true</span> :: HNil)
<span class="co">// res9: List[String] = List(abc, 123, yes)</span></code></pre></div>
<h3 id="sec:generic:product-generic"><span class="header-section-number">3.2.2</span> Des instance pour nos produits</h3>
<p>On peut combiner nos règles de déduction de <code>HList</code>s avec nos instances de <code>Generic</code> pour produire un <code>CsvEncoder</code> pour <code>IceCream</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.<span class="fu">Generic</span>
<span class="kw">implicit</span> <span class="kw">val</span> iceCreamEncoder: CsvEncoder[IceCream] = {
<span class="kw">val</span> gen = Generic[IceCream]
<span class="kw">val</span> enc = CsvEncoder[gen.<span class="fu">Repr</span>]
<span class="fu">createEncoder</span>(iceCream => enc.<span class="fu">encode</span>(gen.<span class="fu">to</span>(iceCream)))
}</code></pre></div>
<p>et l’utiliser comme suit :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(iceCreams)
<span class="co">// res11: String =</span>
<span class="co">// Sundae,1,no</span>
<span class="co">// Cornetto,0,yes</span>
<span class="co">// Banana Split,0,no</span></code></pre></div>
<p>Mais cette solution est spécifique à <code>IceCream</code>. Idéalement on voudrait définir une seule règle pour toutes les <em>case classes</em> qui ont un <code>Generic</code> et le <code>CsvEncoder</code> correspondant. Montrons pas à pas comment faire cette déduction. Voici la première étape :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> genericEncoder[A](
<span class="kw">implicit</span>
gen: Generic[A],
enc: CsvEncoder[???]
): CsvEncoder[A] = <span class="fu">createEncoder</span>(a => enc.<span class="fu">encode</span>(gen.<span class="fu">to</span>(a)))</code></pre></div>
<p>Nous devons choisir le type à placer à la place de <code>???</code>. Mais le problème est que l’on ne peut pas utiliser le type <code>Repr</code> associé avec <code>gen</code>, la solution suivante n’est pas possible :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> genericEncoder[A](
<span class="kw">implicit</span>
gen: Generic[A],
enc: CsvEncoder[gen.<span class="fu">Repr</span>]
): CsvEncoder[A] =
<span class="fu">createEncoder</span>(a => enc.<span class="fu">encode</span>(gen.<span class="fu">to</span>(a)))
<span class="co">// <console>:27: error: illegal dependent method type: parameter may only be referenced in a subsequent parameter section</span>
<span class="co">// gen: Generic[A],</span>
<span class="co">// ^</span></code></pre></div>
<p>Nous avons ici un problème de scope : On ne peut faire référence à un membre de type d’un paramètre à partir d’un autre paramètre du même bloc. L’astuce pour contourner ce problème est d’ajouter un nouveau paramètre de type à notre méthode, et y faire référence dans chacune des valeurs associées :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> genericEncoder[A, R](
<span class="kw">implicit</span>
gen: Generic[A] { <span class="kw">type</span> Repr = R },
enc: CsvEncoder[R]
): CsvEncoder[A] =
<span class="fu">createEncoder</span>(a => enc.<span class="fu">encode</span>(gen.<span class="fu">to</span>(a)))</code></pre></div>
<p>Nous traiterons ce style d’écriture dans le chapitre suivant. Maintenant, cette définiton compile et fonctionne comme attendu avec n’importe quelle case class. Intuitivement, la définition nous dit :</p>
<blockquote>
<p><em>Avec un <code>A</code> donné et une <code>HList</code> de type <code>R</code>, avec un implicite <code>Generic</code> qui relie <code>A</code> a <code>R</code> et un <code>CsvEncoder</code> pour <code>R</code>, alors on crée un <code>CsvEncoder</code> pour <code>A</code>.</em></p>
</blockquote>
<p>Nous avons maintenant un système complet qui peut gérer n’importe quelle case class.</p>
<p>L’appel suivant</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(iceCreams)</code></pre></div>
<p>est résolu par le compilateur comme suit :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(iceCreams)(
<span class="fu">genericEncoder</span>(
Generic[IceCream],
<span class="fu">hlistEncoder</span>(stringEncoder,
<span class="fu">hlistEncoder</span>(intEncoder,
<span class="fu">hlistEncoder</span>(booleanEncoder, hnilEncoder)))))</code></pre></div>
<p>et il peut inférer les valeurs correctes pour un grand nombre de types différents. Tout comme moi, je suis sur que vous appréciez ne pas avoir à écrire ce code à la main !</p>
<div class="callout callout-info">
<p><em>l’alias de type Aux</em></p>
<p>Les types refinements comme <code>Generic[A] { type Repr = L }</code> sont verbeux et difficiles à lire, c’est la raison pour laquelle shapeless fournit un alias de type, <code>Generic.Aux</code>, pour reformuler le membre de type en un paramètre de type :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">package</span> shapeless
<span class="kw">object</span> Generic {
<span class="kw">type</span> Aux[A, R] = Generic[A] { <span class="kw">type</span> Repr = R }
}</code></pre></div>
<p>Avec l’alias de type la définition devient beaucoup plus lisible :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> genericEncoder[A, R](
<span class="kw">implicit</span>
gen: Generic.<span class="fu">Aux</span>[A, R],
env: CsvEncoder[R]
): CsvEncoder[A] =
<span class="fu">createEncoder</span>(a => env.<span class="fu">encode</span>(gen.<span class="fu">to</span>(a)))</code></pre></div>
<p>Notez bien que le type <code>Aux</code> ne change pas la sémantique, cela rend juste les chose plus faciles à lire. Le pattern <code>Aux</code> est souvent utilisé dans le code de shapeless.</p>
</div>
<h3 id="alors-quels-en-sont-les-inconvénients"><span class="header-section-number">3.2.3</span> Alors quels en sont les inconvénients ?</h3>
<p>Si tout ce que l’on vient de voir semble magique, permettez-moi de vous ramener à la réalité. Si quelque-chose tourne mal, le compilateur ne vous sera pas d’une grande aide.</p>
<p>Il existe deux raisons pour laquelle le code précédent pourrait ne pas compiler. La première est si le compilateur ne peut pas trouver l’instance de <code>Generic</code>. Par exemple, si nous essayons d’appeler <code>writeCsv</code> avec une simple classe :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">class</span> <span class="fu">Foo</span>(bar: String, baz: Int)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(List(<span class="kw">new</span> <span class="fu">Foo</span>(<span class="st">"abc"</span>, <span class="dv">123</span>)))
<span class="co">// <console>:31: error: could not find implicit value for parameter encoder: CsvEncoder[Foo]</span>
<span class="co">// writeCsv(List(new Foo("abc", 123)))</span>
<span class="co">// ^</span></code></pre></div>
<p>Dans ce cas le message est relativement simple à comprendre. Si shapeless ne peut calculer un <code>Generic</code> cela veut dire que le type en question n’est pas un <em>ADT</em> (il y a quelque-part dans l’algèbre un type qui n’est pas une case class ou un trait scellé).</p>
<p>L’autre source potentielle d’erreur survient lorsque le compilateur ne peut calculer un <code>CsvEncoder</code> pour notre <code>HList</code>. Cela arrive normalement car l’on n’a pas d’encodeur pour un des champs de notre <em>ADT</em>. Par exemple nous n’avons pas encore défini de <code>CsvEncoder</code> pour <code>java.util.Date</code>, donc le code suivant ne fonctionne pas :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> java.<span class="fu">util</span>.<span class="fu">Date</span>
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">Booking</span>(room: String, date: Date)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(List(<span class="fu">Booking</span>(<span class="st">"Lecture hall"</span>, <span class="kw">new</span> Date())))
<span class="co">// <console>:33: error: could not find implicit value for parameter encoder: CsvEncoder[Booking]</span>
<span class="co">// writeCsv(List(Booking("Lecture hall", new Date())))</span>
<span class="co">// ^</span></code></pre></div>
<p>Le messsage d’erreur ne nous aide pas vraiment. Tout ce que le compilateur sait, c’est qu’il a essayé un grand nombre de combinaisons d’implicites et qu’aucune ne fonctionnait. Il n’a aucune idée de quelle combinaison était la plus proche de celle attendue, donc il ne peut nous dire où se trouve la source du problème.</p>
<p>Il n’y a pas de quoi se réjouir ici. Nous devons trouver nous-même la source des erreurs par un processus d’élimination. Nous aborderons les techniques de debuggage dans la section 3.5. Pour l’instant la seule fonctionalité qui compense c’est que la résolution d’implicite plantera toujours à la compilation. Il y a une petite chance que cela finisse par produire du code qui plante durant l’exécution.</p>
<h2 id="sec:generic:coproducts"><span class="header-section-number">3.3</span> Déduire les instances pour les coproduits</h2>
<p>Dans la section précédente nous avons crée un ensemble de règle pour déduire automatiquement un <code>CsvEncoder</code> pour n’importe quel type de produits. Dans cette section allons appliqué les mêmes patrons de conception aux coproduits. Retournons a notre exemple, l’<em>ADT</em> shape :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">sealed</span> <span class="kw">trait</span> Shape
<span class="kw">final</span> <span class="kw">case</span> <span class="kw">class</span> Rectangle(width: Double, height: Double) <span class="kw">extends</span> Shape
<span class="kw">final</span> <span class="kw">case</span> <span class="kw">class</span> <span class="fu">Circle</span>(radius: Double) <span class="kw">extends</span> Shape</code></pre></div>
<p>La représentation générique de <code>Shape</code> est <code>Rectangle :+: Circle :+: CNil</code>. Dans la section 3.2.2 nous avons définie des encodeurs de produit pour <code>Rectangle</code> et <code>Circle</code>. Maintenant, pour écrire des <code>CsvEncoders</code> générique pour <code>:+:</code> et <code>CNil</code>, nous alons utilisé les mêmes principes que pour <code>HList</code>s:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.{Coproduct, :+:, CNil, Inl, Inr}
<span class="kw">implicit</span> <span class="kw">val</span> cnilEncoder: CsvEncoder[CNil] =
<span class="fu">createEncoder</span>(cnil => <span class="kw">throw</span> <span class="kw">new</span> Exception(<span class="st">"Inconceivable!"</span>))
<span class="kw">implicit</span> <span class="kw">def</span> coproductEncoder[H, T <: Coproduct](
<span class="kw">implicit</span>
hEncoder: CsvEncoder[H],
tEncoder: CsvEncoder[T]
): CsvEncoder[H :+: T] = createEncoder {
<span class="kw">case</span> <span class="fu">Inl</span>(h) => hEncoder.<span class="fu">encode</span>(h)
<span class="kw">case</span> <span class="fu">Inr</span>(t) => tEncoder.<span class="fu">encode</span>(t)
}</code></pre></div>
<p>Il importe de noter deux choses :</p>
<ol style="list-style-type: decimal">
<li><p>Comme <code>Coproduct</code>s est une <em>disjonction</em> de types, l’encoder de <code>:+:</code> doit <em>choisir</em> si il a à encoder la valeur de droit ou de gauche. On fait un pattern matching sur les deux sous types de <code>:+:</code>, qui sont <code>Inl</code> pour la gauche et <code>Inr</code> pour la droite.</p></li>
<li><p>Etonnament, l’encoder de <code>CNil</code> lève une exception! Mais pas de panique. Rappelez vous que l’on ne peut crée de valeur pour le type <code>CNil</code>, donc the <code>throw</code> et en fait du code mort.</p></li>
</ol>
<p>Si l’on utilise ces définitions avec celle de nos produit de la section 3.2, on sera capable de sérializer une liste de shapes. Essayons:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> shapes: List[Shape] = List(
Rectangle(<span class="fl">3.0</span>, <span class="fl">4.0</span>),
<span class="fu">Circle</span>(<span class="fl">1.0</span>)
)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(shapes)
<span class="co">// <console>:33: error: could not find implicit value for parameter encoder: CsvEncoder[Shape]</span>
<span class="co">// writeCsv(shapes)</span>
<span class="co">// ^</span></code></pre></div>
<p>Oh non, ca n’a pas fonctionné ! Le message d’erreur ne nous aide pas comme prévu. Nous avons cette erreur car nous n’avons pas d’instance de <code>CsvEncoder</code> pour <code>Double</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">val</span> doubleEncoder: CsvEncoder[Double] =
<span class="fu">createEncoder</span>(d => List(d.<span class="fu">toString</span>))</code></pre></div>
<p>Avec cette nouvelle définition, tout fonctionne comme prévus:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">writeCsv</span>(shapes)
<span class="co">// res7: String =</span>
<span class="co">// 3.0,4.0</span>
<span class="co">// 1.0</span></code></pre></div>
<div class="callout callout-warning">
<p><em>SI-7046 et vous</em> Il y a dans Scala un bug du compilateur appelé <a href="https://issues.scala-lang.org/browse/SI-7046">SI-7046</a> qui peut amener la résolution de générique pour comproduct a ne pas fonctionner. Le bug provoque dans certaines partie de l’API de macro, dont shapeless dépend, deviens sensible a l’ordre des définitions dans le code source. C’est un problème qui peut souvant etre contourner en réordonant le code et en renoment les fichiers, mais ces solution on tendence a ne durée qu’un temps et sont peut fiable.</p>
<p>Si vous utilisez <em>Lightbend Scala 2.11.8</em> ou une version plus ancienne et que vous ètes toucher par ce problème, pensez a mettre a jour vers la version <em>Lightbend Scala 2.11.9</em> ou <em>Typelevel Scala 2.11.8</em>. SI-7046 est corrigée dans chacune de de ces versions.</p>
</div>
<h3 id="aligner-les-colonnes-dans-la-sortie-csv"><span class="header-section-number">3.3.1</span> Aligner les colonnes dans la sortie CSV</h3>
<p>Notre encodeur de CSV n’est idéal dans ca forme courante. Il permet au champs de <code>Rectangle</code> et <code>Circle</code> de se retrouver dans la meme colonne. Pour remédier a a ce problème il faut changer la définition de <code>CsvEncoder</code> pour ajouter la largeur des type de données et ainsi espacer les colonnes en conséquence. Le dépôt d’exemple contenant l’implémentation complète d’un <code>CsvEncoder</code> traitant ce problème est linké dans la section 1.2</p>
<h2 id="la-déduction-dinstance-pour-les-type-récursif."><span class="header-section-number">3.4</span> La déduction d’instance pour les type récursif.</h2>
<p>Essayons quelque chose de plus ambitieu : un arbre binaire :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">sealed</span> <span class="kw">trait</span> Tree[A]
<span class="kw">case</span> <span class="kw">class</span> Branch[A](left: Tree[A], right: Tree[A]) <span class="kw">extends</span> Tree[A]
<span class="kw">case</span> <span class="kw">class</span> Leaf[A](value: A) <span class="kw">extends</span> Tree[A]</code></pre></div>
<p>En théorie nous devrions deja avoir toutes les définiton pour instancier un CSV writer pour notre arbre. Pourtant, appler <code>writeCsv</code> provoque une erreur : However, calls to <code>writeCsv</code> fail to compile:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Tree[Int]]
<span class="co">// <console>:25: error: could not find implicit value for parameter enc: CsvEncoder[Tree[Int]]</span>
<span class="co">// CsvEncoder[Tree[Int]]</span>
<span class="co">// ^</span></code></pre></div>
<p>Le problème est que notre type est qu’il est récusif. Le compilateur rentre dans une boucle infie en essayant d’appliquer nos implicits puis il abandonne.</p>
<h3 id="les-divergences-dimplicits"><span class="header-section-number">3.4.1</span> Les divergences d’implicits</h3>
<p>La résolution d’<code>implicit</code> est un processus de recherche. Le compilateur utilise des heuristiques pour s’orienter vers la bonne solution. Le compilateur effectue ses recherches branche par branche, si l’une d’elle ne donne pas de résultat favorable, le compilateur considère que cette branche n’aboutira pas et continue ses recherches sur une autre branche.</p>
<p>Une des heuristique est conçue spécifiquement pour éviter les boucles infinies. Si le compilateur rencontre le type cible deux fois dans une branche de recherche; il abandonne cette branche et passe a une autre. On peut l’observer si on regarde l’expression <code>CsvEncoder[Tree[Int]]</code>. Le processus de résolution d’implicits suit les étapes suivantes :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Tree[Int]] <span class="co">// 1</span>
CsvEncoder[Branch[Int] :+: Leaf[Int] :+: CNil] <span class="co">// 2</span>
CsvEncoder[Branch[Int]] <span class="co">// 3</span>
CsvEncoder[Tree[Int] :: Tree[Int] :: HNil] <span class="co">// 4</span>
CsvEncoder[Tree[Int]] <span class="co">// 5 uh oh</span></code></pre></div>
<p>On rencontre <code>Tree[A]</code> deux fois lignes 1 et 5, donc le compilateur abandonne la recherche dans cette branche. La conséquence est que le compilateur echoue à trouver le bon <em>implicit</em>.</p>
<p>En fait, la situation est pire. Si le compilateur voit le même constructeur de types deux fois et que la complexité du paramètre de type <em>augmente</em> il suppose que la branche n’aboutira pas.* C’est un problème avec shapeless car les types comme <code>::[H, T]</code> et <code>:+:[H, T]</code> peuvent apparaître plusieurs fois lorsque le compilateur développe les représentations génériques. Ce qui pousse le compilateur a abandonner prématurément même si il aurait pu trouver la solution si il avait persisté à chercher dans cette voie.</p>
<p>Compte-tenu des types suivants :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">case</span> <span class="kw">class</span> <span class="fu">Bar</span>(baz: Int, qux: String)
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">Foo</span>(bar: Bar)</code></pre></div>
<p>Le déroulement de la recherche pour <code>Foo</code> ressemble à ça :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Foo] <span class="co">// 1</span>
CsvEncoder[Bar :: HNil] <span class="co">// 2</span>
CsvEncoder[Bar] <span class="co">// 3</span>
CsvEncoder[Int :: String :: HNil] <span class="co">// 4 uh oh</span></code></pre></div>
<p>Le compilateur essait de résoudre <code>CsvEncoder[::[H, T]]</code> deux fois dans cette branche, une fois a la ligne 2 et une fois a la ligne 4. Le paramètre de type <code>T</code> est plus complexe à la ligne 4 qu’à la ligne 2, donc le compilateur pense (de façon erronée dans ce cas) que la recherche dans cette branche n’aboutira pas. Il change de branche encore et encore, il ne trouvera pas de quoi générer la bonne instance.</p>
<h3 id="lazy"><span class="header-section-number">3.4.2</span> <em>Lazy</em></h3>
<p>La divergence d’<code>implicit</code> peut marquer un arrêt pour la librairie shapeless. Heureusement, shapeless fournit un type appeler <code>Lazy</code> pour contourner ce problème. <code>Lazy</code> fait deux choses :</p>
<ol style="list-style-type: decimal">
<li><p>Il supprime la divergence d’<code>implicit</code> à la compilation en se protégeant des heuristiques trop défensives.</p></li>
<li><p>Il reporte l’évaluation des paramètres implicites au runtime, ce qui permet la déduction des implicits récursifs.</p></li>
</ol>
<p>On utilise <code>Lazy</code> en le paramétrant avec nos paramètres implicites. En règle générale, il est toujours bon d’englober dans <code>Lazy</code> le paramètre de “tête” de toute règle de <code>HList</code> ou de <code>Coproduct</code> ainsi que n’importe quel paramètre <code>Repr</code> d’un <code>Generic</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> hlistEncoder[H, T <: HList](
<span class="kw">implicit</span>
hEncoder: Lazy[CsvEncoder[H]], <span class="co">// wrap in Lazy</span>
tEncoder: CsvEncoder[T]
): CsvEncoder[H :: T] = createEncoder {
<span class="kw">case</span> h :: t =>
hEncoder.<span class="fu">value</span>.<span class="fu">encode</span>(h) ++ tEncoder.<span class="fu">encode</span>(t)
}</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> coproductEncoder[H, T <: Coproduct](
<span class="kw">implicit</span>
hEncoder: Lazy[CsvEncoder[H]], <span class="co">// wrap in Lazy</span>
tEncoder: CsvEncoder[T]
): CsvEncoder[H :+: T] = createEncoder {
<span class="kw">case</span> <span class="fu">Inl</span>(h) => hEncoder.<span class="fu">value</span>.<span class="fu">encode</span>(h)
<span class="kw">case</span> <span class="fu">Inr</span>(t) => tEncoder.<span class="fu">encode</span>(t)
}</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> genericEncoder[A, R](
<span class="kw">implicit</span>
gen: Generic.<span class="fu">Aux</span>[A, R],
rEncoder: Lazy[CsvEncoder[R]] <span class="co">// wrap in Lazy</span>
): CsvEncoder[A] = createEncoder { value =>
rEncoder.<span class="fu">value</span>.<span class="fu">encode</span>(gen.<span class="fu">to</span>(value))
}</code></pre></div>
<p>Ceci permet au compilateur de ne pas jeter l’éponge prématurément et donc permet aux types complex/récursif comme <code>Tree</code> de fonctionner :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Tree[Int]]
<span class="co">// res2: CsvEncoder[Tree[Int]] = $anon$1@624d14b2</span></code></pre></div>
<h2 id="sec:generic:debugging"><span class="header-section-number">3.5</span> Débugger les résolutions d’implicites</h2>
<p>Les erreurs dans la résolution d’implicites peuvent être déconcertantes et frustrantes. Voici quelques techniques à utiliser quand les choses vont mal.</p>
<h3 id="débugger-en-utilisant-implicitly"><span class="header-section-number">3.5.1</span> Débugger en utilisant <em>implicitly</em></h3>
<p>Que peut-on faire quand les compilateurs ne trouvent simplement pas la valeur implicite ? L’erreur peut être causée par la résolution de n’importe quel implicit. Par exemple :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">case</span> <span class="kw">class</span> <span class="fu">Foo</span>(bar: Int, baz: Float)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Foo]
<span class="co">// <console>:31: error: could not find implicit value for parameter enc: CsvEncoder[Foo]</span>
<span class="co">// CsvEncoder[Foo]</span>
<span class="co">// ^</span></code></pre></div>
<p>Nous avons une erreur car nous navons pas défini <code>CsvEncoder</code> pour <code>Float</code>. Pourtant, cela n’est peut-être pas évident à voir dans le code de l’application. On peut chercher l’erreur en imaginant comment l’implicite est censé se développer, insérer des appels à <code>CsvEncoder.apply</code> ou à <code>implicitly</code> au-dessus de l’erreur pour voir si cela compile. Commençons avec la représentation générique de <code>Foo</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Int :: Float :: HNil]
<span class="co">// <console>:29: error: could not find implicit value for parameter enc: CsvEncoder[shapeless.::[Int,shapeless.::[Float,shapeless.HNil]]]</span>
<span class="co">// CsvEncoder[Int :: Float :: HNil]</span>
<span class="co">// ^</span></code></pre></div>
<p>L’erreur ici nous en dit un peu plus, on doit continuer à chercher plus profondément dans la chaînes d’appel des implicites. L’étape suivante est de tester les composants de <code>HList</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Int]</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">CsvEncoder[Float]
<span class="co">// <console>:29: error: could not find implicit value for parameter enc: CsvEncoder[Float]</span>
<span class="co">// CsvEncoder[Float]</span>
<span class="co">// ^</span></code></pre></div>
<p><code>Int</code> fonctionne mais <code>Float</code> lève une erreur. <code>CsvEncoder[Float]</code> est une feuille dans le développement de notre abre, on sait donc que l’on doit commencer par implémenter l’instance manquante. Si ajouter l’instance ne corrige pas le problème, on répète le processus pour trouver le prochain point problématique.</p>
<h3 id="debugger-en-utilisant-reify"><span class="header-section-number">3.5.2</span> Debugger en utilisant <em>reify</em></h3>
<p>La méthode <code>reify</code> de <code>scala.reflect</code> prend une expression Scala en paramètre et retourne un objet AST représentant l’expression sous forme d’abre avec toutes les annotations de types.</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> scala.<span class="fu">reflect</span>.<span class="fu">runtime</span>.<span class="fu">universe</span>._</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">println</span>(<span class="fu">reify</span>(CsvEncoder[Int]))
<span class="co">// Expr[CsvEncoder[Int]]($read.$iw.$iw.$iw.$iw.CsvEncoder.apply[Int]($read.$iw.$iw.$iw.$iw.intEncoder))</span></code></pre></div>
<p>Les types inferés pendant la résolution d’implicite peuvent nous donner un indice sur le problème. Après la résolution d’implicite, tous les types existentiels restants comme <code>A</code> ou <code>T</code> indiquent que quelque-chose n’a pas bien fonctionné. Les types “top” et “bottom” comme <code>Any</code> and <code>Nothing</code> sont aussi la preuve d’une erreur.</p>
<h2 id="en-résumé"><span class="header-section-number">3.6</span> En résumé</h2>
<p>Dans ce chapitre nous avons expliqué comment utiliser <code>Generic</code>, <code>HList</code>s, et <code>Coproduct</code>s pour déduire automatiquement l’instance d’une <em>type class</em>. Nous avons couvert aussi le type <code>Lazy</code> qui est un moyen de manipuler les types complexes/recursifs. Compte tenu de tout ceci, on peut écrire le squelette commun suivant qui permet de déduire des instances de <em>type class</em>.</p>
<p>Premièrement, définissons la <em>type class</em> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">trait</span> MyTC[A]</code></pre></div>
<p>Définissons les instances pour les types primitifs :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> intInstance: MyTC[Int] = ???
<span class="kw">implicit</span> <span class="kw">def</span> stringInstance: MyTC[String] = ???
<span class="kw">implicit</span> <span class="kw">def</span> booleanInstance: MyTC[Boolean] = ???</code></pre></div>
<p>Définissons les instances pour <code>HList</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless._
<span class="kw">implicit</span> <span class="kw">def</span> hnilInstance: MyTC[HNil] = ???
<span class="kw">implicit</span> <span class="kw">def</span> hlistInstance[H, T <: HList](
<span class="kw">implicit</span>
hInstance: Lazy[MyTC[H]], <span class="co">// wrap in Lazy</span>
tInstance: MyTC[T]
): MyTC[H :: T] = ???</code></pre></div>
<p>Si nécessaire, définissons les instances de <code>Coproduct</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> cnilInstance: MyTC[CNil] = ???
<span class="kw">implicit</span> <span class="kw">def</span> coproductInstance[H, T <: Coproduct](
<span class="kw">implicit</span>
hInstance: Lazy[MyTC[H]], <span class="co">// wrap in Lazy</span>
tInstance: MyTC[T]
): MyTC[H :+: T] = ???</code></pre></div>
<p>Enfin, définissons les instances pour <code>Generic</code>:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> genericInstance[A, R](
<span class="kw">implicit</span>
generic: Generic.<span class="fu">Aux</span>[A, R],
rInstance: Lazy[MyTC[R]] <span class="co">// wrap in Lazy</span>
): MyTC[A] = ???</code></pre></div>
<p>Dans le chapitre suivant nous verrons la théorie et des patrons de conception utiles pour écrire ce genre de code. Dans le Chapitre 5, nous reviendrons sur la déduction de <em>type class</em> en utilisant une variante de <code>Generic</code> qui permet d’inspecter les champs et les noms des types dans nos <em>ADT</em>s.</p>
<h1 id="sec:type-level-programming"><span class="header-section-number">4</span> Travailler avec les types et les implicites</h1>
<p>Dans le chapitre précédent, nous avons vu l’un des cas d’utilisation les plus fascinants de shapeless : la déduction automatique d’instance de case class. Nous allons découvrir qu’il existe plusieurs autres exemples au moins aussi saisissants. Cependant, avant d’en arriver là, nous devons prendre un peu de temps pour traiter la théorie que nous avons évité jusqu’ici et établir un ensemble de patrons de conception pour écrire et débugger du code hautement implicite et hautement typé.</p>
<h2 id="types-dépendants"><span class="header-section-number">4.1</span> Types dépendants</h2>
<p>Dans le dernier chapitre, nous avons passé beaucoup de temps à utiliser <code>Generic</code>, la <em>type class</em> qui sert à lier un type <em>ADT</em> à sa représentation générique. Pourtant, nous n’avons pas encore abordé la théorie sous-jacente à <code>Generic</code> et à tout shapeless : <em>les types dépendants</em>.</p>
<p>Pour illustrer tout ca, intéressons-nous de plus près à <code>Generic</code>. Voici une version simplifié de sa définition :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">trait</span> Generic[A] {
<span class="kw">type</span> Repr
<span class="kw">def</span> <span class="fu">to</span>(value: A): Repr
<span class="kw">def</span> <span class="fu">from</span>(value: Repr): A
}</code></pre></div>
<p>Les instances de <code>Generic</code> font référence à deux autres types : un paramètre de type <code>A</code> et un membre de type <code>Repr</code>. Imaginons que l’on implémente une méthode <code>getRepr</code> de la façon suivante. Quel type allons-nous obtenir en retour ?</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.<span class="fu">Generic</span>
<span class="kw">def</span> getRepr[A](value: A)(<span class="kw">implicit</span> gen: Generic[A]) =
gen.<span class="fu">to</span>(value)</code></pre></div>
<p>La réponse est : tout dépend de l’instance de <code>gen</code> que nous avons. En développant l’appel de <code>getRepr</code>, le compilateur va chercher un <code>Generic[A]</code> et le type sera le <code>Repr</code> défini dans l’instance :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">case</span> <span class="kw">class</span> <span class="fu">Vec</span>(x: Int, y: Int)
<span class="kw">case</span> <span class="kw">class</span> <span class="fu">Rect</span>(origin: Vec, size: Vec)</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">getRepr</span>(<span class="fu">Vec</span>(<span class="dv">1</span>, <span class="dv">2</span>))
<span class="co">// res1: shapeless.::[Int,shapeless.::[Int,shapeless.HNil]] = 1 :: 2 :: HNil</span>
<span class="fu">getRepr</span>(<span class="fu">Rect</span>(<span class="fu">Vec</span>(<span class="dv">0</span>, <span class="dv">0</span>), <span class="fu">Vec</span>(<span class="dv">5</span>, <span class="dv">5</span>)))
<span class="co">// res2: shapeless.::[Vec,shapeless.::[Vec,shapeless.HNil]] = Vec(0,0) :: Vec(5,5) :: HNil</span></code></pre></div>
<p>Ce que nous voyons ici est appelé <em>typage dependent</em>: le type du résultat de <code>getRepr</code> dépend de la valeur de son paramètre de type via son membre de type. Imaginons que nous avons spécifié <code>Repr</code> comme paramètre de type de <code>Generic</code> à la place du membre de type:</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">trait</span> Generic2[A, Repr]
<span class="kw">def</span> getRepr2[A, R](value: A)(<span class="kw">implicit</span> generic: Generic2[A, R]): R =
???</code></pre></div>
<p>Nous aurions dû passer la valeur désirée de <code>Repr</code> dans le paramètre de type de <code>getRepr</code>, ce qui finit par rendre <code>getRepr</code> inutile. On peut en déduire que les paramètres de type sont utiles en tant « qu’inputs » et les membre de type sont utiles en tant « qu’outputs. »</p>
<h2 id="sec:type-level-programming:depfun"><span class="header-section-number">4.2</span> Fonctions à type dépendant</h2>
<p>Shapeless utilise les types dépendants partout : dans <code>Generic</code>, dans <code>Witness</code> (que nous traiterons dans le chapitre suivant), et dans de nombreux type classes « ops » que nous traiterons dans la <em>Partie II</em> de ce guide. Par exemple, shapeless fournit une case class appelée <code>Last</code> qui retourne le dernier élément d’une <code>HList</code>. Voici une version simplifiée de son implémentation :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">package</span> shapeless.<span class="fu">ops</span>.<span class="fu">hlist</span>
<span class="kw">trait</span> Last[L <: HList] {
<span class="kw">type</span> Out
<span class="kw">def</span> <span class="fu">apply</span>(in: L): Out
}</code></pre></div>
<p>On peut invoquer des instances de <code>Last</code> pour inspecter les <code>HList</code>s dans notre code. Notez que dans les deux exemples ci-dessous les types de <code>Out</code> sont dépendants des types des <code>HList</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless.{HList, ::, HNil}
<span class="kw">import</span> shapeless.<span class="fu">ops</span>.<span class="fu">hlist</span>.<span class="fu">Last</span></code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> last1 = Last[String :: Int :: HNil]
<span class="co">// last1: shapeless.ops.hlist.Last[shapeless.::[String,shapeless.::[Int,shapeless.HNil]]]{type Out = Int} = shapeless.ops.hlist$Last$$anon$34@697ed93b</span>
<span class="kw">val</span> last2 = Last[Int :: String :: HNil]
<span class="co">// last2: shapeless.ops.hlist.Last[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]]{type Out = String} = shapeless.ops.hlist$Last$$anon$34@6266c63f</span></code></pre></div>
<p>Une fois les instances de <code>Last</code> invoquées, et on peut les utiliser au value level via leurs méthodes <code>apply</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">last1</span>(<span class="st">"foo"</span> :: <span class="dv">123</span> :: HNil)
<span class="co">// res1: last1.Out = 123</span>
<span class="fu">last2</span>(<span class="dv">321</span> :: <span class="st">"bar"</span> :: HNil)
<span class="co">// res2: last2.Out = bar</span></code></pre></div>
<p>Nous avons deux formes de protection contre les erreurs. L’implicite définie pour <code>Last</code> nous garantit que l’on peut construire une instance de <code>Last</code> uniquement si la <code>HList</code> en entrée est dotée d’au moins un élément :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">Last[HNil]
<span class="co">// <console>:15: error: Implicit not found: shapeless.Ops.Last[shapeless.HNil]. shapeless.HNil is empty, so there is no last element.</span>
<span class="co">// Last[HNil]</span>
<span class="co">// ^</span></code></pre></div>
<p>De plus, le paramètre de type de l’instance de <code>Last</code> vérifie qu’on lui passe bien une instance de <code>HList</code> du bon type :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">last1</span>(<span class="dv">321</span> :: <span class="st">"bar"</span> :: HNil)
<span class="co">// <console>:16: error: type mismatch;</span>
<span class="co">// found : shapeless.::[Int,shapeless.::[String,shapeless.HNil]]</span>
<span class="co">// required: shapeless.::[String,shapeless.::[Int,shapeless.HNil]]</span>
<span class="co">// last1(321 :: "bar" :: HNil)</span>
<span class="co">// ^</span></code></pre></div>
<p>Pour faire un autre exemple, implémentons notre propre type classe, appelé <code>Second</code>, qui retourne le second élément d’une <code>HList</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">trait</span> Second[L <: HList] {
<span class="kw">type</span> Out
<span class="kw">def</span> <span class="fu">apply</span>(value: L): Out
}
<span class="kw">object</span> Second {
<span class="kw">type</span> Aux[L <: HList, O] = Second[L] { <span class="kw">type</span> Out = O }
<span class="kw">def</span> apply[L <: HList](<span class="kw">implicit</span> inst: Second[L]): Aux[L, inst.<span class="fu">Out</span>] =
inst
}</code></pre></div>
<p>Ce code utilise l’agencement idiomatique décrit dans la section 3.1.2. On définit un type <code>Aux</code> dans l’objet compagnon aux cotés de la méthode standard <code>apply</code>, qui permet d’invoquer des instances.</p>
<div class="callout callout-warning">
<p><em>Méthode d’invocation versus “implicitly” versus “the”</em></p>
<p>Remarquez que le type de retour d’<code>apply</code> est <code>Aux[L, O]</code> et non pas <code>Second[L]</code>. C’est important. Utiliser <code>Aux</code> assure que la methode <code>apply</code> n’écrase pas les membres de type de l’instance invoquée. Si l’on définit <code>Second[L]</code> comme type de retour, le membre de type <code>Out</code> sera perdu dans le type retourné et la <em>type class</em> ne fonctionnera plus correctement.</p>
<p>La méthode <code>implicitly</code> de <code>scala.Predef</code> est dotée de cette propriété. Comparons le type d’une instance de <code>Last</code> invoqué par <code>implicitly</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">implicitly[Last[String :: Int :: HNil]]
<span class="co">// res6: shapeless.ops.hlist.Last[shapeless.::[String,shapeless.::[Int,shapeless.HNil]]] = shapeless.ops.hlist$Last$$anon$34@4ce01309</span></code></pre></div>
<p>au type retourné par <code>Last.apply</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">Last[String :: Int :: HNil]
<span class="co">// res7: shapeless.ops.hlist.Last[shapeless.::[String,shapeless.::[Int,shapeless.HNil]]]{type Out = Int} = shapeless.ops.hlist$Last$$anon$34@b46b74a</span></code></pre></div>
<p>Le type invoqué par <code>implicitly</code> n’a pas de membre de type <code>Out</code>. C’est pourquoi on doit éviter d’utiliser <code>implicitly</code> lorsque l’on travaille avec des fonctions à type dépendant. On peut utiliser une méthode d’invocation custom ou directement la méthode <code>the</code> de shapeless :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">import</span> shapeless._
the[Last[String :: Int :: HNil]]
<span class="co">// res8: shapeless.ops.hlist.Last[shapeless.::[String,shapeless.::[Int,shapeless.HNil]]]{type Out = Int} = shapeless.ops.hlist$Last$$anon$34@357a953d</span></code></pre></div>
</div>
<p>Nous n’avons besoin que d’une seule instance définie pour une <code>HList</code>s d’au moins deux éléments :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">implicit</span> <span class="kw">def</span> hlistSecond[A, B, Rest <: HList]: Aux[A :: B :: Rest, B] =
<span class="kw">new</span> Second[A :: B :: Rest] {
<span class="kw">type</span> Out = B
<span class="kw">def</span> <span class="fu">apply</span>(value: A :: B :: Rest): B =
value.<span class="fu">tail</span>.<span class="fu">head</span>
}</code></pre></div>
<p>On peut invoquer les instances en utilisant <code>Second.apply</code> :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">val</span> second1 = Second[String :: Boolean :: Int :: HNil]
<span class="co">// second1: Second[shapeless.::[String,shapeless.::[Boolean,shapeless.::[Int,shapeless.HNil]]]]{type Out = Boolean} = $anon$1@13acefad</span>
<span class="kw">val</span> second2 = Second[String :: Int :: Boolean :: HNil]
<span class="co">// second2: Second[shapeless.::[String,shapeless.::[Int,shapeless.::[Boolean,shapeless.HNil]]]]{type Out = Int} = $anon$1@780348f1</span></code></pre></div>
<p>L’invocation est sujette aux mêmes contraintes que <code>Last</code>. Si l’on essaie d’invoquer une instance pour une <code>HList</code> incompatible, alors la résolution échoue et l’on obtient une erreur de compilation :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala">Second[String :: HNil]
<span class="co">// <console>:27: error: could not find implicit value for parameter inst: Second[shapeless.::[String,shapeless.HNil]]</span>
<span class="co">// Second[String :: HNil]</span>
<span class="co">// ^</span></code></pre></div>
<p>Les instances invoquées avec la méthode <code>apply</code> fonctionne avec les types de <code>HList</code> appropriés au niveau des valeurs (value level)</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">second1</span>(<span class="st">"foo"</span> :: <span class="kw">true</span> :: <span class="dv">123</span> :: HNil)
<span class="co">// res10: second1.Out = true</span>
<span class="fu">second2</span>(<span class="st">"bar"</span> :: <span class="dv">321</span> :: <span class="kw">false</span> :: HNil)
<span class="co">// res11: second2.Out = 321</span></code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">second1</span>(<span class="st">"baz"</span> :: HNil)
<span class="co">// <console>:28: error: type mismatch;</span>
<span class="co">// found : shapeless.::[String,shapeless.HNil]</span>
<span class="co">// required: shapeless.::[String,shapeless.::[Boolean,shapeless.::[Int,shapeless.HNil]]]</span>
<span class="co">// second1("baz" :: HNil)</span>
<span class="co">// ^</span></code></pre></div>
<h2 id="sec:type-level-programming:chaining"><span class="header-section-number">4.3</span> Enchaîner les fonctions dépendantes</h2>
<p>Les fonctions à type dépendant offrent un moyen de calculer un type à partir d’un autre. On peut enchaîner les fonctions à type dépendant pour effectuer un calcul nécessitant plusieurs étapes. Par exemple, on pourrait utiliser <code>Generic</code> pour calculer le <code>Repr</code> d’une case classe et utiliser <code>Last</code> pour calculer le type du dernier élément. Essayons de coder ceci :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> lastField[A](input: A)(
<span class="kw">implicit</span>
gen: Generic[A],
last: Last[gen.<span class="fu">Repr</span>]
): last.<span class="fu">Out</span> = last.<span class="fu">apply</span>(gen.<span class="fu">to</span>(input))
<span class="co">// <console>:29: error: illegal dependent method type: parameter may only be referenced in a subsequent parameter section</span>
<span class="co">// gen: Generic[A],</span>
<span class="co">// ^</span></code></pre></div>
<p>Malheureusement, notre code ne compile pas. Il s’agit du même problème que nous avions rencontré dans la section 3.2.2 avec notre définition de <code>genericEncoder</code>. Nous avions contourné le problème en remontant la variable de type non-parametré dans la liste des paramètres de types :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> lastField[A, Repr <: HList](input: A)(
<span class="kw">implicit</span>
gen: Generic.<span class="fu">Aux</span>[A, Repr],
last: Last[Repr]
): last.<span class="fu">Out</span> = last.<span class="fu">apply</span>(gen.<span class="fu">to</span>(input))</code></pre></div>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="fu">lastField</span>(<span class="fu">Rect</span>(<span class="fu">Vec</span>(<span class="dv">1</span>, <span class="dv">2</span>), <span class="fu">Vec</span>(<span class="dv">3</span>, <span class="dv">4</span>)))
<span class="co">// res13: Vec = Vec(3,4)</span></code></pre></div>
<p>En règle général, on écrit toujours du code dans ce style. En paramétrant toutes les variables de type, on permet au compilateur de les unifier avec les types appropriés. Cela vaut également pour des contraintes plus subtiles. Par exemple, imaginons qu’on veuille invoquer un <code>Generic</code> pour une case class qui porte exactement un champ. On pourrait être tenté d’écrire le code suivant :</p>
<div class="sourceCode"><pre class="sourceCode scala"><code class="sourceCode scala"><span class="kw">def</span> getWrappedValue[A, H](input: A)(
<span class="kw">implicit</span>