sequenceserver 0.8.9 → 1.0.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sequenceserver might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/{README.txt → README.md} +2 -0
- data/bin/sequenceserver +255 -55
- data/config.ru +2 -4
- data/lib/sequenceserver.rb +293 -447
- data/lib/sequenceserver/blast.rb +464 -64
- data/lib/sequenceserver/database.rb +185 -19
- data/lib/sequenceserver/links.rb +114 -0
- data/lib/sequenceserver/logger.rb +27 -0
- data/lib/sequenceserver/sequence.rb +141 -0
- data/public/css/bootstrap.min.css +8 -413
- data/public/css/custom.css +363 -122
- data/public/css/font-awesome.min.css +4 -0
- data/public/fonts/FontAwesome.otf +0 -0
- data/public/fonts/fontawesome-webfont.eot +0 -0
- data/public/fonts/fontawesome-webfont.svg +565 -0
- data/public/fonts/fontawesome-webfont.ttf +0 -0
- data/public/fonts/fontawesome-webfont.woff +0 -0
- data/public/fonts/fontawesome-webfont.woff2 +0 -0
- data/public/js/bootstrap.min.js +11 -0
- data/public/js/d3.v3.min.js +5 -0
- data/public/js/html5shiv.min.js +4 -0
- data/public/js/jquery.scrollspy.js +74 -0
- data/public/js/jquery.t.js +353 -0
- data/public/js/sequence.js +2419 -0
- data/public/js/sequenceserver.blast.js +29 -30
- data/public/js/sequenceserver.js +544 -120
- data/public/js/underscore.min.js +6 -0
- data/public/js/webshims/polyfiller.js +1 -0
- data/public/js/webshims/shims/FlashCanvas/canvas2png.js +1 -0
- data/public/js/webshims/shims/FlashCanvas/flashcanvas.js +1 -0
- data/public/js/webshims/shims/FlashCanvas/flashcanvas.swf +0 -0
- data/public/js/webshims/shims/FlashCanvasPro/canvas2png.js +1 -0
- data/public/js/webshims/shims/FlashCanvasPro/flash10canvas.swf +0 -0
- data/public/js/webshims/shims/FlashCanvasPro/flash9canvas.swf +0 -0
- data/public/js/webshims/shims/FlashCanvasPro/flashcanvas.js +1 -0
- data/public/js/webshims/shims/canvas-blob.js +1 -0
- data/public/js/webshims/shims/color-picker.js +2 -0
- data/public/js/webshims/shims/combos/1.js +6 -0
- data/public/js/webshims/shims/combos/10.js +2 -0
- data/public/js/webshims/shims/combos/11.js +2 -0
- data/public/js/webshims/shims/combos/12.js +6 -0
- data/public/js/webshims/shims/combos/13.js +1 -0
- data/public/js/webshims/shims/combos/14.js +1 -0
- data/public/js/webshims/shims/combos/15.js +2 -0
- data/public/js/webshims/shims/combos/16.js +7 -0
- data/public/js/webshims/shims/combos/17.js +2 -0
- data/public/js/webshims/shims/combos/18.js +3 -0
- data/public/js/webshims/shims/combos/2.js +7 -0
- data/public/js/webshims/shims/combos/21.js +2 -0
- data/public/js/webshims/shims/combos/22.js +1 -0
- data/public/js/webshims/shims/combos/23.js +6 -0
- data/public/js/webshims/shims/combos/25.js +2 -0
- data/public/js/webshims/shims/combos/27.js +1 -0
- data/public/js/webshims/shims/combos/28.js +1 -0
- data/public/js/webshims/shims/combos/29.js +1 -0
- data/public/js/webshims/shims/combos/3.js +1 -0
- data/public/js/webshims/shims/combos/30.js +2 -0
- data/public/js/webshims/shims/combos/31.js +1 -0
- data/public/js/webshims/shims/combos/33.js +1 -0
- data/public/js/webshims/shims/combos/34.js +1 -0
- data/public/js/webshims/shims/combos/4.js +1 -0
- data/public/js/webshims/shims/combos/5.js +2 -0
- data/public/js/webshims/shims/combos/6.js +2 -0
- data/public/js/webshims/shims/combos/7.js +7 -0
- data/public/js/webshims/shims/combos/8.js +7 -0
- data/public/js/webshims/shims/combos/9.js +2 -0
- data/public/js/webshims/shims/combos/97.js +1 -0
- data/public/js/webshims/shims/combos/98.js +1 -0
- data/public/js/webshims/shims/combos/99.js +1 -0
- data/public/js/webshims/shims/details.js +1 -0
- data/public/js/webshims/shims/dom-extend.js +1 -0
- data/public/js/webshims/shims/es5.js +1 -0
- data/public/js/webshims/shims/es6.js +1 -0
- data/public/js/webshims/shims/excanvas.js +1 -0
- data/public/js/webshims/shims/filereader-xhr.js +1 -0
- data/public/js/webshims/shims/form-combat.js +1 -0
- data/public/js/webshims/shims/form-core.js +1 -0
- data/public/js/webshims/shims/form-datalist-lazy.js +1 -0
- data/public/js/webshims/shims/form-datalist.js +1 -0
- data/public/js/webshims/shims/form-fixrangechange.js +1 -0
- data/public/js/webshims/shims/form-inputmode.js +1 -0
- data/public/js/webshims/shims/form-message.js +1 -0
- data/public/js/webshims/shims/form-native-extend.js +1 -0
- data/public/js/webshims/shims/form-number-date-api.js +1 -0
- data/public/js/webshims/shims/form-number-date-ui.js +1 -0
- data/public/js/webshims/shims/form-shim-extend.js +1 -0
- data/public/js/webshims/shims/form-shim-extend2.js +1 -0
- data/public/js/webshims/shims/form-validation.js +1 -0
- data/public/js/webshims/shims/form-validators.js +1 -0
- data/public/js/webshims/shims/forms-picker.js +1 -0
- data/public/js/webshims/shims/geolocation.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-ar.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-ch-CN.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-cs.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-de.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-el.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-en.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-es.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-fa.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-fr.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-he.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-hi.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-hu.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-it.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-ja.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-lt.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-nl.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-pl.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-pt-BR.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-pt-PT.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-pt.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-ru.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-sv.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-zh-CN.js +1 -0
- data/public/js/webshims/shims/i18n/formcfg-zh-TW.js +1 -0
- data/public/js/webshims/shims/jme/alternate-media.js +1 -0
- data/public/js/webshims/shims/jme/base.js +1 -0
- data/public/js/webshims/shims/jme/controls.css +1 -0
- data/public/js/webshims/shims/jme/jme.eot +0 -0
- data/public/js/webshims/shims/jme/jme.svg +36 -0
- data/public/js/webshims/shims/jme/jme.ttf +0 -0
- data/public/js/webshims/shims/jme/jme.woff +0 -0
- data/public/js/webshims/shims/jme/mediacontrols-lazy.js +1 -0
- data/public/js/webshims/shims/jme/mediacontrols.js +1 -0
- data/public/js/webshims/shims/jme/playlist.js +1 -0
- data/public/js/webshims/shims/jpicker/images/AlphaBar.png +0 -0
- data/public/js/webshims/shims/jpicker/images/Bars.png +0 -0
- data/public/js/webshims/shims/jpicker/images/Maps.png +0 -0
- data/public/js/webshims/shims/jpicker/images/NoColor.png +0 -0
- data/public/js/webshims/shims/jpicker/images/bar-opacity.png +0 -0
- data/public/js/webshims/shims/jpicker/images/map-opacity.png +0 -0
- data/public/js/webshims/shims/jpicker/images/mappoint.gif +0 -0
- data/public/js/webshims/shims/jpicker/images/picker.gif +0 -0
- data/public/js/webshims/shims/jpicker/images/preview-opacity.png +0 -0
- data/public/js/webshims/shims/jpicker/images/rangearrows.gif +0 -0
- data/public/js/webshims/shims/jpicker/jpicker.css +1 -0
- data/public/js/webshims/shims/matchMedia.js +3 -0
- data/public/js/webshims/shims/mediacapture-picker.js +1 -0
- data/public/js/webshims/shims/mediacapture.js +1 -0
- data/public/js/webshims/shims/mediaelement-core.js +1 -0
- data/public/js/webshims/shims/mediaelement-debug.js +1 -0
- data/public/js/webshims/shims/mediaelement-jaris.js +1 -0
- data/public/js/webshims/shims/mediaelement-native-fix.js +1 -0
- data/public/js/webshims/shims/mediaelement-yt.js +1 -0
- data/public/js/webshims/shims/moxie/flash/Moxie.cdn.swf +0 -0
- data/public/js/webshims/shims/moxie/flash/Moxie.min.swf +0 -0
- data/public/js/webshims/shims/moxie/js/moxie-html4.js +3 -0
- data/public/js/webshims/shims/moxie/js/moxie-swf.js +2 -0
- data/public/js/webshims/shims/picture.js +1 -0
- data/public/js/webshims/shims/plugins/jquery.ui.position.js +11 -0
- data/public/js/webshims/shims/range-ui.js +1 -0
- data/public/js/webshims/shims/sizzle.js +11 -0
- data/public/js/webshims/shims/sticky.js +1 -0
- data/public/js/webshims/shims/styles/color-picker.png +0 -0
- data/public/js/webshims/shims/styles/forms-ext.css +1 -0
- data/public/js/webshims/shims/styles/forms-picker.css +1 -0
- data/public/js/webshims/shims/styles/progress.gif +0 -0
- data/public/js/webshims/shims/styles/progress.png +0 -0
- data/public/js/webshims/shims/styles/shim-ext.css +1 -0
- data/public/js/webshims/shims/styles/shim.css +1 -0
- data/public/js/webshims/shims/styles/transparent.png +0 -0
- data/public/js/webshims/shims/styles/widget.eot +0 -0
- data/public/js/webshims/shims/styles/widget.svg +12 -0
- data/public/js/webshims/shims/styles/widget.ttf +0 -0
- data/public/js/webshims/shims/styles/widget.woff +0 -0
- data/public/js/webshims/shims/swf/JarisFLVPlayer.swf +0 -0
- data/public/js/webshims/shims/swfmini-embed.js +1 -0
- data/public/js/webshims/shims/swfmini.js +6 -0
- data/public/js/webshims/shims/track-ui.js +1 -0
- data/public/js/webshims/shims/track.js +1 -0
- data/public/js/webshims/shims/url.js +1 -0
- data/public/js/webshims/shims/usermedia-core.js +1 -0
- data/public/js/webshims/shims/usermedia-shim.js +1 -0
- data/sequenceserver.gemspec +16 -13
- data/views/400.erb +28 -0
- data/views/500.erb +35 -19
- data/views/_options.erb +6 -15
- data/views/result.erb +218 -0
- data/views/search.erb +354 -151
- metadata +254 -62
- data/example.config.yml +0 -39
- data/lib/sequenceserver/customisation.rb +0 -60
- data/lib/sequenceserver/database_formatter.rb +0 -190
- data/lib/sequenceserver/helpers.rb +0 -136
- data/lib/sequenceserver/sequencehelpers.rb +0 -93
- data/lib/sequenceserver/sinatralikeloggerformatter.rb +0 -12
- data/lib/sequenceserver/version.rb +0 -9
- data/public/css/beige.css.css +0 -254
- data/public/css/bootstrap.dropdown.css +0 -29
- data/public/css/bootstrap.icons.css +0 -155
- data/public/css/bootstrap.modal.css +0 -28
- data/public/js/bootstrap.dropdown.js +0 -92
- data/public/js/bootstrap.modal.js +0 -7
- data/public/js/bootstrap.transition.js +0 -7
- data/public/js/jquery-scrollspy.js +0 -98
- data/public/js/jquery.activity.js +0 -10
- data/public/js/jquery.enablePlaceholder.min.js +0 -10
- data/public/js/store.min.js +0 -2
- data/public/sequence.html +0 -28
- data/tests/database/nucleotide/Sinvicta2-2-3.cdna.subset.fasta +0 -5486
- data/tests/database/nucleotide/Sinvicta2-2-3.cdna.subset.fasta.nhr +0 -0
- data/tests/database/nucleotide/Sinvicta2-2-3.cdna.subset.fasta.nin +0 -0
- data/tests/database/nucleotide/Sinvicta2-2-3.cdna.subset.fasta.nsq +0 -0
- data/tests/database/protein/Sinvicta2-2-3.prot.subset.fasta +0 -6449
- data/tests/database/protein/Sinvicta2-2-3.prot.subset.fasta.phr +0 -0
- data/tests/database/protein/Sinvicta2-2-3.prot.subset.fasta.pin +0 -0
- data/tests/database/protein/Sinvicta2-2-3.prot.subset.fasta.psq +0 -0
- data/tests/run +0 -26
- data/tests/test_sequencehelpers.rb +0 -77
- data/tests/test_sequenceserver_blast.rb +0 -60
- data/tests/test_ui.rb +0 -104
- data/tests/ui.specs.todo +0 -10
@@ -0,0 +1,2419 @@
|
|
1
|
+
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
2
|
+
// legacy!!
|
3
|
+
$.browser = require("jquery-browser-plugin");
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Sequence component
|
7
|
+
*
|
8
|
+
* @class
|
9
|
+
* @extends Biojs
|
10
|
+
*
|
11
|
+
* @author <a href="mailto:johncar@gmail.com">John Gomez</a>, <a href="mailto:secevalliv@gmail.com">Jose Villaveces</a>
|
12
|
+
* @version 1.0.0
|
13
|
+
* @category 3
|
14
|
+
*
|
15
|
+
* @requires <a href='http://blog.jquery.com/2011/09/12/jquery-1-6-4-released/'>jQuery Core 1.6.4</a>
|
16
|
+
* @dependency <script language="JavaScript" type="text/javascript" src="../biojs/dependencies/jquery/jquery-1.4.2.min.js"></script>
|
17
|
+
*
|
18
|
+
* @requires <a href='http://jqueryui.com/download'>jQuery UI 1.8.16</a>
|
19
|
+
* @dependency <script language="JavaScript" type="text/javascript" src="../biojs/dependencies/jquery/jquery-ui-1.8.2.custom.min.js"></script>
|
20
|
+
*
|
21
|
+
* @requires <a href='Biojs.Tooltip.css'>Biojs.Tooltip</a>
|
22
|
+
* @dependency <script language="JavaScript" type="text/javascript" src="src/Biojs.Tooltip.js"></script>
|
23
|
+
*
|
24
|
+
* @param {Object} options An object with the options for Sequence component.
|
25
|
+
*
|
26
|
+
* @option {string} target
|
27
|
+
* Identifier of the DIV tag where the component should be displayed.
|
28
|
+
*
|
29
|
+
* @option {string} sequence
|
30
|
+
* The sequence to be displayed.
|
31
|
+
*
|
32
|
+
* @option {string} [id]
|
33
|
+
* Sequence identifier if apply.
|
34
|
+
*
|
35
|
+
* @option {string} [format="FASTA"]
|
36
|
+
* The display format for the sequence representation.
|
37
|
+
*
|
38
|
+
* @option {Object[]} [highlights]
|
39
|
+
* For highlighting multiple regions.
|
40
|
+
* <pre class="brush: js" title="Syntax:">
|
41
|
+
* [
|
42
|
+
* // Highlight aminoacids from 'start' to 'end' of the current strand using the specified 'color' (optional) and 'background' (optional).
|
43
|
+
* { start: <startVal1>, end: <endVal1> [, id:<idVal1>] [, color: <HTMLColor>] [, background: <HTMLColor>]},
|
44
|
+
* //
|
45
|
+
* // Any others highlights
|
46
|
+
* ...,
|
47
|
+
* //
|
48
|
+
* { start: <startValN>, end: <endValN> [, id:<idValN>] [, color: <HTMLColor>] [, background: <HTMLColor>]}
|
49
|
+
* ]</pre>
|
50
|
+
*
|
51
|
+
* <pre class="brush: js" title="Example:">
|
52
|
+
* highlights : [
|
53
|
+
* { start:30, end:42, color:"white", background:"green", id:"spin1" },
|
54
|
+
* { start:139, end:140 },
|
55
|
+
* { start:631, end:633, color:"white", background:"blue" }
|
56
|
+
* ]
|
57
|
+
* </pre>
|
58
|
+
*
|
59
|
+
* @option {Object} [columns={size:40,spacedEach:10}]
|
60
|
+
* Options for displaying the columns. Syntax: { size: <numCols>, spacedEach: <numCols>}
|
61
|
+
*
|
62
|
+
* @option {Object} [selection]
|
63
|
+
* Positions for the current selected region. Syntax: { start: <startValue>, end: <endValue>}
|
64
|
+
*
|
65
|
+
* @option {Object[]} [annotations]
|
66
|
+
* Set of overlapping annotations. Must be an array of objects following the syntax:
|
67
|
+
* <pre class="brush: js" title="Syntax:">
|
68
|
+
* [
|
69
|
+
* // An annotation:
|
70
|
+
* { name: <name>,
|
71
|
+
* html: <message>,
|
72
|
+
* color: <color_code>,
|
73
|
+
* regions: [{ start: <startVal1>, end: <endVal1> color: <HTMLColor>}, ...,{ start: <startValN>, end: <endValN>, color: <HTMLColor>}]
|
74
|
+
* },
|
75
|
+
*
|
76
|
+
* // ...
|
77
|
+
* // more annotations here
|
78
|
+
* // ...
|
79
|
+
* ]
|
80
|
+
* </pre>
|
81
|
+
* where:
|
82
|
+
* <ul>
|
83
|
+
* <li><b>name</b> is the unique name for the annotation</li>
|
84
|
+
* <li><b>html</b> is the message (can be HTML) to be displayed in the tool tip.</li>
|
85
|
+
* <li><b>color</b> is the default HTML color code for all the regions.</li>
|
86
|
+
* <li><b>regions</b> array of objects defining the intervals which belongs to the annotation.</li>
|
87
|
+
* <li><b>regions[i].start</b> is the starting character for the i-th interval.</li>
|
88
|
+
* <li><b>regions[i].end</b> is the ending character for the i-th interval.</li>
|
89
|
+
* <li><b>regions[i].color</b> is an optional color for the i-th interval.
|
90
|
+
* </ul>
|
91
|
+
*
|
92
|
+
* @option {Object} [formatOptions={title:true, footer:true}]
|
93
|
+
* Options for displaying the title. by now just affecting the CODATA format.
|
94
|
+
* <pre class="brush: js" title="Syntax:">
|
95
|
+
* formatOptions : {
|
96
|
+
* title:false,
|
97
|
+
* footer:false
|
98
|
+
* }
|
99
|
+
* </pre>
|
100
|
+
*
|
101
|
+
* @example
|
102
|
+
* var theSequence = "METLCQRLNVCQDKILTHYENDSTDLRDHIDYWKHMRLECAIYYKAREMGFKHINHQVVPTLAVSKNKALQAIELQLTLETIYNSQYSNEKWTLQDVSLEVYLTAPTGCIKKHGYTVEVQFDGDICNTMHYTNWTHIYICEEAojs SVTVVEGQVDYYGLYYVHEGIRTYFVQFKDDAEKYSKNKVWEVHAGGQVILCPTSVFSSNEVSSPEIIRQHLANHPAATHTKAVALGTEETQTTIQRPRSEPDTGNPCHTTKLLHRDSVDSAPILTAFNSSHKGRINCNSNTTPIVHLKGDANTLKCLRYRFKKHCTLYTAVSSTWHWTGHNVKHKSAIVTLTYDSEWQRDQFLSQVKIPKTITVSTGFMSI";
|
103
|
+
* var mySequence = new Sequence({
|
104
|
+
* sequence : theSequence,
|
105
|
+
* target : "YourOwnDivId",
|
106
|
+
* format : 'CODATA',
|
107
|
+
* id : 'P918283',
|
108
|
+
* annotations: [
|
109
|
+
* { name:"CATH",
|
110
|
+
* color:"#F0F020",
|
111
|
+
* html: "Using color code #F0F020 ",
|
112
|
+
* regions: [{start: 122, end: 135}]
|
113
|
+
* },
|
114
|
+
* { name:"TEST",
|
115
|
+
* html:"<br> Example of <b>HTML</b>",
|
116
|
+
* color:"green",
|
117
|
+
* regions: [
|
118
|
+
* {start: 285, end: 292},
|
119
|
+
* {start: 293, end: 314, color: "#2E4988"}]
|
120
|
+
* }
|
121
|
+
* ],
|
122
|
+
* highlights : [
|
123
|
+
* { start:30, end:42, color:"white", background:"green", id:"spin1" },
|
124
|
+
* { start:139, end:140 },
|
125
|
+
* { start:631, end:633, color:"white", background:"blue" }
|
126
|
+
* ]
|
127
|
+
* });
|
128
|
+
*
|
129
|
+
*/
|
130
|
+
|
131
|
+
var Class = require('js-class');
|
132
|
+
|
133
|
+
var EVT_ON_SELECTION_CHANGE= "onSelectionChange";
|
134
|
+
var EVT_ON_SELECTION_CHANGED= "onSelectionChanged";
|
135
|
+
var EVT_ON_ANNOTATION_CLICKED= "onAnnotationClicked";
|
136
|
+
|
137
|
+
Sequence = Class(
|
138
|
+
/** @lends Sequence# */
|
139
|
+
{
|
140
|
+
constructor: function (options) {
|
141
|
+
var self = this;
|
142
|
+
|
143
|
+
this.opt = jQuery.extend(this.opt,options);
|
144
|
+
|
145
|
+
this._container = jQuery(this.opt.target );
|
146
|
+
|
147
|
+
// legacy support (target id without '#')
|
148
|
+
if(this._container.length == 0){
|
149
|
+
this._container = jQuery( "#" + this.opt.target )
|
150
|
+
}
|
151
|
+
|
152
|
+
if(this._container.length == 0){
|
153
|
+
console.log("empty target container");
|
154
|
+
}
|
155
|
+
|
156
|
+
// legacy: copy target id
|
157
|
+
this.opt.target = this._container[0].id;
|
158
|
+
|
159
|
+
// Lazy initialization
|
160
|
+
this._container.ready(function() {
|
161
|
+
self._initialize();
|
162
|
+
});
|
163
|
+
},
|
164
|
+
|
165
|
+
/**
|
166
|
+
* Default values for the options
|
167
|
+
* @name Sequence-opt
|
168
|
+
*/
|
169
|
+
opt : {
|
170
|
+
|
171
|
+
sequence : "",
|
172
|
+
id : "",
|
173
|
+
target : "",
|
174
|
+
format : "FASTA",
|
175
|
+
selection: { start: 0, end: 0 },
|
176
|
+
columns: { size: 35, spacedEach: 10 },
|
177
|
+
highlights : [],
|
178
|
+
annotations: [],
|
179
|
+
sequenceUrl: 'http://www.ebi.ac.uk/das-srv/uniprot/das/uniprot/sequence',
|
180
|
+
|
181
|
+
// Styles
|
182
|
+
selectionColor : 'Yellow',
|
183
|
+
selectionFontColor : 'black',
|
184
|
+
highlightFontColor : 'red',
|
185
|
+
highlightBackgroundColor : 'white',
|
186
|
+
fontColor : 'inherit',
|
187
|
+
backgroundColor : 'inherit',
|
188
|
+
width: undefined,
|
189
|
+
height: undefined,
|
190
|
+
formatSelectorVisible: true
|
191
|
+
},
|
192
|
+
|
193
|
+
/**
|
194
|
+
* Array containing the supported event names
|
195
|
+
* @name Sequence-eventTypes
|
196
|
+
*/
|
197
|
+
eventTypes : [
|
198
|
+
/**
|
199
|
+
* @name Sequence#onSelectionChanged
|
200
|
+
* @event
|
201
|
+
* @param {function} actionPerformed An function which receives an {@link Biojs.Event} object as argument.
|
202
|
+
* @eventData {Object} source The component which did triggered the event.
|
203
|
+
* @eventData {string} type The name of the event.
|
204
|
+
* @eventData {int} start A number indicating the start of the selection.
|
205
|
+
* @eventData {int} end A number indicating the ending of selection.
|
206
|
+
* @example
|
207
|
+
* mySequence.onSelectionChanged(
|
208
|
+
* function( objEvent ) {
|
209
|
+
* alert("Selected: " + objEvent.start + ", " + objEvent.end );
|
210
|
+
* }
|
211
|
+
* );
|
212
|
+
*
|
213
|
+
* */
|
214
|
+
"onSelectionChanged",
|
215
|
+
|
216
|
+
/**
|
217
|
+
* @name Sequence#onSelectionChange
|
218
|
+
* @event
|
219
|
+
* @param {function} actionPerformed An function which receives an {@link Biojs.Event} object as argument.
|
220
|
+
* @eventData {Object} source The component which did triggered the event.
|
221
|
+
* @eventData {string} type The name of the event.
|
222
|
+
* @eventData {int} start A number indicating the start of the selection.
|
223
|
+
* @eventData {int} end A number indicating the ending of selection.
|
224
|
+
* @example
|
225
|
+
* mySequence.onSelectionChange(
|
226
|
+
* function( objEvent ) {
|
227
|
+
* alert("Selection in progress: " + objEvent.start + ", " + objEvent.end );
|
228
|
+
* }
|
229
|
+
* );
|
230
|
+
*
|
231
|
+
*
|
232
|
+
* */
|
233
|
+
"onSelectionChange",
|
234
|
+
|
235
|
+
/**
|
236
|
+
* @name Sequence#onAnnotationClicked
|
237
|
+
* @event
|
238
|
+
* @param {function} actionPerformed An function which receives an {@link Biojs.Event} object as argument.
|
239
|
+
* @eventData {Object} source The component which did triggered the event.
|
240
|
+
* @eventData {string} type The name of the event.
|
241
|
+
* @eventData {string} name The name of the selected annotation.
|
242
|
+
* @eventData {int} pos A number indicating the position of the selected amino acid.
|
243
|
+
* @example
|
244
|
+
* mySequence.onAnnotationClicked(
|
245
|
+
* function( objEvent ) {
|
246
|
+
* alert("Clicked " + objEvent.name + " on position " + objEvent.pos );
|
247
|
+
* }
|
248
|
+
* );
|
249
|
+
*
|
250
|
+
* */
|
251
|
+
"onAnnotationClicked"
|
252
|
+
],
|
253
|
+
|
254
|
+
getId : function () {
|
255
|
+
return this.opt.id;
|
256
|
+
},
|
257
|
+
|
258
|
+
// internal members
|
259
|
+
_headerDiv : null,
|
260
|
+
_contentDiv : null,
|
261
|
+
|
262
|
+
// Methods
|
263
|
+
|
264
|
+
_initialize: function () {
|
265
|
+
|
266
|
+
if ( this.opt.width !== undefined ) {
|
267
|
+
this._container.width( this.opt.width );
|
268
|
+
}
|
269
|
+
|
270
|
+
if ( this.opt.height !== undefined ) {
|
271
|
+
this._container.height( this.opt.height );
|
272
|
+
}
|
273
|
+
|
274
|
+
// DIV for the format selector
|
275
|
+
this._buildFormatSelector();
|
276
|
+
|
277
|
+
// DIV for the sequence
|
278
|
+
this._contentDiv = jQuery('<div></div>').appendTo(this._container);
|
279
|
+
this._contentDiv.css({
|
280
|
+
'text-align': 'left'
|
281
|
+
});
|
282
|
+
|
283
|
+
// Initialize highlighting
|
284
|
+
this._highlights = this.opt.highlights;
|
285
|
+
|
286
|
+
// Initialize annotations
|
287
|
+
this._annotations = this.opt.annotations;
|
288
|
+
|
289
|
+
//Initialize tooltip
|
290
|
+
var tooltip = "sequenceTip" + this.opt.target ;
|
291
|
+
jQuery('<div id="' + tooltip + '"></div>')
|
292
|
+
.css({
|
293
|
+
'position': "absolute",
|
294
|
+
'z-index': "999999",
|
295
|
+
'color': "#fff",
|
296
|
+
'font-size': "12px",
|
297
|
+
'width': "auto",
|
298
|
+
'display': 'none'
|
299
|
+
})
|
300
|
+
.addClass("tooltip")
|
301
|
+
.appendTo("body")
|
302
|
+
.hide();
|
303
|
+
this.opt._tooltip = document.getElementById(tooltip);
|
304
|
+
|
305
|
+
if ( (this.opt.sequence) ) {
|
306
|
+
this._redraw();
|
307
|
+
|
308
|
+
} else if ( (this.opt.id) ) {
|
309
|
+
this._requestSequence( this.opt.id );
|
310
|
+
|
311
|
+
} else {
|
312
|
+
this.clearSequence("No sequence available", "../biojs/css/images/warning_icon.png");
|
313
|
+
}
|
314
|
+
|
315
|
+
},
|
316
|
+
|
317
|
+
|
318
|
+
/**
|
319
|
+
* Shows the columns indicated by the indexes array.
|
320
|
+
* @param {string} seq The sequence strand.
|
321
|
+
* @param {string} [identifier] Sequence identifier.
|
322
|
+
*
|
323
|
+
* @example
|
324
|
+
* mySequence.setSequence("P99999");
|
325
|
+
*
|
326
|
+
*/
|
327
|
+
setSequence: function ( seq, identifier ) {
|
328
|
+
|
329
|
+
if ( seq.match(/^([A-N,R-Z][0-9][A-Z][A-Z, 0-9][A-Z, 0-9][0-9])|([O,P,Q][0-9][A-Z, 0-9][A-Z, 0-9][A-Z, 0-9][0-9])(\.\d+)?$/i) ) {
|
330
|
+
this._requestSequence( arguments[0] );
|
331
|
+
|
332
|
+
} else {
|
333
|
+
this.opt.sequence = seq;
|
334
|
+
this.opt.id = identifier;
|
335
|
+
this._highlights = [];
|
336
|
+
this._highlightsCount = 0;
|
337
|
+
this.opt.selection = { start: 0, end: 0 };
|
338
|
+
this._annotations = [];
|
339
|
+
|
340
|
+
this._contentDiv.children().remove();
|
341
|
+
this._redraw();
|
342
|
+
}
|
343
|
+
},
|
344
|
+
|
345
|
+
_requestSequence: function ( accession ) {
|
346
|
+
var self = this;
|
347
|
+
|
348
|
+
console.log("Requesting sequence for: " + accession );
|
349
|
+
|
350
|
+
jQuery.ajax({
|
351
|
+
url: self.opt.sequenceUrl,
|
352
|
+
dataType: "xml",
|
353
|
+
data: { segment: accession },
|
354
|
+
success: function ( xml ) {
|
355
|
+
try {
|
356
|
+
|
357
|
+
var sequenceNode = jQuery(xml).find('SEQUENCE:first');
|
358
|
+
self.setSequence( sequenceNode.text(), sequenceNode.attr("id"), sequenceNode.attr("label") );
|
359
|
+
|
360
|
+
} catch (e) {
|
361
|
+
console.log("Error decoding response data: " + e.message );
|
362
|
+
self.clearSequence("No sequence available", "../biojs/css/images/warning_icon.png");
|
363
|
+
}
|
364
|
+
|
365
|
+
},
|
366
|
+
error: function (jqXHR, textStatus, errorThrown) {
|
367
|
+
console.log("Error decoding response data: " + textStatus );
|
368
|
+
self.clearSequence("Error requesting the sequence to the server " + this.url , "../biojs/css/images/warning_icon.png");
|
369
|
+
}
|
370
|
+
});
|
371
|
+
},
|
372
|
+
|
373
|
+
/**
|
374
|
+
* Shows the columns indicated by the indexes array.
|
375
|
+
* @param {string} [showMessage] Message to be showed.
|
376
|
+
* @param {string} [icon] Icon to be showed a side of the message
|
377
|
+
*
|
378
|
+
* @example
|
379
|
+
* mySequence.clearSequence("No sequence available", "../biojs/css/images/warning_icon.png");
|
380
|
+
*
|
381
|
+
*/
|
382
|
+
clearSequence: function ( showMessage, icon ) {
|
383
|
+
|
384
|
+
var message = undefined;
|
385
|
+
|
386
|
+
this.opt.sequence = "";
|
387
|
+
this.opt.id = "";
|
388
|
+
this._highlights = [];
|
389
|
+
this._highlightsCount = 0;
|
390
|
+
this.opt.selection = { start: 0, end: 0 };
|
391
|
+
this._annotations = [];
|
392
|
+
this._contentDiv.children().remove();
|
393
|
+
|
394
|
+
this._headerDiv.hide();
|
395
|
+
|
396
|
+
if ( undefined !== showMessage ) {
|
397
|
+
message = jQuery('<div>' + showMessage + '</div>')
|
398
|
+
.appendTo(this._contentDiv)
|
399
|
+
.addClass("message");
|
400
|
+
|
401
|
+
if ( undefined !== icon ) {
|
402
|
+
message.css({
|
403
|
+
'background': 'transparent url("' + icon + '") no-repeat center left',
|
404
|
+
'padding-left': '20px'
|
405
|
+
});
|
406
|
+
}
|
407
|
+
}
|
408
|
+
},
|
409
|
+
|
410
|
+
/**
|
411
|
+
* Set the current selection in the sequence causing the event {@link Sequence#onSelectionChanged}
|
412
|
+
*
|
413
|
+
* @example
|
414
|
+
* // set selection from the position 100 to 150
|
415
|
+
* mySequence.setSelection(100, 150);
|
416
|
+
*
|
417
|
+
* @param {int} start The starting character of the selection.
|
418
|
+
* @param {int} end The ending character of the selection
|
419
|
+
*/
|
420
|
+
setSelection : function(start, end) {
|
421
|
+
if(start > end) {
|
422
|
+
var aux = end;
|
423
|
+
end = start;
|
424
|
+
start = aux;
|
425
|
+
|
426
|
+
}
|
427
|
+
|
428
|
+
if(start != this.opt.selection.start || end != this.opt.selection.end) {
|
429
|
+
this._setSelection(start, end);
|
430
|
+
this.trigger(
|
431
|
+
EVT_ON_SELECTION_CHANGED,
|
432
|
+
{ "start" : start, "end" : end }
|
433
|
+
);
|
434
|
+
}
|
435
|
+
},
|
436
|
+
|
437
|
+
_buildFormatSelector: function () {
|
438
|
+
var self = this;
|
439
|
+
|
440
|
+
this._headerDiv = jQuery('<div></div>').appendTo(this._container);
|
441
|
+
this._headerDiv.append('Format: ');
|
442
|
+
|
443
|
+
this._formatSelector = jQuery('<select> '+
|
444
|
+
'<option value="FASTA">FASTA</option>'+
|
445
|
+
'<option value="CODATA">CODATA</option>'+
|
446
|
+
'<option value="PRIDE">PRIDE</option>'+
|
447
|
+
'<option value="RAW">RAW</option></select>').appendTo(self._headerDiv);
|
448
|
+
|
449
|
+
this._formatSelector.change(function(e) {
|
450
|
+
self.opt.format = jQuery(this).val();
|
451
|
+
self._redraw();
|
452
|
+
});
|
453
|
+
|
454
|
+
this._formatSelector.val(self.opt.format);
|
455
|
+
|
456
|
+
this.formatSelectorVisible( this.opt.formatSelectorVisible );
|
457
|
+
},
|
458
|
+
|
459
|
+
/**
|
460
|
+
* Highlights a region using the font color defined in {Sequence#highlightFontColor} by default is red.
|
461
|
+
*
|
462
|
+
* @example
|
463
|
+
* // highlight the characters within the position 100 to 150, included.
|
464
|
+
* mySequence.addHighlight( { "start": 100, "end": 150, "color": "white", "background": "red", "id": "aaa" } );
|
465
|
+
*
|
466
|
+
* @param {Object} h The highlight defined as follows:
|
467
|
+
*
|
468
|
+
*
|
469
|
+
* @return {int} representing the id of the highlight on the internal array. Returns -1 on failure
|
470
|
+
*/
|
471
|
+
addHighlight : function ( h ) {
|
472
|
+
var id = '-1';
|
473
|
+
var color = "";
|
474
|
+
var background = "";
|
475
|
+
var highlight = {};
|
476
|
+
|
477
|
+
if ( h instanceof Object && h.start <= h.end ) {
|
478
|
+
|
479
|
+
color = ( "string" == typeof h.color )? h.color : this.opt.highlightFontColor;
|
480
|
+
background = ( "string" == typeof h.background )? h.background : this.opt.highlightBackgroundColor;
|
481
|
+
id = ( "string" == typeof h.id )? h.id : (new Number(this._highlightsCount++)).toString();
|
482
|
+
|
483
|
+
highlight = { "start": h.start, "end": h.end, "color": color, "background": background, "id": id };
|
484
|
+
|
485
|
+
this._highlights.push(highlight);
|
486
|
+
this._applyHighlight(highlight);
|
487
|
+
this._restoreSelection(h.start,h.end);
|
488
|
+
}
|
489
|
+
|
490
|
+
return id;
|
491
|
+
},
|
492
|
+
/*
|
493
|
+
* Function: Sequence._applyHighlight
|
494
|
+
* Purpose: Apply the specified color and background to a region between 'start' and 'end'.
|
495
|
+
* Returns: -
|
496
|
+
* Inputs: highlight -> {Object} An object containing the fields start (int), end (int),
|
497
|
+
* color (HTML color string) and background (HTML color string).
|
498
|
+
*/
|
499
|
+
_applyHighlight: function ( highlight ) {
|
500
|
+
var seq = this._contentDiv.find('.sequence');
|
501
|
+
for ( var i = highlight.start - 1; i < highlight.end; i++ ){
|
502
|
+
zindex = jQuery(seq[i]).css("z-index");
|
503
|
+
if (zindex=="auto"){
|
504
|
+
z = 1;
|
505
|
+
o = 1;
|
506
|
+
}
|
507
|
+
else{
|
508
|
+
z = 0;
|
509
|
+
o = 0.5;
|
510
|
+
}
|
511
|
+
jQuery(seq[i])
|
512
|
+
.css({
|
513
|
+
"color": highlight.color,
|
514
|
+
"background-color": highlight.background,
|
515
|
+
"z-index": z,
|
516
|
+
"opacity": o
|
517
|
+
})
|
518
|
+
.addClass("highlighted");
|
519
|
+
}
|
520
|
+
},
|
521
|
+
/*
|
522
|
+
* Function: Sequence._applyHighlights
|
523
|
+
* Purpose: Apply the specified highlights.
|
524
|
+
* Returns: -
|
525
|
+
* Inputs: highlights -> {Object[]} An array containing the highlights to be applied.
|
526
|
+
*/
|
527
|
+
_applyHighlights: function ( highlights ) {
|
528
|
+
for ( var i in highlights ) {
|
529
|
+
this._applyHighlight(highlights[i]);
|
530
|
+
}
|
531
|
+
},
|
532
|
+
/*
|
533
|
+
* Function: Sequence._restoreHighlights
|
534
|
+
* Purpose: Repaint the highlights in the specified region.
|
535
|
+
* Returns: -
|
536
|
+
* Inputs: start -> {int} Start of the region to be restored.
|
537
|
+
* end -> {int} End of the region to be restored.
|
538
|
+
*/
|
539
|
+
_restoreHighlights: function ( start, end ) {
|
540
|
+
var h = this._highlights;
|
541
|
+
// paint the region using default blank settings
|
542
|
+
this._applyHighlight({
|
543
|
+
"start": start,
|
544
|
+
"end": end,
|
545
|
+
"color": this.opt.fontColor,
|
546
|
+
"background": this.opt.backgroundColor
|
547
|
+
});
|
548
|
+
// restore highlights in that region
|
549
|
+
for ( var i in h ) {
|
550
|
+
// interval intersects with highlight i ?
|
551
|
+
if ( !( h[i].start > end || h[i].end < start ) ) {
|
552
|
+
a = ( h[i].start < start ) ? start : h[i].start;
|
553
|
+
b = ( h[i].end > end ) ? end : h[i].end;
|
554
|
+
this._applyHighlight({
|
555
|
+
"start": a,
|
556
|
+
"end": b,
|
557
|
+
"color": h[i].color,
|
558
|
+
"background": h[i].background
|
559
|
+
});
|
560
|
+
}
|
561
|
+
}
|
562
|
+
},
|
563
|
+
/*
|
564
|
+
* Function: Sequence._restoreSelection
|
565
|
+
* Purpose: Repaint the current selection in the specified region.
|
566
|
+
* It is used in the case of any highlight do overriding of the current selection.
|
567
|
+
* Returns: -
|
568
|
+
* Inputs: start -> {int} Start of the region to be restored.
|
569
|
+
* end -> {int} End of the region to be restored.
|
570
|
+
*/
|
571
|
+
_restoreSelection: function ( start, end ) {
|
572
|
+
var sel = this.opt.selection;
|
573
|
+
// interval intersects with current selection ?
|
574
|
+
// restore selection
|
575
|
+
if ( !( start > sel.end || end < sel.start ) ) {
|
576
|
+
a = ( start < sel.start ) ? sel.start : start;
|
577
|
+
b = ( end > sel.end ) ? sel.end : end;
|
578
|
+
|
579
|
+
this._applyHighlight({
|
580
|
+
"start": a,
|
581
|
+
"end": b,
|
582
|
+
"color": this.opt.selectionFontColor,
|
583
|
+
"background": this.opt.selectionColor,
|
584
|
+
});
|
585
|
+
}
|
586
|
+
},
|
587
|
+
|
588
|
+
/**
|
589
|
+
* Remove a highlight.
|
590
|
+
*
|
591
|
+
* @example
|
592
|
+
* // Clear the highlighted characters within the position 100 to 150, included.
|
593
|
+
* mySequence.removeHighlight("spin1");
|
594
|
+
*
|
595
|
+
* @param {string} id The id of the highlight on the internal array. This value is returned by method highlight.
|
596
|
+
*/
|
597
|
+
removeHighlight : function (id) {
|
598
|
+
var h = this._highlights;
|
599
|
+
for ( i in h ) {
|
600
|
+
if ( h[i].id == id ) {
|
601
|
+
start = h[i].start;
|
602
|
+
end = h[i].end;
|
603
|
+
h.splice(i,1);
|
604
|
+
|
605
|
+
this._restoreHighlights(start,end);
|
606
|
+
this._restoreSelection(start,end);
|
607
|
+
|
608
|
+
break;
|
609
|
+
}
|
610
|
+
}
|
611
|
+
},
|
612
|
+
|
613
|
+
/**
|
614
|
+
* Remove all the highlights of whole sequence.
|
615
|
+
*
|
616
|
+
* @example
|
617
|
+
* mySequence.removeAllHighlights();
|
618
|
+
*/
|
619
|
+
removeAllHighlights : function () {
|
620
|
+
this._highlights = [];
|
621
|
+
this._restoreHighlights(1,this.opt.sequence.length);
|
622
|
+
this._restoreSelection(1,this.opt.sequence.length);
|
623
|
+
},
|
624
|
+
|
625
|
+
/**
|
626
|
+
* Changes the current displaying format of the sequence.
|
627
|
+
*
|
628
|
+
* @example
|
629
|
+
* // Set format to 'FASTA'.
|
630
|
+
* mySequence.setFormat('FASTA');
|
631
|
+
*
|
632
|
+
* @param {string} format The format for the sequence to be displayed.
|
633
|
+
*/
|
634
|
+
setFormat : function(format) {
|
635
|
+
if ( this.opt.format != format.toUpperCase() ) {
|
636
|
+
this.opt.format = format.toUpperCase();
|
637
|
+
this._redraw();
|
638
|
+
}
|
639
|
+
|
640
|
+
var self = this;
|
641
|
+
// Changes the option in the combo box
|
642
|
+
this._headerDiv.find('option').each(function() {
|
643
|
+
if(jQuery(this).val() == self.opt.format.toUpperCase()) {
|
644
|
+
jQuery(this).attr('selected', 'selected');
|
645
|
+
}
|
646
|
+
});
|
647
|
+
},
|
648
|
+
|
649
|
+
/**
|
650
|
+
* Changes the current number of columns in the displayed sequence.
|
651
|
+
*
|
652
|
+
* @example
|
653
|
+
* // Set the number of columns to 70.
|
654
|
+
* mySequence.setNumCols(70);
|
655
|
+
*
|
656
|
+
* @param {int} numCols The number of columns.
|
657
|
+
*/
|
658
|
+
setNumCols : function(numCols) {
|
659
|
+
this.opt.columns.size = numCols;
|
660
|
+
this._redraw();
|
661
|
+
},
|
662
|
+
|
663
|
+
/**
|
664
|
+
* Set the visibility of the drop-down list of formats.
|
665
|
+
*
|
666
|
+
* @param {boolean} visible true: show; false: hide.
|
667
|
+
*/
|
668
|
+
formatSelectorVisible : function (visible){
|
669
|
+
if (visible) {
|
670
|
+
this._headerDiv.show();
|
671
|
+
} else {
|
672
|
+
this._headerDiv.hide();
|
673
|
+
}
|
674
|
+
},
|
675
|
+
|
676
|
+
/**
|
677
|
+
* This is similar to a {Biojs.Protein3D#formatSelectorVisible} with the 'true' argument.
|
678
|
+
*
|
679
|
+
* @example
|
680
|
+
* // Shows the format selector.
|
681
|
+
* mySequence.showFormatSelector();
|
682
|
+
*
|
683
|
+
*/
|
684
|
+
showFormatSelector : function() {
|
685
|
+
this._headerDiv.show();
|
686
|
+
},
|
687
|
+
|
688
|
+
/**
|
689
|
+
* This is similar to a {Biojs.Protein3D#formatSelectorVisible} with the 'false' argument.
|
690
|
+
*
|
691
|
+
* @example
|
692
|
+
* // Hides the format selector.
|
693
|
+
* mySequence.hideFormatSelector();
|
694
|
+
*
|
695
|
+
*/
|
696
|
+
hideFormatSelector : function() {
|
697
|
+
this._headerDiv.hide();
|
698
|
+
},
|
699
|
+
|
700
|
+
/**
|
701
|
+
* Hides the whole component.
|
702
|
+
*
|
703
|
+
*/
|
704
|
+
hide : function () {
|
705
|
+
this._headerDiv.hide();
|
706
|
+
this._contentDiv.hide();
|
707
|
+
},
|
708
|
+
|
709
|
+
/**
|
710
|
+
* Shows the whole component.
|
711
|
+
*
|
712
|
+
*/
|
713
|
+
show : function () {
|
714
|
+
this._headerDiv.show();
|
715
|
+
this._contentDiv.show();
|
716
|
+
},
|
717
|
+
/*
|
718
|
+
* Function: Sequence._setSelection
|
719
|
+
* Purpose: Update the current selection.
|
720
|
+
* Returns: -
|
721
|
+
* Inputs: start -> {int} Start of the region to be selected.
|
722
|
+
* end -> {int} End of the region to be selected.
|
723
|
+
*/
|
724
|
+
_setSelection : function(start, end) {
|
725
|
+
//alert("adsas");
|
726
|
+
|
727
|
+
var current = this.opt.selection;
|
728
|
+
var change = {};
|
729
|
+
|
730
|
+
// Which is the change on selection?
|
731
|
+
if ( current.start == start ) {
|
732
|
+
// forward?
|
733
|
+
if ( current.end < end ) {
|
734
|
+
change.start = current.end;
|
735
|
+
change.end = end;
|
736
|
+
} else {
|
737
|
+
this._restoreHighlights(end+1, current.end);
|
738
|
+
}
|
739
|
+
} else if ( current.end == end ) {
|
740
|
+
// forward?
|
741
|
+
if ( current.start > start ) {
|
742
|
+
change.start = start;
|
743
|
+
change.end = current.start;
|
744
|
+
} else {
|
745
|
+
this._restoreHighlights(current.start, start-1);
|
746
|
+
}
|
747
|
+
} else {
|
748
|
+
this._restoreHighlights(current.start, current.end);
|
749
|
+
change.start = start;
|
750
|
+
change.end = end;
|
751
|
+
}
|
752
|
+
|
753
|
+
current.start = start;
|
754
|
+
current.end = end;
|
755
|
+
},
|
756
|
+
|
757
|
+
/*
|
758
|
+
* Function: Sequence._repaintSelection
|
759
|
+
* Purpose: Repaint the whole current selection.
|
760
|
+
* Returns: -
|
761
|
+
* Inputs: -
|
762
|
+
*/
|
763
|
+
_repaintSelection: function(){
|
764
|
+
var s = this.opt.selection;
|
765
|
+
this._setSelection(0,0);
|
766
|
+
this._setSelection(s.start,s.end);
|
767
|
+
},
|
768
|
+
|
769
|
+
/*
|
770
|
+
* Function: Sequence._redraw
|
771
|
+
* Purpose: Repaint the current sequence.
|
772
|
+
* Returns: -
|
773
|
+
* Inputs: -
|
774
|
+
*/
|
775
|
+
_redraw : function() {
|
776
|
+
var i = 0;
|
777
|
+
var self = this;
|
778
|
+
|
779
|
+
// Reset the content
|
780
|
+
//this._contentDiv.text('');
|
781
|
+
this._contentDiv.children().remove();
|
782
|
+
|
783
|
+
// Rebuild the spans of the sequence
|
784
|
+
// according to format
|
785
|
+
if(this.opt.format == 'RAW') {
|
786
|
+
this._drawRaw();
|
787
|
+
} else if(this.opt.format == 'CODATA') {
|
788
|
+
this._drawCodata();
|
789
|
+
} else if (this.opt.format == 'FASTA'){
|
790
|
+
this._drawFasta();
|
791
|
+
} else {
|
792
|
+
this.opt.format = 'PRIDE';
|
793
|
+
this._drawPride();
|
794
|
+
}
|
795
|
+
|
796
|
+
// Restore the highlighted regions
|
797
|
+
this._applyHighlights(this._highlights);
|
798
|
+
this._repaintSelection();
|
799
|
+
this._addSpanEvents();
|
800
|
+
},
|
801
|
+
/*
|
802
|
+
* Function: Sequence._drawFasta
|
803
|
+
* Purpose: Repaint the current sequence using FASTA format.
|
804
|
+
* Returns: -
|
805
|
+
* Inputs: -
|
806
|
+
*/
|
807
|
+
_drawFasta : function() {
|
808
|
+
var self = this;
|
809
|
+
var a = this.opt.sequence.toUpperCase().split('');
|
810
|
+
var pre = jQuery('<pre></pre>').appendTo(this._contentDiv);
|
811
|
+
|
812
|
+
var i = 1;
|
813
|
+
var arr = [];
|
814
|
+
var str = '>' + this.opt.id + ' ' + a.length + ' bp<br/>';
|
815
|
+
|
816
|
+
/* Correct column size in case the sequence is as small peptide */
|
817
|
+
var numCols = this.opt.columns.size;
|
818
|
+
if ( this.opt.sequence.length < this.opt.columns.size ) {
|
819
|
+
numCols = this.opt.sequence.length;
|
820
|
+
}
|
821
|
+
|
822
|
+
var opt = {
|
823
|
+
numCols: numCols,
|
824
|
+
numColsForSpace: 0
|
825
|
+
};
|
826
|
+
|
827
|
+
str += this._drawSequence(a, opt);
|
828
|
+
pre.html(str);
|
829
|
+
|
830
|
+
this._drawAnnotations(opt);
|
831
|
+
},
|
832
|
+
/*
|
833
|
+
* Function: Sequence._drawCodata
|
834
|
+
* Purpose: Repaint the current sequence using CODATA format.
|
835
|
+
* Returns: -
|
836
|
+
* Inputs: -
|
837
|
+
*/
|
838
|
+
_drawCodata : function() {
|
839
|
+
|
840
|
+
var self = this;
|
841
|
+
var a = this.opt.sequence.toUpperCase().split('');
|
842
|
+
var pre = jQuery('<pre/>').appendTo(this._contentDiv);
|
843
|
+
|
844
|
+
var i = 0;
|
845
|
+
var str = 'ENTRY ' + this.opt.id + '<br/>';
|
846
|
+
str += 'SEQUENCE<br/>';
|
847
|
+
if ( this.opt.formatOptions !== undefined ){
|
848
|
+
if(this.opt.formatOptions.title !== undefined ){
|
849
|
+
if (this.opt.formatOptions.title == false) {
|
850
|
+
str = '';
|
851
|
+
}
|
852
|
+
}
|
853
|
+
}
|
854
|
+
|
855
|
+
/* Correct column size in case the sequence is as small peptide */
|
856
|
+
var numCols = this.opt.columns.size;
|
857
|
+
if ( this.opt.sequence.length < this.opt.columns.size ) {
|
858
|
+
numCols = this.opt.sequence.length;
|
859
|
+
}
|
860
|
+
|
861
|
+
var opt = {
|
862
|
+
numLeft: true,
|
863
|
+
numLeftSize: 7,
|
864
|
+
numLeftPad:' ',
|
865
|
+
numTop: true,
|
866
|
+
numTopEach: 5,
|
867
|
+
numCols: numCols,
|
868
|
+
numColsForSpace: 0,
|
869
|
+
spaceBetweenChars: true
|
870
|
+
};
|
871
|
+
|
872
|
+
str += this._drawSequence(a, opt);
|
873
|
+
|
874
|
+
var footer = '<br/>///';
|
875
|
+
if (this.opt.formatOptions !== undefined) {
|
876
|
+
if (this.opt.formatOptions.footer !== undefined) {
|
877
|
+
if (this.opt.formatOptions.footer == false) {
|
878
|
+
footer = '';
|
879
|
+
}
|
880
|
+
}
|
881
|
+
}
|
882
|
+
str += footer;
|
883
|
+
pre.html(str);
|
884
|
+
|
885
|
+
this._drawAnnotations(opt);
|
886
|
+
},
|
887
|
+
/*
|
888
|
+
* Function: Sequence._drawAnnotations
|
889
|
+
* Purpose: Paint the annotations on the sequence.
|
890
|
+
* Returns: -
|
891
|
+
* Inputs: settings -> {object}
|
892
|
+
*/
|
893
|
+
_drawAnnotations: function ( settings ){
|
894
|
+
|
895
|
+
var self = this;
|
896
|
+
var a = this.opt.sequence.toLowerCase().split('');
|
897
|
+
var annotations = this._annotations;
|
898
|
+
var leftSpaces = '';
|
899
|
+
var row = '';
|
900
|
+
var annot = '';
|
901
|
+
|
902
|
+
// Index at the left?
|
903
|
+
if ( settings.numLeft ) {
|
904
|
+
leftSpaces += this._formatIndex(' ', settings.numLeftSize+2, ' ');
|
905
|
+
}
|
906
|
+
|
907
|
+
for ( var i = 0; i < a.length; i += settings.numCols ){
|
908
|
+
row = '';
|
909
|
+
for ( var key in annotations ){
|
910
|
+
annotations[key].id = this.getId() + "_" + key;
|
911
|
+
annot = this._getHTMLRowAnnot(i+1, annotations[key], settings);
|
912
|
+
if (annot.length > 0) {
|
913
|
+
row += '<br/>';
|
914
|
+
row += leftSpaces;
|
915
|
+
row += annot;
|
916
|
+
row += '<br/>';
|
917
|
+
}
|
918
|
+
}
|
919
|
+
|
920
|
+
var numCols = settings.numCols;
|
921
|
+
var charRemaining = a.length-i;
|
922
|
+
if(charRemaining < numCols){
|
923
|
+
numCols = charRemaining;
|
924
|
+
}
|
925
|
+
|
926
|
+
if ( settings.numRight ) {
|
927
|
+
jQuery(row).insertAfter('div#'+self.opt.target+' div pre span#numRight_' + this.getId() + '_' + (i + numCols) );
|
928
|
+
} else {
|
929
|
+
jQuery(row).insertAfter('div#'+self.opt.target+' div pre span#'+ this.getId() + '_' + (i + numCols) );
|
930
|
+
}
|
931
|
+
}
|
932
|
+
|
933
|
+
// add tool tips and background' coloring effect
|
934
|
+
jQuery(this._contentDiv).find('.annotation').each( function(){
|
935
|
+
self._addToolTip( this, function() {
|
936
|
+
return self._getAnnotationString( jQuery(this).attr("id") );
|
937
|
+
});
|
938
|
+
|
939
|
+
jQuery(this).mouseover(function(e) {
|
940
|
+
jQuery('.annotation.'+jQuery(e.target).attr("id")).each(function(){
|
941
|
+
jQuery(this).css("background-color", jQuery(this).attr("color") );
|
942
|
+
});
|
943
|
+
}).mouseout(function() {
|
944
|
+
jQuery('.annotation').css("background-color", "transparent");
|
945
|
+
|
946
|
+
}).click(function(e) {
|
947
|
+
var name = undefined;
|
948
|
+
var id = jQuery(e.target).attr("id");
|
949
|
+
for(var i =0; i < self._annotations.length;i++){
|
950
|
+
if(self._annotations[i].id == id){
|
951
|
+
name = self._annotations[i].name;
|
952
|
+
continue;
|
953
|
+
}
|
954
|
+
}
|
955
|
+
self.trigger( EVT_ON_ANNOTATION_CLICKED, {
|
956
|
+
"name": name,
|
957
|
+
//"pos": parseInt( jQuery(e.target).attr("pos") )
|
958
|
+
});
|
959
|
+
});
|
960
|
+
|
961
|
+
});
|
962
|
+
|
963
|
+
},
|
964
|
+
/*
|
965
|
+
* Function: Sequence._getAnnotationString
|
966
|
+
* Purpose: Get the annotation text message for the tooltip
|
967
|
+
* Returns: {string} Annotation text for the annotation
|
968
|
+
* Inputs: id -> {int} index of the internal annotation array
|
969
|
+
*/
|
970
|
+
_getAnnotationString: function ( id ) {
|
971
|
+
var annotation = this._annotations[id.substr(id.indexOf("_") + 1)];
|
972
|
+
return annotation.name + "<br/>" + ((annotation.html)? annotation.html : '');
|
973
|
+
},
|
974
|
+
|
975
|
+
/*
|
976
|
+
* Function: Sequence._getHTMLRowAnnot
|
977
|
+
* Purpose: Build an annotation
|
978
|
+
* Returns: HTML of the annotation
|
979
|
+
* Inputs: currentPos -> {int}
|
980
|
+
* annotation -> {Object}
|
981
|
+
* settings -> {Object}
|
982
|
+
*/
|
983
|
+
_getHTMLRowAnnot : function (currentPos, annotation, settings) {
|
984
|
+
var styleBegin = 'border-left:1px solid; border-bottom:1px solid; border-color:';
|
985
|
+
var styleOn = 'border-bottom:1px solid; border-color:';
|
986
|
+
var styleEnd = 'border-bottom:1px solid; border-right:1px solid; border-color:';
|
987
|
+
var styleBeginAndEnd = 'border-left:1px solid; border-right:1px solid; border-bottom:1px solid; border-color:';
|
988
|
+
|
989
|
+
var row = [];
|
990
|
+
var end = (currentPos + settings.numCols);
|
991
|
+
var spaceBetweenChars = (settings.spaceBetweenChars)? ' ' : '';
|
992
|
+
var defaultColor = annotation.color;
|
993
|
+
var id = annotation.id;
|
994
|
+
for ( var pos=currentPos; pos < end ; pos++ ) {
|
995
|
+
// regions
|
996
|
+
for ( var r in annotation.regions ) {
|
997
|
+
region = annotation.regions[r];
|
998
|
+
|
999
|
+
spaceAfter = '';
|
1000
|
+
spaceAfter += (pos % settings.numColsForSpace == 0 )? ' ' : '';
|
1001
|
+
spaceAfter += spaceBetweenChars;
|
1002
|
+
|
1003
|
+
color = ((region.color)? region.color : defaultColor);
|
1004
|
+
data = 'class="annotation '+id+'" id="'+id+'" color="'+color+'" pos="'+pos+'"';
|
1005
|
+
|
1006
|
+
if ( pos == region.start && pos == region.end) {
|
1007
|
+
row[pos] = '<span style="'+styleBeginAndEnd+color+'" '+data+'> ';
|
1008
|
+
row[pos] += spaceAfter;
|
1009
|
+
row[pos] += '</span>';
|
1010
|
+
} else if ( pos == region.start ) {
|
1011
|
+
row[pos] = '<span style="'+styleBegin+color+'" '+data+'> ';
|
1012
|
+
row[pos] += spaceAfter;
|
1013
|
+
row[pos] += '</span>';
|
1014
|
+
} else if ( pos == region.end ) {
|
1015
|
+
row[pos] = '<span style="'+styleEnd+color+' " '+data+'> ';
|
1016
|
+
//row[pos] += spaceAfter;
|
1017
|
+
row[pos] += '</span>';
|
1018
|
+
} else if ( pos > region.start && pos < region.end ) {
|
1019
|
+
row[pos] = '<span style="'+styleOn+color+'" '+data+'> ';
|
1020
|
+
row[pos] += spaceAfter;
|
1021
|
+
row[pos] += '</span>';
|
1022
|
+
} else if (!row[pos]) {
|
1023
|
+
row[pos] = ' ';
|
1024
|
+
row[pos] += spaceAfter;
|
1025
|
+
}
|
1026
|
+
}
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
var str = row.join("");
|
1030
|
+
|
1031
|
+
return ( str.indexOf("span") == -1 )? "" : str;
|
1032
|
+
},
|
1033
|
+
/*
|
1034
|
+
* Function: Sequence._drawRaw
|
1035
|
+
* Purpose: Repaint the current sequence using RAW format.
|
1036
|
+
* Returns: -
|
1037
|
+
* Inputs: -
|
1038
|
+
*/
|
1039
|
+
_drawRaw : function() {
|
1040
|
+
var self = this;
|
1041
|
+
var a = this.opt.sequence.toLowerCase().split('');
|
1042
|
+
var i = 0;
|
1043
|
+
var arr = [];
|
1044
|
+
var pre = jQuery('<pre></pre>').appendTo(this._contentDiv);
|
1045
|
+
|
1046
|
+
/* Correct column size in case the sequence is as small peptide */
|
1047
|
+
var numCols = this.opt.columns.size;
|
1048
|
+
if ( this.opt.sequence.length < this.opt.columns.size ) {
|
1049
|
+
numCols = this.opt.sequence.length;
|
1050
|
+
}
|
1051
|
+
|
1052
|
+
var opt = {
|
1053
|
+
numCols: numCols
|
1054
|
+
};
|
1055
|
+
|
1056
|
+
pre.html(
|
1057
|
+
this._drawSequence(a, opt)
|
1058
|
+
);
|
1059
|
+
|
1060
|
+
this._drawAnnotations(opt);
|
1061
|
+
},
|
1062
|
+
/*
|
1063
|
+
* Function: Sequence._drawPride
|
1064
|
+
* Purpose: Repaint the current sequence using PRIDE format.
|
1065
|
+
* Returns: -
|
1066
|
+
* Inputs: -
|
1067
|
+
*/
|
1068
|
+
_drawPride : function() {
|
1069
|
+
var self = this;
|
1070
|
+
var a = this.opt.sequence.toUpperCase().split('');
|
1071
|
+
var pre = jQuery('<pre></pre>').appendTo(this._contentDiv);
|
1072
|
+
|
1073
|
+
/* Correct column size in case the sequence is as small peptide */
|
1074
|
+
var numCols = this.opt.columns.size;
|
1075
|
+
if ( this.opt.sequence.length < this.opt.columns.size ) {
|
1076
|
+
numCols = this.opt.sequence.length;
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
opt = {
|
1080
|
+
numLeft: true,
|
1081
|
+
numLeftSize: 5,
|
1082
|
+
numLeftPad:'0',
|
1083
|
+
numRight: true,
|
1084
|
+
numRightSize: 5,
|
1085
|
+
numRightPad: '0',
|
1086
|
+
numCols: numCols,
|
1087
|
+
numColsForSpace: self.opt.columns.spacedEach
|
1088
|
+
};
|
1089
|
+
|
1090
|
+
pre.html(
|
1091
|
+
this._drawSequence(a, opt)
|
1092
|
+
);
|
1093
|
+
|
1094
|
+
this._drawAnnotations(opt);
|
1095
|
+
},
|
1096
|
+
/*
|
1097
|
+
* Function: Sequence._drawSequence
|
1098
|
+
* Purpose: Repaint the current sequence using CUSTOM format.
|
1099
|
+
* Returns: -
|
1100
|
+
* Inputs: a -> {char[]} a The sequence strand.
|
1101
|
+
* opt -> {Object} opt The CUSTOM format.
|
1102
|
+
*/
|
1103
|
+
_drawSequence : function(a, opt) {
|
1104
|
+
var str = '';
|
1105
|
+
|
1106
|
+
// Index at top?
|
1107
|
+
if( opt.numTop )
|
1108
|
+
{
|
1109
|
+
str += '<span class="numTop pos-marker">'
|
1110
|
+
var size = (opt.spaceBetweenChars)? opt.numTopEach*2: opt.numTopEach;
|
1111
|
+
|
1112
|
+
if (opt.numLeft) {
|
1113
|
+
str += this._formatIndex(' ', opt.numLeftSize, ' ');
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
str += this._formatIndex(' ', size, ' ');
|
1117
|
+
|
1118
|
+
for(var x = opt.numTopEach; x < opt.numCols; x += opt.numTopEach) {
|
1119
|
+
str += this._formatIndex(x, size, ' ', true);
|
1120
|
+
}
|
1121
|
+
str += '</span>'
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
|
1125
|
+
// Index at the left?
|
1126
|
+
if (opt.numLeft) {
|
1127
|
+
str += '<span id="numLeft_' + this.getId() + '_' + 0 + '"';
|
1128
|
+
str += 'class="pos-marker">'
|
1129
|
+
str += this._formatIndex(1, opt.numLeftSize, opt.numLeftPad);
|
1130
|
+
str += ' ';
|
1131
|
+
str += '</span>';
|
1132
|
+
}
|
1133
|
+
|
1134
|
+
var j=1;
|
1135
|
+
for (var i=1; i <= a.length; i++) {
|
1136
|
+
|
1137
|
+
if( i % opt.numCols == 0) {
|
1138
|
+
str += '<span class="sequence" id="' + this.getId() + '_' + i + '">' + a[i-1] + '</span>';
|
1139
|
+
|
1140
|
+
if (opt.numRight) {
|
1141
|
+
str += '<span id="numRight_' + this.getId() + '_' + i + '"';
|
1142
|
+
str += 'class="pos-marker">'
|
1143
|
+
str += ' ';
|
1144
|
+
str += this._formatIndex(i, opt.numRightSize, opt.numRightPad);
|
1145
|
+
str += '</span>';
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
str += '<br/>';
|
1149
|
+
|
1150
|
+
var aaRemaining = a.length - i;
|
1151
|
+
if (opt.numLeft && aaRemaining > 0) {
|
1152
|
+
str += '<span id="numLeft_' + this.getId() + '_' + i + '"';
|
1153
|
+
str += 'class="pos-marker">'
|
1154
|
+
str += this._formatIndex(i+1, opt.numLeftSize, opt.numLeftPad);
|
1155
|
+
str += ' ';
|
1156
|
+
str += '</span>';
|
1157
|
+
}
|
1158
|
+
|
1159
|
+
j = 1;
|
1160
|
+
|
1161
|
+
} else {
|
1162
|
+
str += '<span class="sequence" id="' + this.getId() + '_' + i + '">' + a[i-1];
|
1163
|
+
str += ( j % opt.numColsForSpace == 0)? ' ' : '';
|
1164
|
+
str += (opt.spaceBetweenChars)? ' ' : '';
|
1165
|
+
str += '</span>';
|
1166
|
+
j++;
|
1167
|
+
}
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
str += '<br/>'
|
1171
|
+
|
1172
|
+
if (jQuery.browser.msie) {
|
1173
|
+
str = "<pre>" + str + "</pre>";
|
1174
|
+
}
|
1175
|
+
|
1176
|
+
return str;
|
1177
|
+
},
|
1178
|
+
/*
|
1179
|
+
* Function: Sequence._formatIndex
|
1180
|
+
* Purpose: Build the HTML corresponding to counting numbers (top, left, right) in the strand.
|
1181
|
+
* Returns: -
|
1182
|
+
* Inputs: number -> {int} The number
|
1183
|
+
* size -> {int} Number of bins to suit the number.
|
1184
|
+
* fillingChar -> {char} Character to be used for filling out blank bins.
|
1185
|
+
* alignLeft -> {bool} Tell if aligned to the left.
|
1186
|
+
*/
|
1187
|
+
_formatIndex : function( number, size, fillingChar, alignLeft) {
|
1188
|
+
var str = number.toString();
|
1189
|
+
var filling = '';
|
1190
|
+
var padding = size - str.length;
|
1191
|
+
if ( padding > 0 ) {
|
1192
|
+
while ( padding-- > 0 ) {
|
1193
|
+
filling += ("<span>"+fillingChar+"</span>");
|
1194
|
+
}
|
1195
|
+
if (alignLeft){
|
1196
|
+
str = number+filling;
|
1197
|
+
} else {
|
1198
|
+
str = filling+number;
|
1199
|
+
}
|
1200
|
+
}
|
1201
|
+
return str;
|
1202
|
+
},
|
1203
|
+
/*
|
1204
|
+
* Function: Sequence._addSpanEvents
|
1205
|
+
* Purpose: Add the event handlers to the strand.
|
1206
|
+
* Returns: -
|
1207
|
+
* Inputs: -
|
1208
|
+
*/
|
1209
|
+
_addSpanEvents : function() {
|
1210
|
+
var self = this;
|
1211
|
+
var isMouseDown = false;
|
1212
|
+
var clickPos;
|
1213
|
+
var currentPos;
|
1214
|
+
|
1215
|
+
self._contentDiv.find('.sequence').each( function () {
|
1216
|
+
|
1217
|
+
// Register the starting position
|
1218
|
+
jQuery(this).mousedown(function() {
|
1219
|
+
var id = jQuery(this).attr('id');
|
1220
|
+
currentPos = parseInt(id.substr(id.indexOf("_") + 1));
|
1221
|
+
clickPos = currentPos;
|
1222
|
+
self._setSelection(clickPos,currentPos);
|
1223
|
+
isMouseDown = true;
|
1224
|
+
|
1225
|
+
// Selection is happening, raise an event
|
1226
|
+
self.trigger(
|
1227
|
+
EVT_ON_SELECTION_CHANGE,
|
1228
|
+
{
|
1229
|
+
"start" : self.opt.selection.start,
|
1230
|
+
"end" : self.opt.selection.end
|
1231
|
+
}
|
1232
|
+
);
|
1233
|
+
|
1234
|
+
}).mouseover(function() {
|
1235
|
+
// Update selection
|
1236
|
+
// Show tooltip containing the position
|
1237
|
+
var id = jQuery(this).attr('id');
|
1238
|
+
currentPos = parseInt(id.substr(id.indexOf("_") + 1));
|
1239
|
+
|
1240
|
+
if(isMouseDown) {
|
1241
|
+
if( currentPos > clickPos ) {
|
1242
|
+
self._setSelection(clickPos, currentPos);
|
1243
|
+
} else {
|
1244
|
+
self._setSelection(currentPos, clickPos);
|
1245
|
+
}
|
1246
|
+
|
1247
|
+
// Selection is happening, raise an event
|
1248
|
+
self.trigger( EVT_ON_SELECTION_CHANGE, {
|
1249
|
+
"start" : self.opt.selection.start,
|
1250
|
+
"end" : self.opt.selection.end
|
1251
|
+
});
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
}).mouseup(function() {
|
1255
|
+
isMouseDown = false;
|
1256
|
+
// Selection is done, raise an event
|
1257
|
+
self.trigger( EVT_ON_SELECTION_CHANGED, {
|
1258
|
+
"start" : self.opt.selection.start,
|
1259
|
+
"end" : self.opt.selection.end
|
1260
|
+
});
|
1261
|
+
});
|
1262
|
+
|
1263
|
+
// Add a tooltip for this sequence base.
|
1264
|
+
self._addToolTip.call( self, this, function( ) {
|
1265
|
+
if (isMouseDown) {
|
1266
|
+
return "[" + self.opt.selection.start +", " + self.opt.selection.end + "]";
|
1267
|
+
} else {
|
1268
|
+
return currentPos;
|
1269
|
+
}
|
1270
|
+
});
|
1271
|
+
|
1272
|
+
})
|
1273
|
+
.css('cursor', 'pointer');
|
1274
|
+
},
|
1275
|
+
/*
|
1276
|
+
* Function: Sequence._addTooltip
|
1277
|
+
* Purpose: Add a tooltip around the target DOM element provided as argument
|
1278
|
+
* Returns: -
|
1279
|
+
* Inputs: target -> {Element} DOM element wich is the targeted focus for the tooltip.
|
1280
|
+
* cbGetMessageFunction -> {function} A callback function wich returns the message to be displayed in the tip.
|
1281
|
+
*/
|
1282
|
+
_addToolTip : function ( target, cbGetMessageFunction ) {
|
1283
|
+
|
1284
|
+
var tipId = this.opt._tooltip;
|
1285
|
+
|
1286
|
+
jQuery(target).mouseover(function(e) {
|
1287
|
+
|
1288
|
+
var offset = jQuery(e.target).offset();
|
1289
|
+
|
1290
|
+
if ( ! jQuery( tipId ).is(':visible') ) {
|
1291
|
+
jQuery( tipId )
|
1292
|
+
.css({
|
1293
|
+
'background-color': "#000",
|
1294
|
+
'padding': "3px 10px 3px 10px",
|
1295
|
+
'top': offset.top + jQuery(e.target).height() + "px",
|
1296
|
+
'left': offset.left + jQuery(e.target).width() + "px"
|
1297
|
+
})
|
1298
|
+
.animate( {opacity: '0.85'}, 10)
|
1299
|
+
.html( cbGetMessageFunction.call( target ) )
|
1300
|
+
.show();
|
1301
|
+
}
|
1302
|
+
|
1303
|
+
}).mouseout(function() {
|
1304
|
+
//Remove the appended tooltip template
|
1305
|
+
jQuery( tipId ).hide();
|
1306
|
+
});
|
1307
|
+
},
|
1308
|
+
|
1309
|
+
/**
|
1310
|
+
* Annotate a set of intervals provided in the argument.
|
1311
|
+
*
|
1312
|
+
* @example
|
1313
|
+
* // Annotations using regions with different colors.
|
1314
|
+
* mySequence.addAnnotation({
|
1315
|
+
* name:"UNIPROT",
|
1316
|
+
* html:"<br> Example of <b>HTML</b>",
|
1317
|
+
* color:"green",
|
1318
|
+
* regions: [
|
1319
|
+
* {start: 540, end: 560},
|
1320
|
+
* {start: 561, end:580, color: "#FFA010"},
|
1321
|
+
* {start: 581, end:590, color: "red"},
|
1322
|
+
* {start: 690, end:710}]
|
1323
|
+
* });
|
1324
|
+
*
|
1325
|
+
*
|
1326
|
+
* @param {Object} annotation The intervals belonging to the same annotation.
|
1327
|
+
* Syntax: { name: <value>, color: <HTMLColorCode>, html: <HTMLString>, regions: [{ start: <startVal1>, end: <endVal1>}, ..., { start: <startValN>, end: <endValN>}] }
|
1328
|
+
*/
|
1329
|
+
addAnnotation: function ( annotation ) {
|
1330
|
+
this._annotations.push(annotation);
|
1331
|
+
this._redraw();
|
1332
|
+
},
|
1333
|
+
|
1334
|
+
/**
|
1335
|
+
* Removes an annotation by means of its name.
|
1336
|
+
*
|
1337
|
+
* @example
|
1338
|
+
* // Remove the UNIPROT annotation.
|
1339
|
+
* mySequence.removeAnnotation('UNIPROT');
|
1340
|
+
*
|
1341
|
+
* @param {string} name The name of the annotation to be removed.
|
1342
|
+
*
|
1343
|
+
*/
|
1344
|
+
removeAnnotation: function ( name ) {
|
1345
|
+
for (var i=0; i < this._annotations.length ; i++ ){
|
1346
|
+
if(name != this._annotations[i].name){
|
1347
|
+
this._annotations.splice(i,1);
|
1348
|
+
this._redraw();
|
1349
|
+
break;
|
1350
|
+
}
|
1351
|
+
}
|
1352
|
+
},
|
1353
|
+
/**
|
1354
|
+
* Removes all the current annotations.
|
1355
|
+
*
|
1356
|
+
* @example
|
1357
|
+
* mySequence.removeAllAnnotations();
|
1358
|
+
*
|
1359
|
+
*/
|
1360
|
+
removeAllAnnotations: function () {
|
1361
|
+
this._annotations = [];
|
1362
|
+
this._redraw();
|
1363
|
+
},
|
1364
|
+
|
1365
|
+
|
1366
|
+
});
|
1367
|
+
|
1368
|
+
require("biojs-events").mixin(Sequence.prototype);
|
1369
|
+
module.exports = Sequence;
|
1370
|
+
|
1371
|
+
},{"biojs-events":2,"jquery-browser-plugin":20,"js-class":22}],2:[function(require,module,exports){
|
1372
|
+
var events = require("backbone-events-standalone");
|
1373
|
+
|
1374
|
+
events.onAll = function(callback,context){
|
1375
|
+
this.on("all", callback,context);
|
1376
|
+
return this;
|
1377
|
+
};
|
1378
|
+
|
1379
|
+
// Mixin utility
|
1380
|
+
events.oldMixin = events.mixin;
|
1381
|
+
events.mixin = function(proto) {
|
1382
|
+
events.oldMixin(proto);
|
1383
|
+
// add custom onAll
|
1384
|
+
var exports = ['onAll'];
|
1385
|
+
for(var i=0; i < exports.length;i++){
|
1386
|
+
var name = exports[i];
|
1387
|
+
proto[name] = this[name];
|
1388
|
+
}
|
1389
|
+
return proto;
|
1390
|
+
};
|
1391
|
+
|
1392
|
+
module.exports = events;
|
1393
|
+
|
1394
|
+
},{"backbone-events-standalone":4}],3:[function(require,module,exports){
|
1395
|
+
/**
|
1396
|
+
* Standalone extraction of Backbone.Events, no external dependency required.
|
1397
|
+
* Degrades nicely when Backone/underscore are already available in the current
|
1398
|
+
* global context.
|
1399
|
+
*
|
1400
|
+
* Note that docs suggest to use underscore's `_.extend()` method to add Events
|
1401
|
+
* support to some given object. A `mixin()` method has been added to the Events
|
1402
|
+
* prototype to avoid using underscore for that sole purpose:
|
1403
|
+
*
|
1404
|
+
* var myEventEmitter = BackboneEvents.mixin({});
|
1405
|
+
*
|
1406
|
+
* Or for a function constructor:
|
1407
|
+
*
|
1408
|
+
* function MyConstructor(){}
|
1409
|
+
* MyConstructor.prototype.foo = function(){}
|
1410
|
+
* BackboneEvents.mixin(MyConstructor.prototype);
|
1411
|
+
*
|
1412
|
+
* (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
|
1413
|
+
* (c) 2013 Nicolas Perriault
|
1414
|
+
*/
|
1415
|
+
/* global exports:true, define, module */
|
1416
|
+
(function() {
|
1417
|
+
var root = this,
|
1418
|
+
breaker = {},
|
1419
|
+
nativeForEach = Array.prototype.forEach,
|
1420
|
+
hasOwnProperty = Object.prototype.hasOwnProperty,
|
1421
|
+
slice = Array.prototype.slice,
|
1422
|
+
idCounter = 0;
|
1423
|
+
|
1424
|
+
// Returns a partial implementation matching the minimal API subset required
|
1425
|
+
// by Backbone.Events
|
1426
|
+
function miniscore() {
|
1427
|
+
return {
|
1428
|
+
keys: Object.keys || function (obj) {
|
1429
|
+
if (typeof obj !== "object" && typeof obj !== "function" || obj === null) {
|
1430
|
+
throw new TypeError("keys() called on a non-object");
|
1431
|
+
}
|
1432
|
+
var key, keys = [];
|
1433
|
+
for (key in obj) {
|
1434
|
+
if (obj.hasOwnProperty(key)) {
|
1435
|
+
keys[keys.length] = key;
|
1436
|
+
}
|
1437
|
+
}
|
1438
|
+
return keys;
|
1439
|
+
},
|
1440
|
+
|
1441
|
+
uniqueId: function(prefix) {
|
1442
|
+
var id = ++idCounter + '';
|
1443
|
+
return prefix ? prefix + id : id;
|
1444
|
+
},
|
1445
|
+
|
1446
|
+
has: function(obj, key) {
|
1447
|
+
return hasOwnProperty.call(obj, key);
|
1448
|
+
},
|
1449
|
+
|
1450
|
+
each: function(obj, iterator, context) {
|
1451
|
+
if (obj == null) return;
|
1452
|
+
if (nativeForEach && obj.forEach === nativeForEach) {
|
1453
|
+
obj.forEach(iterator, context);
|
1454
|
+
} else if (obj.length === +obj.length) {
|
1455
|
+
for (var i = 0, l = obj.length; i < l; i++) {
|
1456
|
+
if (iterator.call(context, obj[i], i, obj) === breaker) return;
|
1457
|
+
}
|
1458
|
+
} else {
|
1459
|
+
for (var key in obj) {
|
1460
|
+
if (this.has(obj, key)) {
|
1461
|
+
if (iterator.call(context, obj[key], key, obj) === breaker) return;
|
1462
|
+
}
|
1463
|
+
}
|
1464
|
+
}
|
1465
|
+
},
|
1466
|
+
|
1467
|
+
once: function(func) {
|
1468
|
+
var ran = false, memo;
|
1469
|
+
return function() {
|
1470
|
+
if (ran) return memo;
|
1471
|
+
ran = true;
|
1472
|
+
memo = func.apply(this, arguments);
|
1473
|
+
func = null;
|
1474
|
+
return memo;
|
1475
|
+
};
|
1476
|
+
}
|
1477
|
+
};
|
1478
|
+
}
|
1479
|
+
|
1480
|
+
var _ = miniscore(), Events;
|
1481
|
+
|
1482
|
+
// Backbone.Events
|
1483
|
+
// ---------------
|
1484
|
+
|
1485
|
+
// A module that can be mixed in to *any object* in order to provide it with
|
1486
|
+
// custom events. You may bind with `on` or remove with `off` callback
|
1487
|
+
// functions to an event; `trigger`-ing an event fires all callbacks in
|
1488
|
+
// succession.
|
1489
|
+
//
|
1490
|
+
// var object = {};
|
1491
|
+
// _.extend(object, Backbone.Events);
|
1492
|
+
// object.on('expand', function(){ alert('expanded'); });
|
1493
|
+
// object.trigger('expand');
|
1494
|
+
//
|
1495
|
+
Events = {
|
1496
|
+
|
1497
|
+
// Bind an event to a `callback` function. Passing `"all"` will bind
|
1498
|
+
// the callback to all events fired.
|
1499
|
+
on: function(name, callback, context) {
|
1500
|
+
if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
|
1501
|
+
this._events || (this._events = {});
|
1502
|
+
var events = this._events[name] || (this._events[name] = []);
|
1503
|
+
events.push({callback: callback, context: context, ctx: context || this});
|
1504
|
+
return this;
|
1505
|
+
},
|
1506
|
+
|
1507
|
+
// Bind an event to only be triggered a single time. After the first time
|
1508
|
+
// the callback is invoked, it will be removed.
|
1509
|
+
once: function(name, callback, context) {
|
1510
|
+
if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
|
1511
|
+
var self = this;
|
1512
|
+
var once = _.once(function() {
|
1513
|
+
self.off(name, once);
|
1514
|
+
callback.apply(this, arguments);
|
1515
|
+
});
|
1516
|
+
once._callback = callback;
|
1517
|
+
return this.on(name, once, context);
|
1518
|
+
},
|
1519
|
+
|
1520
|
+
// Remove one or many callbacks. If `context` is null, removes all
|
1521
|
+
// callbacks with that function. If `callback` is null, removes all
|
1522
|
+
// callbacks for the event. If `name` is null, removes all bound
|
1523
|
+
// callbacks for all events.
|
1524
|
+
off: function(name, callback, context) {
|
1525
|
+
var retain, ev, events, names, i, l, j, k;
|
1526
|
+
if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
|
1527
|
+
if (!name && !callback && !context) {
|
1528
|
+
this._events = {};
|
1529
|
+
return this;
|
1530
|
+
}
|
1531
|
+
|
1532
|
+
names = name ? [name] : _.keys(this._events);
|
1533
|
+
for (i = 0, l = names.length; i < l; i++) {
|
1534
|
+
name = names[i];
|
1535
|
+
if (events = this._events[name]) {
|
1536
|
+
this._events[name] = retain = [];
|
1537
|
+
if (callback || context) {
|
1538
|
+
for (j = 0, k = events.length; j < k; j++) {
|
1539
|
+
ev = events[j];
|
1540
|
+
if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
|
1541
|
+
(context && context !== ev.context)) {
|
1542
|
+
retain.push(ev);
|
1543
|
+
}
|
1544
|
+
}
|
1545
|
+
}
|
1546
|
+
if (!retain.length) delete this._events[name];
|
1547
|
+
}
|
1548
|
+
}
|
1549
|
+
|
1550
|
+
return this;
|
1551
|
+
},
|
1552
|
+
|
1553
|
+
// Trigger one or many events, firing all bound callbacks. Callbacks are
|
1554
|
+
// passed the same arguments as `trigger` is, apart from the event name
|
1555
|
+
// (unless you're listening on `"all"`, which will cause your callback to
|
1556
|
+
// receive the true name of the event as the first argument).
|
1557
|
+
trigger: function(name) {
|
1558
|
+
if (!this._events) return this;
|
1559
|
+
var args = slice.call(arguments, 1);
|
1560
|
+
if (!eventsApi(this, 'trigger', name, args)) return this;
|
1561
|
+
var events = this._events[name];
|
1562
|
+
var allEvents = this._events.all;
|
1563
|
+
if (events) triggerEvents(events, args);
|
1564
|
+
if (allEvents) triggerEvents(allEvents, arguments);
|
1565
|
+
return this;
|
1566
|
+
},
|
1567
|
+
|
1568
|
+
// Tell this object to stop listening to either specific events ... or
|
1569
|
+
// to every object it's currently listening to.
|
1570
|
+
stopListening: function(obj, name, callback) {
|
1571
|
+
var listeners = this._listeners;
|
1572
|
+
if (!listeners) return this;
|
1573
|
+
var deleteListener = !name && !callback;
|
1574
|
+
if (typeof name === 'object') callback = this;
|
1575
|
+
if (obj) (listeners = {})[obj._listenerId] = obj;
|
1576
|
+
for (var id in listeners) {
|
1577
|
+
listeners[id].off(name, callback, this);
|
1578
|
+
if (deleteListener) delete this._listeners[id];
|
1579
|
+
}
|
1580
|
+
return this;
|
1581
|
+
}
|
1582
|
+
|
1583
|
+
};
|
1584
|
+
|
1585
|
+
// Regular expression used to split event strings.
|
1586
|
+
var eventSplitter = /\s+/;
|
1587
|
+
|
1588
|
+
// Implement fancy features of the Events API such as multiple event
|
1589
|
+
// names `"change blur"` and jQuery-style event maps `{change: action}`
|
1590
|
+
// in terms of the existing API.
|
1591
|
+
var eventsApi = function(obj, action, name, rest) {
|
1592
|
+
if (!name) return true;
|
1593
|
+
|
1594
|
+
// Handle event maps.
|
1595
|
+
if (typeof name === 'object') {
|
1596
|
+
for (var key in name) {
|
1597
|
+
obj[action].apply(obj, [key, name[key]].concat(rest));
|
1598
|
+
}
|
1599
|
+
return false;
|
1600
|
+
}
|
1601
|
+
|
1602
|
+
// Handle space separated event names.
|
1603
|
+
if (eventSplitter.test(name)) {
|
1604
|
+
var names = name.split(eventSplitter);
|
1605
|
+
for (var i = 0, l = names.length; i < l; i++) {
|
1606
|
+
obj[action].apply(obj, [names[i]].concat(rest));
|
1607
|
+
}
|
1608
|
+
return false;
|
1609
|
+
}
|
1610
|
+
|
1611
|
+
return true;
|
1612
|
+
};
|
1613
|
+
|
1614
|
+
// A difficult-to-believe, but optimized internal dispatch function for
|
1615
|
+
// triggering events. Tries to keep the usual cases speedy (most internal
|
1616
|
+
// Backbone events have 3 arguments).
|
1617
|
+
var triggerEvents = function(events, args) {
|
1618
|
+
var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
|
1619
|
+
switch (args.length) {
|
1620
|
+
case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
|
1621
|
+
case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
|
1622
|
+
case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
|
1623
|
+
case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
|
1624
|
+
default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
|
1625
|
+
}
|
1626
|
+
};
|
1627
|
+
|
1628
|
+
var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
|
1629
|
+
|
1630
|
+
// Inversion-of-control versions of `on` and `once`. Tell *this* object to
|
1631
|
+
// listen to an event in another object ... keeping track of what it's
|
1632
|
+
// listening to.
|
1633
|
+
_.each(listenMethods, function(implementation, method) {
|
1634
|
+
Events[method] = function(obj, name, callback) {
|
1635
|
+
var listeners = this._listeners || (this._listeners = {});
|
1636
|
+
var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
|
1637
|
+
listeners[id] = obj;
|
1638
|
+
if (typeof name === 'object') callback = this;
|
1639
|
+
obj[implementation](name, callback, this);
|
1640
|
+
return this;
|
1641
|
+
};
|
1642
|
+
});
|
1643
|
+
|
1644
|
+
// Aliases for backwards compatibility.
|
1645
|
+
Events.bind = Events.on;
|
1646
|
+
Events.unbind = Events.off;
|
1647
|
+
|
1648
|
+
// Mixin utility
|
1649
|
+
Events.mixin = function(proto) {
|
1650
|
+
var exports = ['on', 'once', 'off', 'trigger', 'stopListening', 'listenTo',
|
1651
|
+
'listenToOnce', 'bind', 'unbind'];
|
1652
|
+
_.each(exports, function(name) {
|
1653
|
+
proto[name] = this[name];
|
1654
|
+
}, this);
|
1655
|
+
return proto;
|
1656
|
+
};
|
1657
|
+
|
1658
|
+
// Export Events as BackboneEvents depending on current context
|
1659
|
+
if (typeof define === "function") {
|
1660
|
+
define(function() {
|
1661
|
+
return Events;
|
1662
|
+
});
|
1663
|
+
} else if (typeof exports !== 'undefined') {
|
1664
|
+
if (typeof module !== 'undefined' && module.exports) {
|
1665
|
+
exports = module.exports = Events;
|
1666
|
+
}
|
1667
|
+
exports.BackboneEvents = Events;
|
1668
|
+
} else {
|
1669
|
+
root.BackboneEvents = Events;
|
1670
|
+
}
|
1671
|
+
})(this);
|
1672
|
+
|
1673
|
+
},{}],4:[function(require,module,exports){
|
1674
|
+
module.exports = require('./backbone-events-standalone');
|
1675
|
+
|
1676
|
+
},{"./backbone-events-standalone":3}],5:[function(require,module,exports){
|
1677
|
+
// Generated by CoffeeScript 1.8.0
|
1678
|
+
var GenericReader, xhr;
|
1679
|
+
|
1680
|
+
xhr = require('nets');
|
1681
|
+
|
1682
|
+
module.exports = GenericReader = (function() {
|
1683
|
+
function GenericReader() {}
|
1684
|
+
|
1685
|
+
GenericReader.read = function(url, callback) {
|
1686
|
+
var onret;
|
1687
|
+
onret = (function(_this) {
|
1688
|
+
return function(err, response, text) {
|
1689
|
+
return _this._onRetrieval(text, callback);
|
1690
|
+
};
|
1691
|
+
})(this);
|
1692
|
+
return xhr(url, onret);
|
1693
|
+
};
|
1694
|
+
|
1695
|
+
GenericReader._onRetrieval = function(text, callback) {
|
1696
|
+
var rText;
|
1697
|
+
rText = this.parse(text);
|
1698
|
+
return callback(rText);
|
1699
|
+
};
|
1700
|
+
|
1701
|
+
return GenericReader;
|
1702
|
+
|
1703
|
+
})();
|
1704
|
+
|
1705
|
+
},{"nets":12}],6:[function(require,module,exports){
|
1706
|
+
// Generated by CoffeeScript 1.8.0
|
1707
|
+
var Fasta, GenericReader, Seq, Str,
|
1708
|
+
__hasProp = {}.hasOwnProperty,
|
1709
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
1710
|
+
|
1711
|
+
Str = require("./strings");
|
1712
|
+
|
1713
|
+
GenericReader = require("./generic_reader");
|
1714
|
+
|
1715
|
+
Seq = require("biojs-model").seq;
|
1716
|
+
|
1717
|
+
module.exports = Fasta = (function(_super) {
|
1718
|
+
__extends(Fasta, _super);
|
1719
|
+
|
1720
|
+
function Fasta() {
|
1721
|
+
return Fasta.__super__.constructor.apply(this, arguments);
|
1722
|
+
}
|
1723
|
+
|
1724
|
+
Fasta.parse = function(text) {
|
1725
|
+
var currentSeq, database, databaseID, identifiers, k, label, line, seqs, _i, _len;
|
1726
|
+
seqs = [];
|
1727
|
+
if (Object.prototype.toString.call(text) !== '[object Array]') {
|
1728
|
+
text = text.split("\n");
|
1729
|
+
}
|
1730
|
+
for (_i = 0, _len = text.length; _i < _len; _i++) {
|
1731
|
+
line = text[_i];
|
1732
|
+
if (line[0] === ">" || line[0] === ";") {
|
1733
|
+
label = line.slice(1);
|
1734
|
+
currentSeq = new Seq("", label, seqs.length);
|
1735
|
+
seqs.push(currentSeq);
|
1736
|
+
if (Str.contains("|", line)) {
|
1737
|
+
identifiers = label.split("|");
|
1738
|
+
k = 1;
|
1739
|
+
while (k < identifiers.length) {
|
1740
|
+
database = identifiers[k];
|
1741
|
+
databaseID = identifiers[k + 1];
|
1742
|
+
currentSeq.meta[database] = databaseID;
|
1743
|
+
k += 2;
|
1744
|
+
}
|
1745
|
+
currentSeq.name = identifiers[identifiers.length - 1];
|
1746
|
+
}
|
1747
|
+
} else {
|
1748
|
+
currentSeq.seq += line;
|
1749
|
+
}
|
1750
|
+
}
|
1751
|
+
return seqs;
|
1752
|
+
};
|
1753
|
+
|
1754
|
+
return Fasta;
|
1755
|
+
|
1756
|
+
})(GenericReader);
|
1757
|
+
|
1758
|
+
},{"./generic_reader":5,"./strings":7,"biojs-model":10}],7:[function(require,module,exports){
|
1759
|
+
// Generated by CoffeeScript 1.8.0
|
1760
|
+
var strings;
|
1761
|
+
|
1762
|
+
strings = {
|
1763
|
+
contains: function(text, search) {
|
1764
|
+
return ''.indexOf.call(text, search, 0) !== -1;
|
1765
|
+
}
|
1766
|
+
};
|
1767
|
+
|
1768
|
+
module.exports = strings;
|
1769
|
+
|
1770
|
+
},{}],8:[function(require,module,exports){
|
1771
|
+
// Generated by CoffeeScript 1.8.0
|
1772
|
+
var Utils;
|
1773
|
+
|
1774
|
+
Utils = {};
|
1775
|
+
|
1776
|
+
Utils.splitNChars = function(txt, num) {
|
1777
|
+
var i, result, _i, _ref;
|
1778
|
+
result = [];
|
1779
|
+
for (i = _i = 0, _ref = txt.length - 1; num > 0 ? _i <= _ref : _i >= _ref; i = _i += num) {
|
1780
|
+
result.push(txt.substr(i, num));
|
1781
|
+
}
|
1782
|
+
return result;
|
1783
|
+
};
|
1784
|
+
|
1785
|
+
module.exports = Utils;
|
1786
|
+
|
1787
|
+
},{}],9:[function(require,module,exports){
|
1788
|
+
// Generated by CoffeeScript 1.8.0
|
1789
|
+
var FastaExporter, Utils;
|
1790
|
+
|
1791
|
+
Utils = require("./utils");
|
1792
|
+
|
1793
|
+
module.exports = FastaExporter = (function() {
|
1794
|
+
function FastaExporter() {}
|
1795
|
+
|
1796
|
+
FastaExporter["export"] = function(seqs, access) {
|
1797
|
+
var seq, text, _i, _len;
|
1798
|
+
text = "";
|
1799
|
+
for (_i = 0, _len = seqs.length; _i < _len; _i++) {
|
1800
|
+
seq = seqs[_i];
|
1801
|
+
if (access != null) {
|
1802
|
+
seq = access(seq);
|
1803
|
+
}
|
1804
|
+
text += ">" + seq.name + "\n";
|
1805
|
+
text += (Utils.splitNChars(seq.seq, 80)).join("\n");
|
1806
|
+
text += "\n";
|
1807
|
+
}
|
1808
|
+
return text;
|
1809
|
+
};
|
1810
|
+
|
1811
|
+
return FastaExporter;
|
1812
|
+
|
1813
|
+
})();
|
1814
|
+
|
1815
|
+
},{"./utils":8}],10:[function(require,module,exports){
|
1816
|
+
module.exports.seq = require("./seq");
|
1817
|
+
|
1818
|
+
},{"./seq":11}],11:[function(require,module,exports){
|
1819
|
+
module.exports = function(seq, name, id) {
|
1820
|
+
this.seq = seq;
|
1821
|
+
this.name = name;
|
1822
|
+
this.id = id;
|
1823
|
+
this.meta = {};
|
1824
|
+
};
|
1825
|
+
|
1826
|
+
},{}],12:[function(require,module,exports){
|
1827
|
+
var req = require('request')
|
1828
|
+
|
1829
|
+
module.exports = Nets
|
1830
|
+
|
1831
|
+
function Nets(uri, opts, cb) {
|
1832
|
+
req(uri, opts, cb)
|
1833
|
+
}
|
1834
|
+
},{"request":13}],13:[function(require,module,exports){
|
1835
|
+
var window = require("global/window")
|
1836
|
+
var once = require("once")
|
1837
|
+
var parseHeaders = require('parse-headers')
|
1838
|
+
|
1839
|
+
var messages = {
|
1840
|
+
"0": "Internal XMLHttpRequest Error",
|
1841
|
+
"4": "4xx Client Error",
|
1842
|
+
"5": "5xx Server Error"
|
1843
|
+
}
|
1844
|
+
|
1845
|
+
var XHR = window.XMLHttpRequest || noop
|
1846
|
+
var XDR = "withCredentials" in (new XHR()) ? XHR : window.XDomainRequest
|
1847
|
+
|
1848
|
+
module.exports = createXHR
|
1849
|
+
|
1850
|
+
function createXHR(options, callback) {
|
1851
|
+
if (typeof options === "string") {
|
1852
|
+
options = { uri: options }
|
1853
|
+
}
|
1854
|
+
|
1855
|
+
options = options || {}
|
1856
|
+
callback = once(callback)
|
1857
|
+
|
1858
|
+
var xhr = options.xhr || null
|
1859
|
+
|
1860
|
+
if (!xhr) {
|
1861
|
+
if (options.cors || options.useXDR) {
|
1862
|
+
xhr = new XDR()
|
1863
|
+
}else{
|
1864
|
+
xhr = new XHR()
|
1865
|
+
}
|
1866
|
+
}
|
1867
|
+
|
1868
|
+
var uri = xhr.url = options.uri || options.url
|
1869
|
+
var method = xhr.method = options.method || "GET"
|
1870
|
+
var body = options.body || options.data
|
1871
|
+
var headers = xhr.headers = options.headers || {}
|
1872
|
+
var sync = !!options.sync
|
1873
|
+
var isJson = false
|
1874
|
+
var key
|
1875
|
+
var load = options.response ? loadResponse : loadXhr
|
1876
|
+
|
1877
|
+
if ("json" in options) {
|
1878
|
+
isJson = true
|
1879
|
+
headers["Accept"] = "application/json"
|
1880
|
+
if (method !== "GET" && method !== "HEAD") {
|
1881
|
+
headers["Content-Type"] = "application/json"
|
1882
|
+
body = JSON.stringify(options.json)
|
1883
|
+
}
|
1884
|
+
}
|
1885
|
+
|
1886
|
+
xhr.onreadystatechange = readystatechange
|
1887
|
+
xhr.onload = load
|
1888
|
+
xhr.onerror = error
|
1889
|
+
// IE9 must have onprogress be set to a unique function.
|
1890
|
+
xhr.onprogress = function () {
|
1891
|
+
// IE must die
|
1892
|
+
}
|
1893
|
+
// hate IE
|
1894
|
+
xhr.ontimeout = noop
|
1895
|
+
xhr.open(method, uri, !sync)
|
1896
|
+
//backward compatibility
|
1897
|
+
if (options.withCredentials || (options.cors && options.withCredentials !== false)) {
|
1898
|
+
xhr.withCredentials = true
|
1899
|
+
}
|
1900
|
+
|
1901
|
+
// Cannot set timeout with sync request
|
1902
|
+
if (!sync) {
|
1903
|
+
xhr.timeout = "timeout" in options ? options.timeout : 5000
|
1904
|
+
}
|
1905
|
+
|
1906
|
+
if (xhr.setRequestHeader) {
|
1907
|
+
for(key in headers){
|
1908
|
+
if(headers.hasOwnProperty(key)){
|
1909
|
+
xhr.setRequestHeader(key, headers[key])
|
1910
|
+
}
|
1911
|
+
}
|
1912
|
+
} else if (options.headers) {
|
1913
|
+
throw new Error("Headers cannot be set on an XDomainRequest object")
|
1914
|
+
}
|
1915
|
+
|
1916
|
+
if ("responseType" in options) {
|
1917
|
+
xhr.responseType = options.responseType
|
1918
|
+
}
|
1919
|
+
|
1920
|
+
if ("beforeSend" in options &&
|
1921
|
+
typeof options.beforeSend === "function"
|
1922
|
+
) {
|
1923
|
+
options.beforeSend(xhr)
|
1924
|
+
}
|
1925
|
+
|
1926
|
+
xhr.send(body)
|
1927
|
+
|
1928
|
+
return xhr
|
1929
|
+
|
1930
|
+
function readystatechange() {
|
1931
|
+
if (xhr.readyState === 4) {
|
1932
|
+
load()
|
1933
|
+
}
|
1934
|
+
}
|
1935
|
+
|
1936
|
+
function getBody() {
|
1937
|
+
// Chrome with requestType=blob throws errors arround when even testing access to responseText
|
1938
|
+
var body = null
|
1939
|
+
|
1940
|
+
if (xhr.response) {
|
1941
|
+
body = xhr.response
|
1942
|
+
} else if (xhr.responseType === 'text' || !xhr.responseType) {
|
1943
|
+
body = xhr.responseText || xhr.responseXML
|
1944
|
+
}
|
1945
|
+
|
1946
|
+
if (isJson) {
|
1947
|
+
try {
|
1948
|
+
body = JSON.parse(body)
|
1949
|
+
} catch (e) {}
|
1950
|
+
}
|
1951
|
+
|
1952
|
+
return body
|
1953
|
+
}
|
1954
|
+
|
1955
|
+
function getStatusCode() {
|
1956
|
+
return xhr.status === 1223 ? 204 : xhr.status
|
1957
|
+
}
|
1958
|
+
|
1959
|
+
// if we're getting a none-ok statusCode, build & return an error
|
1960
|
+
function errorFromStatusCode(status, body) {
|
1961
|
+
var error = null
|
1962
|
+
if (status === 0 || (status >= 400 && status < 600)) {
|
1963
|
+
var message = (typeof body === "string" ? body : false) ||
|
1964
|
+
messages[String(status).charAt(0)]
|
1965
|
+
error = new Error(message)
|
1966
|
+
error.statusCode = status
|
1967
|
+
}
|
1968
|
+
|
1969
|
+
return error
|
1970
|
+
}
|
1971
|
+
|
1972
|
+
// will load the data & process the response in a special response object
|
1973
|
+
function loadResponse() {
|
1974
|
+
var status = getStatusCode()
|
1975
|
+
var body = getBody()
|
1976
|
+
var error = errorFromStatusCode(status, body)
|
1977
|
+
var response = {
|
1978
|
+
body: body,
|
1979
|
+
statusCode: status,
|
1980
|
+
statusText: xhr.statusText,
|
1981
|
+
raw: xhr
|
1982
|
+
}
|
1983
|
+
if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE
|
1984
|
+
response.headers = parseHeaders(xhr.getAllResponseHeaders())
|
1985
|
+
} else {
|
1986
|
+
response.headers = {}
|
1987
|
+
}
|
1988
|
+
|
1989
|
+
callback(error, response, response.body)
|
1990
|
+
}
|
1991
|
+
|
1992
|
+
// will load the data and add some response properties to the source xhr
|
1993
|
+
// and then respond with that
|
1994
|
+
function loadXhr() {
|
1995
|
+
var status = getStatusCode()
|
1996
|
+
var error = errorFromStatusCode(status)
|
1997
|
+
|
1998
|
+
xhr.status = xhr.statusCode = status
|
1999
|
+
xhr.body = getBody()
|
2000
|
+
xhr.headers = parseHeaders(xhr.getAllResponseHeaders())
|
2001
|
+
|
2002
|
+
callback(error, xhr, xhr.body)
|
2003
|
+
}
|
2004
|
+
|
2005
|
+
function error(evt) {
|
2006
|
+
callback(evt, xhr)
|
2007
|
+
}
|
2008
|
+
}
|
2009
|
+
|
2010
|
+
|
2011
|
+
function noop() {}
|
2012
|
+
|
2013
|
+
},{"global/window":14,"once":15,"parse-headers":19}],14:[function(require,module,exports){
|
2014
|
+
(function (global){
|
2015
|
+
if (typeof window !== "undefined") {
|
2016
|
+
module.exports = window;
|
2017
|
+
} else if (typeof global !== "undefined") {
|
2018
|
+
module.exports = global;
|
2019
|
+
} else if (typeof self !== "undefined"){
|
2020
|
+
module.exports = self;
|
2021
|
+
} else {
|
2022
|
+
module.exports = {};
|
2023
|
+
}
|
2024
|
+
|
2025
|
+
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
2026
|
+
|
2027
|
+
},{}],15:[function(require,module,exports){
|
2028
|
+
module.exports = once
|
2029
|
+
|
2030
|
+
once.proto = once(function () {
|
2031
|
+
Object.defineProperty(Function.prototype, 'once', {
|
2032
|
+
value: function () {
|
2033
|
+
return once(this)
|
2034
|
+
},
|
2035
|
+
configurable: true
|
2036
|
+
})
|
2037
|
+
})
|
2038
|
+
|
2039
|
+
function once (fn) {
|
2040
|
+
var called = false
|
2041
|
+
return function () {
|
2042
|
+
if (called) return
|
2043
|
+
called = true
|
2044
|
+
return fn.apply(this, arguments)
|
2045
|
+
}
|
2046
|
+
}
|
2047
|
+
|
2048
|
+
},{}],16:[function(require,module,exports){
|
2049
|
+
var isFunction = require('is-function')
|
2050
|
+
|
2051
|
+
module.exports = forEach
|
2052
|
+
|
2053
|
+
var toString = Object.prototype.toString
|
2054
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty
|
2055
|
+
|
2056
|
+
function forEach(list, iterator, context) {
|
2057
|
+
if (!isFunction(iterator)) {
|
2058
|
+
throw new TypeError('iterator must be a function')
|
2059
|
+
}
|
2060
|
+
|
2061
|
+
if (arguments.length < 3) {
|
2062
|
+
context = this
|
2063
|
+
}
|
2064
|
+
|
2065
|
+
if (toString.call(list) === '[object Array]')
|
2066
|
+
forEachArray(list, iterator, context)
|
2067
|
+
else if (typeof list === 'string')
|
2068
|
+
forEachString(list, iterator, context)
|
2069
|
+
else
|
2070
|
+
forEachObject(list, iterator, context)
|
2071
|
+
}
|
2072
|
+
|
2073
|
+
function forEachArray(array, iterator, context) {
|
2074
|
+
for (var i = 0, len = array.length; i < len; i++) {
|
2075
|
+
if (hasOwnProperty.call(array, i)) {
|
2076
|
+
iterator.call(context, array[i], i, array)
|
2077
|
+
}
|
2078
|
+
}
|
2079
|
+
}
|
2080
|
+
|
2081
|
+
function forEachString(string, iterator, context) {
|
2082
|
+
for (var i = 0, len = string.length; i < len; i++) {
|
2083
|
+
// no such thing as a sparse string.
|
2084
|
+
iterator.call(context, string.charAt(i), i, string)
|
2085
|
+
}
|
2086
|
+
}
|
2087
|
+
|
2088
|
+
function forEachObject(object, iterator, context) {
|
2089
|
+
for (var k in object) {
|
2090
|
+
if (hasOwnProperty.call(object, k)) {
|
2091
|
+
iterator.call(context, object[k], k, object)
|
2092
|
+
}
|
2093
|
+
}
|
2094
|
+
}
|
2095
|
+
|
2096
|
+
},{"is-function":17}],17:[function(require,module,exports){
|
2097
|
+
module.exports = isFunction
|
2098
|
+
|
2099
|
+
var toString = Object.prototype.toString
|
2100
|
+
|
2101
|
+
function isFunction (fn) {
|
2102
|
+
var string = toString.call(fn)
|
2103
|
+
return string === '[object Function]' ||
|
2104
|
+
(typeof fn === 'function' && string !== '[object RegExp]') ||
|
2105
|
+
(typeof window !== 'undefined' &&
|
2106
|
+
// IE8 and below
|
2107
|
+
(fn === window.setTimeout ||
|
2108
|
+
fn === window.alert ||
|
2109
|
+
fn === window.confirm ||
|
2110
|
+
fn === window.prompt))
|
2111
|
+
};
|
2112
|
+
|
2113
|
+
},{}],18:[function(require,module,exports){
|
2114
|
+
|
2115
|
+
exports = module.exports = trim;
|
2116
|
+
|
2117
|
+
function trim(str){
|
2118
|
+
return str.replace(/^\s*|\s*$/g, '');
|
2119
|
+
}
|
2120
|
+
|
2121
|
+
exports.left = function(str){
|
2122
|
+
return str.replace(/^\s*/, '');
|
2123
|
+
};
|
2124
|
+
|
2125
|
+
exports.right = function(str){
|
2126
|
+
return str.replace(/\s*$/, '');
|
2127
|
+
};
|
2128
|
+
|
2129
|
+
},{}],19:[function(require,module,exports){
|
2130
|
+
var trim = require('trim')
|
2131
|
+
, forEach = require('for-each')
|
2132
|
+
, isArray = function(arg) {
|
2133
|
+
return Object.prototype.toString.call(arg) === '[object Array]';
|
2134
|
+
}
|
2135
|
+
|
2136
|
+
module.exports = function (headers) {
|
2137
|
+
if (!headers)
|
2138
|
+
return {}
|
2139
|
+
|
2140
|
+
var result = {}
|
2141
|
+
|
2142
|
+
forEach(
|
2143
|
+
trim(headers).split('\n')
|
2144
|
+
, function (row) {
|
2145
|
+
var index = row.indexOf(':')
|
2146
|
+
, key = trim(row.slice(0, index)).toLowerCase()
|
2147
|
+
, value = trim(row.slice(index + 1))
|
2148
|
+
|
2149
|
+
if (typeof(result[key]) === 'undefined') {
|
2150
|
+
result[key] = value
|
2151
|
+
} else if (isArray(result[key])) {
|
2152
|
+
result[key].push(value)
|
2153
|
+
} else {
|
2154
|
+
result[key] = [ result[key], value ]
|
2155
|
+
}
|
2156
|
+
}
|
2157
|
+
)
|
2158
|
+
|
2159
|
+
return result
|
2160
|
+
}
|
2161
|
+
},{"for-each":16,"trim":18}],20:[function(require,module,exports){
|
2162
|
+
module.exports = require('./jquery.browser');
|
2163
|
+
|
2164
|
+
},{"./jquery.browser":21}],21:[function(require,module,exports){
|
2165
|
+
/*!
|
2166
|
+
* jQuery Browser Plugin v0.0.6
|
2167
|
+
* https://github.com/gabceb/jquery-browser-plugin
|
2168
|
+
*
|
2169
|
+
* Original jquery-browser code Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
|
2170
|
+
* http://jquery.org/license
|
2171
|
+
*
|
2172
|
+
* Modifications Copyright 2013 Gabriel Cebrian
|
2173
|
+
* https://github.com/gabceb
|
2174
|
+
*
|
2175
|
+
* Released under the MIT license
|
2176
|
+
*
|
2177
|
+
* Date: 2013-07-29T17:23:27-07:00
|
2178
|
+
*/
|
2179
|
+
|
2180
|
+
|
2181
|
+
var matched, browser;
|
2182
|
+
|
2183
|
+
var uaMatch = function( ua ) {
|
2184
|
+
ua = ua.toLowerCase();
|
2185
|
+
|
2186
|
+
var match = /(opr)[\/]([\w.]+)/.exec( ua ) ||
|
2187
|
+
/(chrome)[ \/]([\w.]+)/.exec( ua ) ||
|
2188
|
+
/(version)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec( ua ) ||
|
2189
|
+
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
|
2190
|
+
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
|
2191
|
+
/(msie) ([\w.]+)/.exec( ua ) ||
|
2192
|
+
ua.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec( ua ) ||
|
2193
|
+
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
|
2194
|
+
[];
|
2195
|
+
|
2196
|
+
var platform_match = /(ipad)/.exec( ua ) ||
|
2197
|
+
/(iphone)/.exec( ua ) ||
|
2198
|
+
/(android)/.exec( ua ) ||
|
2199
|
+
/(windows phone)/.exec( ua ) ||
|
2200
|
+
/(win)/.exec( ua ) ||
|
2201
|
+
/(mac)/.exec( ua ) ||
|
2202
|
+
/(linux)/.exec( ua ) ||
|
2203
|
+
/(cros)/i.exec( ua ) ||
|
2204
|
+
[];
|
2205
|
+
|
2206
|
+
return {
|
2207
|
+
browser: match[ 3 ] || match[ 1 ] || "",
|
2208
|
+
version: match[ 2 ] || "0",
|
2209
|
+
platform: platform_match[ 0 ] || ""
|
2210
|
+
};
|
2211
|
+
};
|
2212
|
+
|
2213
|
+
matched = uaMatch( window.navigator.userAgent );
|
2214
|
+
browser = {};
|
2215
|
+
browser.uaMatch = uaMatch;
|
2216
|
+
|
2217
|
+
if ( matched.browser ) {
|
2218
|
+
browser[ matched.browser ] = true;
|
2219
|
+
browser.version = matched.version;
|
2220
|
+
browser.versionNumber = parseInt(matched.version);
|
2221
|
+
}
|
2222
|
+
|
2223
|
+
if ( matched.platform ) {
|
2224
|
+
browser[ matched.platform ] = true;
|
2225
|
+
}
|
2226
|
+
|
2227
|
+
// These are all considered mobile platforms, meaning they run a mobile browser
|
2228
|
+
if ( browser.android || browser.ipad || browser.iphone || browser[ "windows phone" ] ) {
|
2229
|
+
browser.mobile = true;
|
2230
|
+
}
|
2231
|
+
|
2232
|
+
// These are all considered desktop platforms, meaning they run a desktop browser
|
2233
|
+
if ( browser.cros || browser.mac || browser.linux || browser.win ) {
|
2234
|
+
browser.desktop = true;
|
2235
|
+
}
|
2236
|
+
|
2237
|
+
// Chrome, Opera 15+ and Safari are webkit based browsers
|
2238
|
+
if ( browser.chrome || browser.opr || browser.safari ) {
|
2239
|
+
browser.webkit = true;
|
2240
|
+
}
|
2241
|
+
|
2242
|
+
// IE11 has a new token so we will assign it msie to avoid breaking changes
|
2243
|
+
if ( browser.rv )
|
2244
|
+
{
|
2245
|
+
var ie = "msie";
|
2246
|
+
|
2247
|
+
matched.browser = ie;
|
2248
|
+
browser[ie] = true;
|
2249
|
+
}
|
2250
|
+
|
2251
|
+
// Opera 15+ are identified as opr
|
2252
|
+
if ( browser.opr )
|
2253
|
+
{
|
2254
|
+
var opera = "opera";
|
2255
|
+
|
2256
|
+
matched.browser = opera;
|
2257
|
+
browser[opera] = true;
|
2258
|
+
}
|
2259
|
+
|
2260
|
+
// Stock Android browsers are marked as Safari on Android.
|
2261
|
+
if ( browser.safari && browser.android )
|
2262
|
+
{
|
2263
|
+
var android = "android";
|
2264
|
+
|
2265
|
+
matched.browser = android;
|
2266
|
+
browser[android] = true;
|
2267
|
+
}
|
2268
|
+
|
2269
|
+
// Assign the name and platform variable
|
2270
|
+
browser.name = matched.browser;
|
2271
|
+
browser.platform = matched.platform;
|
2272
|
+
|
2273
|
+
|
2274
|
+
module.exports = browser;
|
2275
|
+
|
2276
|
+
},{}],22:[function(require,module,exports){
|
2277
|
+
(function (global){
|
2278
|
+
/** @preserve http://github.com/easeway/js-class */
|
2279
|
+
|
2280
|
+
// Class Definition using ECMA5 prototype chain
|
2281
|
+
|
2282
|
+
function inherit(dest, src, noParent) {
|
2283
|
+
while (src && src !== Object.prototype) {
|
2284
|
+
Object.getOwnPropertyNames(src).forEach(function (name) {
|
2285
|
+
if (name != '.class' && !dest.hasOwnProperty(name)) {
|
2286
|
+
var desc = Object.getOwnPropertyDescriptor(src, name);
|
2287
|
+
Object.defineProperty(dest, name, desc);
|
2288
|
+
}
|
2289
|
+
});
|
2290
|
+
if (noParent) {
|
2291
|
+
break;
|
2292
|
+
}
|
2293
|
+
src = src.__proto__;
|
2294
|
+
}
|
2295
|
+
return dest;
|
2296
|
+
}
|
2297
|
+
|
2298
|
+
var Class = function (base, proto, options) {
|
2299
|
+
if (typeof(base) != 'function') {
|
2300
|
+
options = proto;
|
2301
|
+
proto = base;
|
2302
|
+
base = Object;
|
2303
|
+
}
|
2304
|
+
if (!proto) {
|
2305
|
+
proto = {};
|
2306
|
+
}
|
2307
|
+
if (!options) {
|
2308
|
+
options = {};
|
2309
|
+
}
|
2310
|
+
|
2311
|
+
var meta = {
|
2312
|
+
name: options.name,
|
2313
|
+
base: base,
|
2314
|
+
implements: []
|
2315
|
+
}
|
2316
|
+
var classProto = Class.clone(proto);
|
2317
|
+
if (options.implements) {
|
2318
|
+
(Array.isArray(options.implements) ? options.implements : [options.implements])
|
2319
|
+
.forEach(function (implementedType) {
|
2320
|
+
if (typeof(implementedType) == 'function' && implementedType.prototype) {
|
2321
|
+
meta.implements.push(implementedType);
|
2322
|
+
Class.extend(classProto, implementedType.prototype);
|
2323
|
+
}
|
2324
|
+
});
|
2325
|
+
}
|
2326
|
+
classProto.__proto__ = base.prototype;
|
2327
|
+
var theClass = function () {
|
2328
|
+
if (typeof(this.constructor) == 'function') {
|
2329
|
+
this.constructor.apply(this, arguments);
|
2330
|
+
}
|
2331
|
+
};
|
2332
|
+
meta.type = theClass;
|
2333
|
+
theClass.prototype = classProto;
|
2334
|
+
Object.defineProperty(theClass, '.class.meta', { value: meta, enumerable: false, configurable: false, writable: false });
|
2335
|
+
Object.defineProperty(classProto, '.class', { value: theClass, enumerable: false, configurable: false, writable: false });
|
2336
|
+
if (options.statics) {
|
2337
|
+
Class.extend(theClass, options.statics);
|
2338
|
+
}
|
2339
|
+
return theClass;
|
2340
|
+
};
|
2341
|
+
|
2342
|
+
Class.extend = inherit;
|
2343
|
+
|
2344
|
+
Class.clone = function (object) {
|
2345
|
+
return inherit({}, object);
|
2346
|
+
};
|
2347
|
+
|
2348
|
+
function findType(meta, type) {
|
2349
|
+
while (meta) {
|
2350
|
+
if (meta.type.prototype === type.prototype) {
|
2351
|
+
return true;
|
2352
|
+
}
|
2353
|
+
for (var i in meta.implements) {
|
2354
|
+
var implType = meta.implements[i];
|
2355
|
+
var implMeta = implType['.class.meta'];
|
2356
|
+
if (implMeta) {
|
2357
|
+
if (findType(implMeta, type)) {
|
2358
|
+
return true;
|
2359
|
+
}
|
2360
|
+
} else {
|
2361
|
+
for (var proto = implType.prototype; proto; proto = proto.__proto__) {
|
2362
|
+
if (proto === type.prototype) {
|
2363
|
+
return true;
|
2364
|
+
}
|
2365
|
+
}
|
2366
|
+
}
|
2367
|
+
}
|
2368
|
+
meta = meta.base ? meta.base['.class.meta'] : undefined;
|
2369
|
+
}
|
2370
|
+
return false;
|
2371
|
+
}
|
2372
|
+
|
2373
|
+
var Checker = Class({
|
2374
|
+
constructor: function (object) {
|
2375
|
+
this.object = object;
|
2376
|
+
},
|
2377
|
+
|
2378
|
+
typeOf: function (type) {
|
2379
|
+
if (this.object instanceof type) {
|
2380
|
+
return true;
|
2381
|
+
}
|
2382
|
+
var meta = Class.typeInfo(this.object);
|
2383
|
+
return meta && findType(meta, type);
|
2384
|
+
}
|
2385
|
+
});
|
2386
|
+
|
2387
|
+
// aliases
|
2388
|
+
Checker.prototype.a = Checker.prototype.typeOf;
|
2389
|
+
Checker.prototype.an = Checker.prototype.typeOf;
|
2390
|
+
|
2391
|
+
Class.is = function (object) {
|
2392
|
+
return new Checker(object);
|
2393
|
+
};
|
2394
|
+
|
2395
|
+
Class.typeInfo = function (object) {
|
2396
|
+
var theClass = object.__proto__['.class'];
|
2397
|
+
return theClass ? theClass['.class.meta'] : undefined;
|
2398
|
+
};
|
2399
|
+
|
2400
|
+
Class.VERSION = [0, 0, 2];
|
2401
|
+
|
2402
|
+
if (module) {
|
2403
|
+
module.exports = Class;
|
2404
|
+
} else {
|
2405
|
+
global.Class = Class; // for browser
|
2406
|
+
}
|
2407
|
+
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
2408
|
+
|
2409
|
+
},{}],"biojs-io-fasta":[function(require,module,exports){
|
2410
|
+
// Generated by CoffeeScript 1.8.0
|
2411
|
+
module.exports.parse = require("./parser");
|
2412
|
+
|
2413
|
+
module.exports.writer = require("./writer");
|
2414
|
+
|
2415
|
+
},{"./parser":6,"./writer":9}],"biojs-vis-sequence":[function(require,module,exports){
|
2416
|
+
module.exports = require("./lib/index");
|
2417
|
+
|
2418
|
+
},{"./lib/index":1}]},{},["biojs-vis-sequence"])
|
2419
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2UvbGliL2luZGV4LmpzIiwiL1VzZXJzL3ByaXlhbS9zZXF1ZW5jZXNlcnZlci9ub2RlX21vZHVsZXMvYmlvanMtdmlzLXNlcXVlbmNlL25vZGVfbW9kdWxlcy9iaW9qcy1ldmVudHMvaW5kZXguanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2Jpb2pzLWV2ZW50cy9ub2RlX21vZHVsZXMvYmFja2JvbmUtZXZlbnRzLXN0YW5kYWxvbmUvYmFja2JvbmUtZXZlbnRzLXN0YW5kYWxvbmUuanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2Jpb2pzLWV2ZW50cy9ub2RlX21vZHVsZXMvYmFja2JvbmUtZXZlbnRzLXN0YW5kYWxvbmUvaW5kZXguanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2Jpb2pzLWlvLWZhc3RhL2xpYi9nZW5lcmljX3JlYWRlci5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbGliL3BhcnNlci5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbGliL3N0cmluZ3MuanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2Jpb2pzLWlvLWZhc3RhL2xpYi91dGlscy5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbGliL3dyaXRlci5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbm9kZV9tb2R1bGVzL2Jpb2pzLW1vZGVsL3NyYy9pbmRleC5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbm9kZV9tb2R1bGVzL2Jpb2pzLW1vZGVsL3NyYy9zZXEuanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2Jpb2pzLWlvLWZhc3RhL25vZGVfbW9kdWxlcy9uZXRzL2luZGV4LmpzIiwiL1VzZXJzL3ByaXlhbS9zZXF1ZW5jZXNlcnZlci9ub2RlX21vZHVsZXMvYmlvanMtdmlzLXNlcXVlbmNlL25vZGVfbW9kdWxlcy9iaW9qcy1pby1mYXN0YS9ub2RlX21vZHVsZXMvbmV0cy9ub2RlX21vZHVsZXMveGhyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2Jpb2pzLWlvLWZhc3RhL25vZGVfbW9kdWxlcy9uZXRzL25vZGVfbW9kdWxlcy94aHIvbm9kZV9tb2R1bGVzL2dsb2JhbC93aW5kb3cuanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2Jpb2pzLWlvLWZhc3RhL25vZGVfbW9kdWxlcy9uZXRzL25vZGVfbW9kdWxlcy94aHIvbm9kZV9tb2R1bGVzL29uY2Uvb25jZS5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbm9kZV9tb2R1bGVzL25ldHMvbm9kZV9tb2R1bGVzL3hoci9ub2RlX21vZHVsZXMvcGFyc2UtaGVhZGVycy9ub2RlX21vZHVsZXMvZm9yLWVhY2gvaW5kZXguanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2Jpb2pzLWlvLWZhc3RhL25vZGVfbW9kdWxlcy9uZXRzL25vZGVfbW9kdWxlcy94aHIvbm9kZV9tb2R1bGVzL3BhcnNlLWhlYWRlcnMvbm9kZV9tb2R1bGVzL2Zvci1lYWNoL25vZGVfbW9kdWxlcy9pcy1mdW5jdGlvbi9pbmRleC5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbm9kZV9tb2R1bGVzL25ldHMvbm9kZV9tb2R1bGVzL3hoci9ub2RlX21vZHVsZXMvcGFyc2UtaGVhZGVycy9ub2RlX21vZHVsZXMvdHJpbS9pbmRleC5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbm9kZV9tb2R1bGVzL25ldHMvbm9kZV9tb2R1bGVzL3hoci9ub2RlX21vZHVsZXMvcGFyc2UtaGVhZGVycy9wYXJzZS1oZWFkZXJzLmpzIiwiL1VzZXJzL3ByaXlhbS9zZXF1ZW5jZXNlcnZlci9ub2RlX21vZHVsZXMvYmlvanMtdmlzLXNlcXVlbmNlL25vZGVfbW9kdWxlcy9qcXVlcnktYnJvd3Nlci1wbHVnaW4vaW5kZXguanMiLCIvVXNlcnMvcHJpeWFtL3NlcXVlbmNlc2VydmVyL25vZGVfbW9kdWxlcy9iaW9qcy12aXMtc2VxdWVuY2Uvbm9kZV9tb2R1bGVzL2pxdWVyeS1icm93c2VyLXBsdWdpbi9qcXVlcnkuYnJvd3Nlci5qcyIsIm5vZGVfbW9kdWxlcy9qcy1jbGFzcy9jbGFzcy5qcyIsIi9Vc2Vycy9wcml5YW0vc2VxdWVuY2VzZXJ2ZXIvbm9kZV9tb2R1bGVzL2Jpb2pzLXZpcy1zZXF1ZW5jZS9ub2RlX21vZHVsZXMvYmlvanMtaW8tZmFzdGEvbGliL2luZGV4LmpzIiwiLi9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzc1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDclJBO0FBQ0E7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTs7QUNEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDakxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBOztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDOUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ2hJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0pBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLy8gbGVnYWN5ISFcbiQuYnJvd3NlciA9IHJlcXVpcmUoXCJqcXVlcnktYnJvd3Nlci1wbHVnaW5cIik7XG5cbi8qKiBcbiAqIFNlcXVlbmNlIGNvbXBvbmVudCBcbiAqIFxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBCaW9qc1xuICogXG4gKiBAYXV0aG9yIDxhIGhyZWY9XCJtYWlsdG86am9obmNhckBnbWFpbC5jb21cIj5Kb2huIEdvbWV6PC9hPiwgPGEgaHJlZj1cIm1haWx0bzpzZWNldmFsbGl2QGdtYWlsLmNvbVwiPkpvc2UgVmlsbGF2ZWNlczwvYT5cbiAqIEB2ZXJzaW9uIDEuMC4wXG4gKiBAY2F0ZWdvcnkgM1xuICogXG4gKiBAcmVxdWlyZXMgPGEgaHJlZj0naHR0cDovL2Jsb2cuanF1ZXJ5LmNvbS8yMDExLzA5LzEyL2pxdWVyeS0xLTYtNC1yZWxlYXNlZC8nPmpRdWVyeSBDb3JlIDEuNi40PC9hPlxuICogQGRlcGVuZGVuY3kgPHNjcmlwdCBsYW5ndWFnZT1cIkphdmFTY3JpcHRcIiB0eXBlPVwidGV4dC9qYXZhc2NyaXB0XCIgc3JjPVwiLi4vYmlvanMvZGVwZW5kZW5jaWVzL2pxdWVyeS9qcXVlcnktMS40LjIubWluLmpzXCI+PC9zY3JpcHQ+XG4gKiBcbiAqIEByZXF1aXJlcyA8YSBocmVmPSdodHRwOi8vanF1ZXJ5dWkuY29tL2Rvd25sb2FkJz5qUXVlcnkgVUkgMS44LjE2PC9hPlxuICogQGRlcGVuZGVuY3kgPHNjcmlwdCBsYW5ndWFnZT1cIkphdmFTY3JpcHRcIiB0eXBlPVwidGV4dC9qYXZhc2NyaXB0XCIgc3JjPVwiLi4vYmlvanMvZGVwZW5kZW5jaWVzL2pxdWVyeS9qcXVlcnktdWktMS44LjIuY3VzdG9tLm1pbi5qc1wiPjwvc2NyaXB0PlxuICpcbiAqIEByZXF1aXJlcyA8YSBocmVmPSdCaW9qcy5Ub29sdGlwLmNzcyc+QmlvanMuVG9vbHRpcDwvYT5cbiAqIEBkZXBlbmRlbmN5IDxzY3JpcHQgbGFuZ3VhZ2U9XCJKYXZhU2NyaXB0XCIgdHlwZT1cInRleHQvamF2YXNjcmlwdFwiIHNyYz1cInNyYy9CaW9qcy5Ub29sdGlwLmpzXCI+PC9zY3JpcHQ+XG4gKiBcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIEFuIG9iamVjdCB3aXRoIHRoZSBvcHRpb25zIGZvciBTZXF1ZW5jZSBjb21wb25lbnQuXG4gKiAgICBcbiAqIEBvcHRpb24ge3N0cmluZ30gdGFyZ2V0IFxuICogICAgSWRlbnRpZmllciBvZiB0aGUgRElWIHRhZyB3aGVyZSB0aGUgY29tcG9uZW50IHNob3VsZCBiZSBkaXNwbGF5ZWQuXG4gKiAgICBcbiAqIEBvcHRpb24ge3N0cmluZ30gc2VxdWVuY2UgXG4gKiAgICBUaGUgc2VxdWVuY2UgdG8gYmUgZGlzcGxheWVkLlxuICogICAgXG4gKiBAb3B0aW9uIHtzdHJpbmd9IFtpZF0gXG4gKiAgICBTZXF1ZW5jZSBpZGVudGlmaWVyIGlmIGFwcGx5LlxuICogICAgXG4gKiBAb3B0aW9uIHtzdHJpbmd9IFtmb3JtYXQ9XCJGQVNUQVwiXSBcbiAqICAgIFRoZSBkaXNwbGF5IGZvcm1hdCBmb3IgdGhlIHNlcXVlbmNlIHJlcHJlc2VudGF0aW9uLlxuICogICAgXG4gKiBAb3B0aW9uIHtPYmplY3RbXX0gW2hpZ2hsaWdodHNdIFxuICogXHQgIEZvciBoaWdobGlnaHRpbmcgbXVsdGlwbGUgcmVnaW9ucy4gXG4gKiAgICA8cHJlIGNsYXNzPVwiYnJ1c2g6IGpzXCIgdGl0bGU9XCJTeW50YXg6XCI+IFxuICogICAgW1xuICogICAgXHQvLyBIaWdobGlnaHQgYW1pbm9hY2lkcyBmcm9tICdzdGFydCcgdG8gJ2VuZCcgb2YgdGhlIGN1cnJlbnQgc3RyYW5kIHVzaW5nIHRoZSBzcGVjaWZpZWQgJ2NvbG9yJyAob3B0aW9uYWwpIGFuZCAnYmFja2dyb3VuZCcgKG9wdGlvbmFsKS5cbiAqICAgIFx0eyBzdGFydDogJmx0O3N0YXJ0VmFsMSZndDssIGVuZDogJmx0O2VuZFZhbDEmZ3Q7IFssIGlkOiZsdDtpZFZhbDEmZ3Q7XSBbLCBjb2xvcjogJmx0O0hUTUxDb2xvciZndDtdIFssIGJhY2tncm91bmQ6ICZsdDtIVE1MQ29sb3ImZ3Q7XX0sIFxuICogICAgXHQvL1xuICogICAgXHQvLyBBbnkgb3RoZXJzIGhpZ2hsaWdodHNcbiAqICAgIFx0Li4uLCAgXG4gKiAgICBcdC8vIFxuICogICAgXHR7IHN0YXJ0OiAmbHQ7c3RhcnRWYWxOJmd0OywgZW5kOiAmbHQ7ZW5kVmFsTiZndDsgWywgaWQ6Jmx0O2lkVmFsTiZndDtdIFssIGNvbG9yOiAmbHQ7SFRNTENvbG9yJmd0O10gWywgYmFja2dyb3VuZDogJmx0O0hUTUxDb2xvciZndDtdfVxuICogICAgXTwvcHJlPlxuICogXG4gKiA8cHJlIGNsYXNzPVwiYnJ1c2g6IGpzXCIgdGl0bGU9XCJFeGFtcGxlOlwiPiBcbiAqIGhpZ2hsaWdodHMgOiBbXG4gKiBcdFx0eyBzdGFydDozMCwgZW5kOjQyLCBjb2xvcjpcIndoaXRlXCIsIGJhY2tncm91bmQ6XCJncmVlblwiLCBpZDpcInNwaW4xXCIgfSxcbiAqXHRcdHsgc3RhcnQ6MTM5LCBlbmQ6MTQwIH0sIFxuICpcdFx0eyBzdGFydDo2MzEsIGVuZDo2MzMsIGNvbG9yOlwid2hpdGVcIiwgYmFja2dyb3VuZDpcImJsdWVcIiB9XG4gKlx0XVxuICogPC9wcmU+XG4gKiBcbiAqIEBvcHRpb24ge09iamVjdH0gW2NvbHVtbnM9e3NpemU6NDAsc3BhY2VkRWFjaDoxMH1dIFxuICogXHQgIE9wdGlvbnMgZm9yIGRpc3BsYXlpbmcgdGhlIGNvbHVtbnMuIFN5bnRheDogeyBzaXplOiAmbHQ7bnVtQ29scyZndDssIHNwYWNlZEVhY2g6ICZsdDtudW1Db2xzJmd0O31cbiAqIFxuICogQG9wdGlvbiB7T2JqZWN0fSBbc2VsZWN0aW9uXSBcbiAqIFx0ICBQb3NpdGlvbnMgZm9yIHRoZSBjdXJyZW50IHNlbGVjdGVkIHJlZ2lvbi4gU3ludGF4OiB7IHN0YXJ0OiAmbHQ7c3RhcnRWYWx1ZSZndDssIGVuZDogJmx0O2VuZFZhbHVlJmd0O31cbiAqIFxuICogQG9wdGlvbiB7T2JqZWN0W119IFthbm5vdGF0aW9uc10gXG4gKiAgICBTZXQgb2Ygb3ZlcmxhcHBpbmcgYW5ub3RhdGlvbnMuIE11c3QgYmUgYW4gYXJyYXkgb2Ygb2JqZWN0cyBmb2xsb3dpbmcgdGhlIHN5bnRheDpcbiAqICAgICBcdFx0PHByZSBjbGFzcz1cImJydXNoOiBqc1wiIHRpdGxlPVwiU3ludGF4OlwiPlxuICogICAgICAgICAgICBbIFxuICogICAgICAgICAgICAgIC8vIEFuIGFubm90YXRpb246XG4gKiAgICAgICAgICAgICAgeyBuYW1lOiAmbHQ7bmFtZSZndDssIFxuICogICAgICAgICAgICAgICAgaHRtbDogJmx0O21lc3NhZ2UmZ3Q7LCBcbiAqICAgICAgICAgICAgICAgIGNvbG9yOiAmbHQ7Y29sb3JfY29kZSZndDssIFxuICogICAgICAgICAgICAgICAgcmVnaW9uczogW3sgc3RhcnQ6ICZsdDtzdGFydFZhbDEmZ3Q7LCBlbmQ6ICZsdDtlbmRWYWwxJmd0OyBjb2xvcjogJmx0O0hUTUxDb2xvciZndDt9LCAuLi4seyBzdGFydDogJmx0O3N0YXJ0VmFsTiZndDssIGVuZDogJmx0O2VuZFZhbE4mZ3Q7LCBjb2xvcjogJmx0O0hUTUxDb2xvciZndDt9XSBcbiAqICAgICAgICAgICAgICB9LCBcbiAqICAgICAgICAgICAgICBcbiAqICAgICAgICAgICAgICAvLyAuLi5cbiAqICAgICAgICAgICAgICAvLyBtb3JlIGFubm90YXRpb25zIGhlcmUgXG4gKiAgICAgICAgICAgICAgLy8gLi4uXG4gKiAgICAgICAgICAgIF1cbiAqICAgIFx0XHQgPC9wcmU+XG4gKiAgICB3aGVyZTpcbiAqICAgICAgPHVsPlxuICogICAgICAgIDxsaT48Yj5uYW1lPC9iPiBpcyB0aGUgdW5pcXVlIG5hbWUgZm9yIHRoZSBhbm5vdGF0aW9uPC9saT5cbiAqICAgICAgICA8bGk+PGI+aHRtbDwvYj4gaXMgdGhlIG1lc3NhZ2UgKGNhbiBiZSBIVE1MKSB0byBiZSBkaXNwbGF5ZWQgaW4gdGhlIHRvb2wgdGlwLjwvbGk+XG4gKiAgICAgICAgPGxpPjxiPmNvbG9yPC9iPiBpcyB0aGUgZGVmYXVsdCBIVE1MIGNvbG9yIGNvZGUgZm9yIGFsbCB0aGUgcmVnaW9ucy48L2xpPlxuICogICAgICAgIDxsaT48Yj5yZWdpb25zPC9iPiBhcnJheSBvZiBvYmplY3RzIGRlZmluaW5nIHRoZSBpbnRlcnZhbHMgd2hpY2ggYmVsb25ncyB0byB0aGUgYW5ub3RhdGlvbi48L2xpPlxuICogICAgICAgIDxsaT48Yj5yZWdpb25zW2ldLnN0YXJ0PC9iPiBpcyB0aGUgc3RhcnRpbmcgY2hhcmFjdGVyIGZvciB0aGUgaS10aCBpbnRlcnZhbC48L2xpPlxuICogICAgICAgIDxsaT48Yj5yZWdpb25zW2ldLmVuZDwvYj4gaXMgdGhlIGVuZGluZyBjaGFyYWN0ZXIgZm9yIHRoZSBpLXRoIGludGVydmFsLjwvbGk+XG4gKiAgICAgICAgPGxpPjxiPnJlZ2lvbnNbaV0uY29sb3I8L2I+IGlzIGFuIG9wdGlvbmFsIGNvbG9yIGZvciB0aGUgaS10aCBpbnRlcnZhbC4gICBcbiAqICAgICAgPC91bD4gXG4gKiAgICAgIFxuICogQG9wdGlvbiB7T2JqZWN0fSBbZm9ybWF0T3B0aW9ucz17dGl0bGU6dHJ1ZSwgZm9vdGVyOnRydWV9XSBcbiAqIFx0ICBPcHRpb25zIGZvciBkaXNwbGF5aW5nIHRoZSB0aXRsZS4gYnkgbm93IGp1c3QgYWZmZWN0aW5nIHRoZSBDT0RBVEEgZm9ybWF0LlxuICogICAgPHByZSBjbGFzcz1cImJydXNoOiBqc1wiIHRpdGxlPVwiU3ludGF4OlwiPiBcbiAqIFx0XHRmb3JtYXRPcHRpb25zIDoge1xuICogXHRcdFx0dGl0bGU6ZmFsc2UsXG4gKiBcdFx0XHRmb290ZXI6ZmFsc2VcbiAqIFx0XHR9XG4gKiAgICA8L3ByZT5cbiAqICAgIFxuICogQGV4YW1wbGUgXG4gKiB2YXIgdGhlU2VxdWVuY2UgPSBcIk1FVExDUVJMTlZDUURLSUxUSFlFTkRTVERMUkRISURZV0tITVJMRUNBSVlZS0FSRU1HRktISU5IUVZWUFRMQVZTS05LQUxRQUlFTFFMVExFVElZTlNRWVNORUtXVExRRFZTTEVWWUxUQVBUR0NJS0tIR1lUVkVWUUZER0RJQ05UTUhZVE5XVEhJWUlDRUVBb2pzIFNWVFZWRUdRVkRZWUdMWVlWSEVHSVJUWUZWUUZLRERBRUtZU0tOS1ZXRVZIQUdHUVZJTENQVFNWRlNTTkVWU1NQRUlJUlFITEFOSFBBQVRIVEtBVkFMR1RFRVRRVFRJUVJQUlNFUERUR05QQ0hUVEtMTEhSRFNWRFNBUElMVEFGTlNTSEtHUklOQ05TTlRUUElWSExLR0RBTlRMS0NMUllSRktLSENUTFlUQVZTU1RXSFdUR0hOVktIS1NBSVZUTFRZRFNFV1FSRFFGTFNRVktJUEtUSVRWU1RHRk1TSVwiO1xuICogdmFyIG15U2VxdWVuY2UgPSBuZXcgU2VxdWVuY2Uoe1xuICogXHRcdHNlcXVlbmNlIDogdGhlU2VxdWVuY2UsXG4gKiBcdFx0dGFyZ2V0IDogXCJZb3VyT3duRGl2SWRcIixcbiAqIFx0XHRmb3JtYXQgOiAnQ09EQVRBJyxcbiAqIFx0XHRpZCA6ICdQOTE4MjgzJyxcbiAqIFx0XHRhbm5vdGF0aW9uczogW1xuICogICAgICAgIHsgbmFtZTpcIkNBVEhcIiwgXG4gKiBcdCAgXHRcdGNvbG9yOlwiI0YwRjAyMFwiLCBcbiAqIFx0ICBcdFx0aHRtbDogXCJVc2luZyBjb2xvciBjb2RlICNGMEYwMjAgXCIsIFxuICogXHQgIFx0XHRyZWdpb25zOiBbe3N0YXJ0OiAxMjIsIGVuZDogMTM1fV1cbiAqIFx0XHQgIH0sXG4gKiAgICAgICAgeyBuYW1lOlwiVEVTVFwiLCBcbiAqICAgICAgICAgIGh0bWw6XCImbHQ7YnImZ3Q7IEV4YW1wbGUgb2YgJmx0O2ImZ3Q7SFRNTCZsdDsvYiZndDtcIiwgXG4gKiAgICAgICAgICBjb2xvcjpcImdyZWVuXCIsIFxuICogICAgICAgICAgcmVnaW9uczogW1xuICogICAgICAgICAgICB7c3RhcnQ6IDI4NSwgZW5kOiAyOTJ9LFxuICogICAgICAgICAgICB7c3RhcnQ6IDI5MywgZW5kOiAzMTQsIGNvbG9yOiBcIiMyRTQ5ODhcIn1dXG4gKiAgICAgICAgfVxuICogICAgICBdLFxuICogICAgICBoaWdobGlnaHRzIDogW1xuICogICAgICBcdHsgc3RhcnQ6MzAsIGVuZDo0MiwgY29sb3I6XCJ3aGl0ZVwiLCBiYWNrZ3JvdW5kOlwiZ3JlZW5cIiwgaWQ6XCJzcGluMVwiIH0sXG4gKiAgICAgIFx0eyBzdGFydDoxMzksIGVuZDoxNDAgfSwgXG4gKiAgICAgIFx0eyBzdGFydDo2MzEsIGVuZDo2MzMsIGNvbG9yOlwid2hpdGVcIiwgYmFja2dyb3VuZDpcImJsdWVcIiB9XG4gKiAgICAgIF1cbiAqIH0pO1x0XG4gKiBcbiAqL1xuXG52YXIgQ2xhc3MgPSByZXF1aXJlKCdqcy1jbGFzcycpO1xuXG52YXIgRVZUX09OX1NFTEVDVElPTl9DSEFOR0U9IFwib25TZWxlY3Rpb25DaGFuZ2VcIjtcbnZhciBFVlRfT05fU0VMRUNUSU9OX0NIQU5HRUQ9IFwib25TZWxlY3Rpb25DaGFuZ2VkXCI7XG52YXIgRVZUX09OX0FOTk9UQVRJT05fQ0xJQ0tFRD0gXCJvbkFubm90YXRpb25DbGlja2VkXCI7XG5cblNlcXVlbmNlID0gQ2xhc3MoXG4vKiogQGxlbmRzIFNlcXVlbmNlIyAqL1xue1x0XG5cdGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuXHRcdHZhciBzZWxmID0gdGhpcztcblxuICAgIHRoaXMub3B0ID0galF1ZXJ5LmV4dGVuZCh0aGlzLm9wdCxvcHRpb25zKTtcblxuICAgIHRoaXMuX2NvbnRhaW5lciA9IGpRdWVyeSh0aGlzLm9wdC50YXJnZXQgKTtcbiAgICBcbiAgICAvLyBsZWdhY3kgc3VwcG9ydCAodGFyZ2V0IGlkIHdpdGhvdXQgJyMnKVxuICAgIGlmKHRoaXMuX2NvbnRhaW5lci5sZW5ndGggPT0gMCl7XG4gICAgICB0aGlzLl9jb250YWluZXIgPSBqUXVlcnkoIFwiI1wiICsgdGhpcy5vcHQudGFyZ2V0IClcbiAgICB9XG5cbiAgICBpZih0aGlzLl9jb250YWluZXIubGVuZ3RoID09IDApe1xuICAgICAgY29uc29sZS5sb2coXCJlbXB0eSB0YXJnZXQgY29udGFpbmVyXCIpO1xuICAgIH1cblxuICAgIC8vIGxlZ2FjeTogY29weSB0YXJnZXQgaWRcbiAgICB0aGlzLm9wdC50YXJnZXQgPSB0aGlzLl9jb250YWluZXJbMF0uaWQ7XG5cdFx0XG5cdFx0Ly8gTGF6eSBpbml0aWFsaXphdGlvbiBcblx0XHR0aGlzLl9jb250YWluZXIucmVhZHkoZnVuY3Rpb24oKSB7XG5cdFx0XHRzZWxmLl9pbml0aWFsaXplKCk7XG5cdFx0fSk7XG5cdH0sXG5cdFxuXHQvKipcblx0ICogRGVmYXVsdCB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zXG5cdCAqIEBuYW1lIFNlcXVlbmNlLW9wdFxuXHQgKi9cblx0b3B0IDoge1xuXHRcdFxuXHRcdHNlcXVlbmNlIDogXCJcIixcblx0XHRpZCA6IFwiXCIsXG5cdFx0dGFyZ2V0IDogXCJcIixcblx0XHRmb3JtYXQgOiBcIkZBU1RBXCIsXG5cdFx0c2VsZWN0aW9uOiB7IHN0YXJ0OiAwLCBlbmQ6IDAgfSxcblx0XHRjb2x1bW5zOiB7IHNpemU6IDM1LCBzcGFjZWRFYWNoOiAxMCB9LFxuXHRcdGhpZ2hsaWdodHMgOiBbXSxcblx0XHRhbm5vdGF0aW9uczogW10sXG5cdFx0c2VxdWVuY2VVcmw6ICdodHRwOi8vd3d3LmViaS5hYy51ay9kYXMtc3J2L3VuaXByb3QvZGFzL3VuaXByb3Qvc2VxdWVuY2UnLFxuXHRcdFxuXHRcdC8vIFN0eWxlcyBcblx0XHRzZWxlY3Rpb25Db2xvciA6ICdZZWxsb3cnLFxuXHRcdHNlbGVjdGlvbkZvbnRDb2xvciA6ICdibGFjaycsXG5cdFx0aGlnaGxpZ2h0Rm9udENvbG9yIDogJ3JlZCcsXG5cdFx0aGlnaGxpZ2h0QmFja2dyb3VuZENvbG9yIDogJ3doaXRlJyxcblx0XHRmb250RmFtaWx5OiAnXCJBbmRhbGUgbW9ub1wiLCBjb3VyaWVyLCBtb25vc3BhY2UnLFxuXHRcdGZvbnRTaXplOiAnMTJweCcsXG5cdFx0Zm9udENvbG9yIDogJ2luaGVyaXQnLFxuXHRcdGJhY2tncm91bmRDb2xvciA6ICdpbmhlcml0Jyxcblx0XHR3aWR0aDogdW5kZWZpbmVkLFxuXHRcdGhlaWdodDogdW5kZWZpbmVkLFxuXHRcdGZvcm1hdFNlbGVjdG9yVmlzaWJsZTogdHJ1ZVxuXHR9LFxuXHRcblx0LyoqXG5cdCAqIEFycmF5IGNvbnRhaW5pbmcgdGhlIHN1cHBvcnRlZCBldmVudCBuYW1lc1xuXHQgKiBAbmFtZSBTZXF1ZW5jZS1ldmVudFR5cGVzXG5cdCAqL1xuXHRldmVudFR5cGVzIDogW1xuXHRcdC8qKlxuXHRcdCAqIEBuYW1lIFNlcXVlbmNlI29uU2VsZWN0aW9uQ2hhbmdlZFxuXHRcdCAqIEBldmVudFxuXHRcdCAqIEBwYXJhbSB7ZnVuY3Rpb259IGFjdGlvblBlcmZvcm1lZCBBbiBmdW5jdGlvbiB3aGljaCByZWNlaXZlcyBhbiB7QGxpbmsgQmlvanMuRXZlbnR9IG9iamVjdCBhcyBhcmd1bWVudC5cblx0XHQgKiBAZXZlbnREYXRhIHtPYmplY3R9IHNvdXJjZSBUaGUgY29tcG9uZW50IHdoaWNoIGRpZCB0cmlnZ2VyZWQgdGhlIGV2ZW50LlxuXHRcdCAqIEBldmVudERhdGEge3N0cmluZ30gdHlwZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnQuXG5cdFx0ICogQGV2ZW50RGF0YSB7aW50fSBzdGFydCBBIG51bWJlciBpbmRpY2F0aW5nIHRoZSBzdGFydCBvZiB0aGUgc2VsZWN0aW9uLlxuXHRcdCAqIEBldmVudERhdGEge2ludH0gZW5kIEEgbnVtYmVyIGluZGljYXRpbmcgdGhlIGVuZGluZyBvZiBzZWxlY3Rpb24uXG5cdFx0ICogQGV4YW1wbGUgXG5cdFx0ICogbXlTZXF1ZW5jZS5vblNlbGVjdGlvbkNoYW5nZWQoXG5cdFx0ICogICAgZnVuY3Rpb24oIG9iakV2ZW50ICkge1xuXHRcdCAqICAgICAgIGFsZXJ0KFwiU2VsZWN0ZWQ6IFwiICsgb2JqRXZlbnQuc3RhcnQgKyBcIiwgXCIgKyBvYmpFdmVudC5lbmQgKTtcblx0XHQgKiAgICB9XG5cdFx0ICogKTsgXG5cdFx0ICogXG5cdFx0ICogKi9cblx0XHRcIm9uU2VsZWN0aW9uQ2hhbmdlZFwiLFxuXHRcdFxuXHRcdC8qKlxuXHRcdCAqIEBuYW1lIFNlcXVlbmNlI29uU2VsZWN0aW9uQ2hhbmdlXG5cdFx0ICogQGV2ZW50XG5cdFx0ICogQHBhcmFtIHtmdW5jdGlvbn0gYWN0aW9uUGVyZm9ybWVkIEFuIGZ1bmN0aW9uIHdoaWNoIHJlY2VpdmVzIGFuIHtAbGluayBCaW9qcy5FdmVudH0gb2JqZWN0IGFzIGFyZ3VtZW50LlxuXHRcdCAqIEBldmVudERhdGEge09iamVjdH0gc291cmNlIFRoZSBjb21wb25lbnQgd2hpY2ggZGlkIHRyaWdnZXJlZCB0aGUgZXZlbnQuXG5cdFx0ICogQGV2ZW50RGF0YSB7c3RyaW5nfSB0eXBlIFRoZSBuYW1lIG9mIHRoZSBldmVudC5cblx0XHQgKiBAZXZlbnREYXRhIHtpbnR9IHN0YXJ0IEEgbnVtYmVyIGluZGljYXRpbmcgdGhlIHN0YXJ0IG9mIHRoZSBzZWxlY3Rpb24uXG5cdFx0ICogQGV2ZW50RGF0YSB7aW50fSBlbmQgQSBudW1iZXIgaW5kaWNhdGluZyB0aGUgZW5kaW5nIG9mIHNlbGVjdGlvbi5cblx0XHQgKiBAZXhhbXBsZSBcblx0XHQgKiBteVNlcXVlbmNlLm9uU2VsZWN0aW9uQ2hhbmdlKFxuXHRcdCAqICAgIGZ1bmN0aW9uKCBvYmpFdmVudCApIHtcblx0XHQgKiAgICAgICBhbGVydChcIlNlbGVjdGlvbiBpbiBwcm9ncmVzczogXCIgKyBvYmpFdmVudC5zdGFydCArIFwiLCBcIiArIG9iakV2ZW50LmVuZCApO1xuXHRcdCAqICAgIH1cblx0XHQgKiApOyAgXG5cdFx0ICogXG5cdFx0ICogXG5cdFx0ICogKi9cblx0XHRcIm9uU2VsZWN0aW9uQ2hhbmdlXCIsXG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogQG5hbWUgU2VxdWVuY2Ujb25Bbm5vdGF0aW9uQ2xpY2tlZFxuXHRcdCAqIEBldmVudFxuXHRcdCAqIEBwYXJhbSB7ZnVuY3Rpb259IGFjdGlvblBlcmZvcm1lZCBBbiBmdW5jdGlvbiB3aGljaCByZWNlaXZlcyBhbiB7QGxpbmsgQmlvanMuRXZlbnR9IG9iamVjdCBhcyBhcmd1bWVudC5cblx0XHQgKiBAZXZlbnREYXRhIHtPYmplY3R9IHNvdXJjZSBUaGUgY29tcG9uZW50IHdoaWNoIGRpZCB0cmlnZ2VyZWQgdGhlIGV2ZW50LlxuXHRcdCAqIEBldmVudERhdGEge3N0cmluZ30gdHlwZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnQuXG5cdFx0ICogQGV2ZW50RGF0YSB7c3RyaW5nfSBuYW1lIFRoZSBuYW1lIG9mIHRoZSBzZWxlY3RlZCBhbm5vdGF0aW9uLlxuXHRcdCAqIEBldmVudERhdGEge2ludH0gcG9zIEEgbnVtYmVyIGluZGljYXRpbmcgdGhlIHBvc2l0aW9uIG9mIHRoZSBzZWxlY3RlZCBhbWlubyBhY2lkLlxuXHRcdCAqIEBleGFtcGxlIFxuXHRcdCAqIG15U2VxdWVuY2Uub25Bbm5vdGF0aW9uQ2xpY2tlZChcblx0XHQgKiAgICBmdW5jdGlvbiggb2JqRXZlbnQgKSB7XG5cdFx0ICogICAgICAgYWxlcnQoXCJDbGlja2VkIFwiICsgb2JqRXZlbnQubmFtZSArIFwiIG9uIHBvc2l0aW9uIFwiICsgb2JqRXZlbnQucG9zICk7XG5cdFx0ICogICAgfVxuXHRcdCAqICk7ICBcblx0XHQgKiBcblx0XHQgKiAqL1xuXHRcdFwib25Bbm5vdGF0aW9uQ2xpY2tlZFwiXG5cdF0sXG5cbiAgZ2V0SWQgOiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMub3B0LmlkO1xuICB9LFxuXG5cdC8vIGludGVybmFsIG1lbWJlcnNcblx0X2hlYWRlckRpdiA6IG51bGwsXG5cdF9jb250ZW50RGl2IDogbnVsbCxcblx0XG5cdC8vIE1ldGhvZHNcblxuXHRfaW5pdGlhbGl6ZTogZnVuY3Rpb24gKCkge1xuXHRcdFxuXHRcdGlmICggdGhpcy5vcHQud2lkdGggIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuX2NvbnRhaW5lci53aWR0aCggdGhpcy5vcHQud2lkdGggKTtcblx0XHR9XG5cdFx0XG5cdFx0aWYgKCB0aGlzLm9wdC5oZWlnaHQgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuX2NvbnRhaW5lci5oZWlnaHQoIHRoaXMub3B0LmhlaWdodCApO1xuXHRcdH1cblx0XHRcblx0XHQvLyBEaXNhYmxlIHRleHQgc2VsZWN0aW9uXG5cdFx0XG5cdFx0dGhpcy5fY29udGFpbmVyLmNzcyh7XG5cdFx0XHQnLW1vei11c2VyLXNlbGVjdCc6J25vbmUnLFxuXHRcdFx0Jy13ZWJraXQtdXNlci1zZWxlY3QnOidub25lJyxcblx0XHRcdCd1c2VyLXNlbGVjdCc6J25vbmUnXG4gICAgICAgIH0pO1xuXHRcdFxuXHRcdC8vIERJViBmb3IgdGhlIGZvcm1hdCBzZWxlY3RvclxuXHRcdHRoaXMuX2J1aWxkRm9ybWF0U2VsZWN0b3IoKTtcblx0XHRcblx0XHQvLyBESVYgZm9yIHRoZSBzZXF1ZW5jZVxuXHRcdHRoaXMuX2NvbnRlbnREaXYgPSBqUXVlcnkoJzxkaXY+PC9kaXY+JykuYXBwZW5kVG8odGhpcy5fY29udGFpbmVyKTtcblx0XHR0aGlzLl9jb250ZW50RGl2LmNzcyh7XG5cdFx0XHRcdCdmb250LWZhbWlseSc6IHRoaXMub3B0LmZvbnRGYW1pbHksXG5cdFx0XHRcdCdmb250LXNpemUnOiB0aGlzLm9wdC5mb250U2l6ZSxcblx0XHRcdFx0J3RleHQtYWxpZ24nOiAnbGVmdCdcblx0XHRcdH0pO1xuXHRcdFxuXHRcdC8vIEluaXRpYWxpemUgaGlnaGxpZ2h0aW5nIFxuXHRcdHRoaXMuX2hpZ2hsaWdodHMgPSB0aGlzLm9wdC5oaWdobGlnaHRzO1xuXHRcdFxuXHRcdC8vIEluaXRpYWxpemUgYW5ub3RhdGlvbnNcblx0XHR0aGlzLl9hbm5vdGF0aW9ucyA9IHRoaXMub3B0LmFubm90YXRpb25zO1xuXHRcdFxuXHRcdC8vSW5pdGlhbGl6ZSB0b29sdGlwXG5cdFx0dmFyIHRvb2x0aXAgPSBcInNlcXVlbmNlVGlwXCIgKyB0aGlzLm9wdC50YXJnZXQgO1xuXHRcdGpRdWVyeSgnPGRpdiBpZD1cIicgKyB0b29sdGlwICsgJ1wiPjwvZGl2PicpIFxuXHQgICAgICAgIC5jc3Moe1x0XG5cdCAgICAgICAgXHQncG9zaXRpb24nOiBcImFic29sdXRlXCIsXG5cdCAgICAgICAgXHQnei1pbmRleCc6IFwiOTk5OTk5XCIsXG5cdCAgICAgICAgXHQnY29sb3InOiBcIiNmZmZcIixcblx0ICAgICAgICBcdCdmb250LXNpemUnOiBcIjEycHhcIixcblx0ICAgICAgICBcdCd3aWR0aCc6IFwiYXV0b1wiLFxuXHQgICAgICAgIFx0J2Rpc3BsYXknOiAnbm9uZSdcblx0ICAgICAgICB9KVxuXHQgICAgICAgIC5hZGRDbGFzcyhcInRvb2x0aXBcIilcblx0ICAgICAgICAuYXBwZW5kVG8oXCJib2R5XCIpXG5cdCAgICAgICAgLmhpZGUoKTtcblx0XHR0aGlzLm9wdC5fdG9vbHRpcCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRvb2x0aXApO1xuXG5cdFx0aWYgKCAodGhpcy5vcHQuc2VxdWVuY2UpICkge1xuXHRcdFx0dGhpcy5fcmVkcmF3KCk7XG5cdFx0XHRcblx0XHR9IGVsc2UgaWYgKCAgKHRoaXMub3B0LmlkKSApIHtcblx0XHRcdHRoaXMuX3JlcXVlc3RTZXF1ZW5jZSggdGhpcy5vcHQuaWQgKTtcblx0XHRcdFxuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmNsZWFyU2VxdWVuY2UoXCJObyBzZXF1ZW5jZSBhdmFpbGFibGVcIiwgXCIuLi9iaW9qcy9jc3MvaW1hZ2VzL3dhcm5pbmdfaWNvbi5wbmdcIik7XG5cdFx0fVxuXHRcdFxuXHR9LFxuXHRcblx0XG5cdC8qKlxuXHQgKiBTaG93cyB0aGUgY29sdW1ucyBpbmRpY2F0ZWQgYnkgdGhlIGluZGV4ZXMgYXJyYXkuXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzZXEgVGhlIHNlcXVlbmNlIHN0cmFuZC5cblx0ICogQHBhcmFtIHtzdHJpbmd9IFtpZGVudGlmaWVyXSBTZXF1ZW5jZSBpZGVudGlmaWVyLlxuXHQgKiBcblx0ICogQGV4YW1wbGUgXG5cdCAqIG15U2VxdWVuY2Uuc2V0U2VxdWVuY2UoXCJQOTk5OTlcIik7XG5cdCAqIFxuXHQgKi9cbiAgICBzZXRTZXF1ZW5jZTogZnVuY3Rpb24gKCBzZXEsIGlkZW50aWZpZXIgKSB7XG5cbiAgICBcdGlmICggc2VxLm1hdGNoKC9eKFtBLU4sUi1aXVswLTldW0EtWl1bQS1aLCAwLTldW0EtWiwgMC05XVswLTldKXwoW08sUCxRXVswLTldW0EtWiwgMC05XVtBLVosIDAtOV1bQS1aLCAwLTldWzAtOV0pKFxcLlxcZCspPyQvaSkgKSB7XG4gICAgXHRcdHRoaXMuX3JlcXVlc3RTZXF1ZW5jZSggYXJndW1lbnRzWzBdICk7XG4gICAgXHRcdFxuICAgIFx0fSBlbHNlIHtcbiAgICBcdFx0dGhpcy5vcHQuc2VxdWVuY2UgPSBzZXE7XG4gICAgICAgIFx0dGhpcy5vcHQuaWQgPSBpZGVudGlmaWVyOyBcbiAgICAgICAgXHR0aGlzLl9oaWdobGlnaHRzID0gW107XG4gICAgXHRcdHRoaXMuX2hpZ2hsaWdodHNDb3VudCA9IDA7XG4gICAgXHRcdHRoaXMub3B0LnNlbGVjdGlvbiA9IHsgc3RhcnQ6IDAsIGVuZDogMCB9O1xuICAgIFx0XHR0aGlzLl9hbm5vdGF0aW9ucyA9IFtdO1xuICAgIFx0XHRcbiAgICBcdFx0dGhpcy5fY29udGVudERpdi5jaGlsZHJlbigpLnJlbW92ZSgpO1xuICAgIFx0XHR0aGlzLl9yZWRyYXcoKTtcbiAgICBcdH1cbiAgICB9LFxuICAgIFxuICAgIF9yZXF1ZXN0U2VxdWVuY2U6IGZ1bmN0aW9uICggYWNjZXNzaW9uICkge1xuXHRcdHZhciBzZWxmID0gdGhpcztcbiAgICBcdFxuICAgIFx0Y29uc29sZS5sb2coXCJSZXF1ZXN0aW5nIHNlcXVlbmNlIGZvcjogXCIgKyBhY2Nlc3Npb24gKTtcblxuXHRcdGpRdWVyeS5hamF4KHsgXG5cdFx0XHR1cmw6IHNlbGYub3B0LnNlcXVlbmNlVXJsLFxuXHRcdFx0ZGF0YVR5cGU6IFwieG1sXCIsXG5cdFx0XHRkYXRhOiB7IHNlZ21lbnQ6IGFjY2Vzc2lvbiB9LFxuXHRcdFx0c3VjY2VzczogZnVuY3Rpb24gKCB4bWwgICkge1xuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFxuXHRcdFx0XHRcdHZhciBzZXF1ZW5jZU5vZGUgPSBqUXVlcnkoeG1sKS5maW5kKCdTRVFVRU5DRTpmaXJzdCcpO1xuXHRcdFx0XHRcdHNlbGYuc2V0U2VxdWVuY2UoIHNlcXVlbmNlTm9kZS50ZXh0KCksIHNlcXVlbmNlTm9kZS5hdHRyKFwiaWRcIiksIHNlcXVlbmNlTm9kZS5hdHRyKFwibGFiZWxcIikgKTtcblx0XHRcdFx0XHRcblx0XHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRcdGNvbnNvbGUubG9nKFwiRXJyb3IgZGVjb2RpbmcgcmVzcG9uc2UgZGF0YTogXCIgKyBlLm1lc3NhZ2UgKTtcblx0XHRcdFx0XHRzZWxmLmNsZWFyU2VxdWVuY2UoXCJObyBzZXF1ZW5jZSBhdmFpbGFibGVcIiwgXCIuLi9iaW9qcy9jc3MvaW1hZ2VzL3dhcm5pbmdfaWNvbi5wbmdcIik7XG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblx0XHRcdGVycm9yOiBmdW5jdGlvbiAoanFYSFIsIHRleHRTdGF0dXMsIGVycm9yVGhyb3duKSB7XG5cdFx0XHRcdGNvbnNvbGUubG9nKFwiRXJyb3IgZGVjb2RpbmcgcmVzcG9uc2UgZGF0YTogXCIgKyB0ZXh0U3RhdHVzICk7XG5cdFx0XHRcdHNlbGYuY2xlYXJTZXF1ZW5jZShcIkVycm9yIHJlcXVlc3RpbmcgdGhlIHNlcXVlbmNlIHRvIHRoZSBzZXJ2ZXIgXCIgKyB0aGlzLnVybCAsIFwiLi4vYmlvanMvY3NzL2ltYWdlcy93YXJuaW5nX2ljb24ucG5nXCIpO1xuXHRcdFx0fVxuXHRcdH0pO1xuICAgIH0sXG5cdFxuICAgIC8qKlxuXHQgKiBTaG93cyB0aGUgY29sdW1ucyBpbmRpY2F0ZWQgYnkgdGhlIGluZGV4ZXMgYXJyYXkuXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBbc2hvd01lc3NhZ2VdIE1lc3NhZ2UgdG8gYmUgc2hvd2VkLlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gW2ljb25dIEljb24gdG8gYmUgc2hvd2VkIGEgc2lkZSBvZiB0aGUgbWVzc2FnZVxuXHQgKiBcblx0ICogQGV4YW1wbGUgXG5cdCAqIG15U2VxdWVuY2UuY2xlYXJTZXF1ZW5jZShcIk5vIHNlcXVlbmNlIGF2YWlsYWJsZVwiLCBcIi4uL2Jpb2pzL2Nzcy9pbWFnZXMvd2FybmluZ19pY29uLnBuZ1wiKTtcblx0ICogXG5cdCAqL1xuICAgIGNsZWFyU2VxdWVuY2U6IGZ1bmN0aW9uICggc2hvd01lc3NhZ2UsIGljb24gKSB7XG4gICAgXHRcbiAgICBcdHZhciBtZXNzYWdlID0gdW5kZWZpbmVkO1xuICAgIFx0XHRcbiAgICBcdHRoaXMub3B0LnNlcXVlbmNlID0gXCJcIjtcbiAgICBcdHRoaXMub3B0LmlkID0gXCJcIjsgXG4gICAgXHR0aGlzLl9oaWdobGlnaHRzID0gW107XG5cdFx0dGhpcy5faGlnaGxpZ2h0c0NvdW50ID0gMDtcblx0XHR0aGlzLm9wdC5zZWxlY3Rpb24gPSB7IHN0YXJ0OiAwLCBlbmQ6IDAgfTtcblx0XHR0aGlzLl9hbm5vdGF0aW9ucyA9IFtdO1xuXHRcdHRoaXMuX2NvbnRlbnREaXYuY2hpbGRyZW4oKS5yZW1vdmUoKTtcblx0XHRcblx0XHR0aGlzLl9oZWFkZXJEaXYuaGlkZSgpO1xuXHRcdFxuXHRcdGlmICggdW5kZWZpbmVkICE9PSBzaG93TWVzc2FnZSApIHtcblx0XHRcdG1lc3NhZ2UgPSBqUXVlcnkoJzxkaXY+JyArIHNob3dNZXNzYWdlICsgJzwvZGl2PicpXG5cdFx0XHRcdC5hcHBlbmRUbyh0aGlzLl9jb250ZW50RGl2KVxuXHRcdFx0XHQuYWRkQ2xhc3MoXCJtZXNzYWdlXCIpO1xuXHRcdFx0XG5cdFx0XHRpZiAoIHVuZGVmaW5lZCAhPT0gaWNvbiApIHtcblx0XHRcdFx0bWVzc2FnZS5jc3Moe1xuXHRcdFx0XHRcdCdiYWNrZ3JvdW5kJzogJ3RyYW5zcGFyZW50IHVybChcIicgKyBpY29uICsgJ1wiKSBuby1yZXBlYXQgY2VudGVyIGxlZnQnLFxuXHRcdFx0XHRcdCdwYWRkaW5nLWxlZnQnOiAnMjBweCdcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0fVxuICAgIH0sXG5cdFxuXHQvKipcbiAgICAqIFNldCB0aGUgY3VycmVudCBzZWxlY3Rpb24gaW4gdGhlIHNlcXVlbmNlIGNhdXNpbmcgdGhlIGV2ZW50IHtAbGluayBTZXF1ZW5jZSNvblNlbGVjdGlvbkNoYW5nZWR9XG4gICAgKlxuICAgICogQGV4YW1wbGVcbiAgICAqIC8vIHNldCBzZWxlY3Rpb24gZnJvbSB0aGUgcG9zaXRpb24gMTAwIHRvIDE1MCBcbiAgICAqIG15U2VxdWVuY2Uuc2V0U2VsZWN0aW9uKDEwMCwgMTUwKTtcbiAgICAqIFxuICAgICogQHBhcmFtIHtpbnR9IHN0YXJ0IFRoZSBzdGFydGluZyBjaGFyYWN0ZXIgb2YgdGhlIHNlbGVjdGlvbi5cbiAgICAqIEBwYXJhbSB7aW50fSBlbmQgVGhlIGVuZGluZyBjaGFyYWN0ZXIgb2YgdGhlIHNlbGVjdGlvblxuICAgICovXG5cdHNldFNlbGVjdGlvbiA6IGZ1bmN0aW9uKHN0YXJ0LCBlbmQpIHtcblx0XHRpZihzdGFydCA+IGVuZCkge1xuXHRcdFx0dmFyIGF1eCA9IGVuZDtcblx0XHRcdGVuZCA9IHN0YXJ0O1xuXHRcdFx0c3RhcnQgPSBhdXg7XG5cblx0XHR9XG5cblx0XHRpZihzdGFydCAhPSB0aGlzLm9wdC5zZWxlY3Rpb24uc3RhcnQgfHwgZW5kICE9IHRoaXMub3B0LnNlbGVjdGlvbi5lbmQpIHtcblx0XHRcdHRoaXMuX3NldFNlbGVjdGlvbihzdGFydCwgZW5kKTtcblx0XHRcdHRoaXMudHJpZ2dlcihcblx0XHRcdFx0XHRFVlRfT05fU0VMRUNUSU9OX0NIQU5HRUQsIFxuXHRcdFx0XHRcdHsgXCJzdGFydFwiIDogc3RhcnQsIFwiZW5kXCIgOiBlbmQgfVxuXHRcdFx0KTtcblx0XHR9XG5cdH0sXG5cdFxuXHRfYnVpbGRGb3JtYXRTZWxlY3RvcjogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBzZWxmID0gdGhpcztcblx0XHRcblx0XHR0aGlzLl9oZWFkZXJEaXYgPSBqUXVlcnkoJzxkaXY+PC9kaXY+JykuYXBwZW5kVG8odGhpcy5fY29udGFpbmVyKTtcblx0XHR0aGlzLl9oZWFkZXJEaXYuY3NzKHtcblx0XHRcdCdmb250LWZhbWlseSc6ICdcIkhldmVsdGljYSBOZXVlXCIsIEFyaWFsLCBcInNhbnMgc2VyaWZcIicsXG5cdFx0XHQnZm9udC1zaXplJzogJzE0cHgnXHRcblx0XHR9KS5hcHBlbmQoJ0Zvcm1hdDogJyk7XG5cdFx0XG5cdFx0dGhpcy5fZm9ybWF0U2VsZWN0b3IgPSBqUXVlcnkoJzxzZWxlY3Q+ICcrXG5cdFx0XHRcdCc8b3B0aW9uIHZhbHVlPVwiRkFTVEFcIj5GQVNUQTwvb3B0aW9uPicrXG5cdFx0XHRcdCc8b3B0aW9uIHZhbHVlPVwiQ09EQVRBXCI+Q09EQVRBPC9vcHRpb24+Jytcblx0XHRcdFx0JzxvcHRpb24gdmFsdWU9XCJQUklERVwiPlBSSURFPC9vcHRpb24+Jytcblx0XHRcdFx0JzxvcHRpb24gdmFsdWU9XCJSQVdcIj5SQVc8L29wdGlvbj48L3NlbGVjdD4nKS5hcHBlbmRUbyhzZWxmLl9oZWFkZXJEaXYpO1xuXG5cdFx0dGhpcy5fZm9ybWF0U2VsZWN0b3IuY2hhbmdlKGZ1bmN0aW9uKGUpIHtcblx0XHRcdHNlbGYub3B0LmZvcm1hdCA9IGpRdWVyeSh0aGlzKS52YWwoKTtcblx0XHRcdHNlbGYuX3JlZHJhdygpO1xuXHRcdH0pO1xuXHRcdFxuXHRcdHRoaXMuX2Zvcm1hdFNlbGVjdG9yLnZhbChzZWxmLm9wdC5mb3JtYXQpO1x0XG5cdFx0XG5cdFx0dGhpcy5mb3JtYXRTZWxlY3RvclZpc2libGUoIHRoaXMub3B0LmZvcm1hdFNlbGVjdG9yVmlzaWJsZSApO1xuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBIaWdobGlnaHRzIGEgcmVnaW9uIHVzaW5nIHRoZSBmb250IGNvbG9yIGRlZmluZWQgaW4ge0Jpb2pzLlByb3RlaW4zRCNoaWdobGlnaHRGb250Q29sb3J9IGJ5IGRlZmF1bHQgaXMgcmVkLlxuICAgICpcbiAgICAqIEBkZXByZWNhdGVkIHVzZSBhZGRIaWdobGlnaHQgaW5zdGVhZC5cbiAgICAqIFxuICAgICogQHBhcmFtIHtpbnR9IHN0YXJ0IFRoZSBzdGFydGluZyBjaGFyYWN0ZXIgb2YgdGhlIGhpZ2hsaWdodGluZy5cbiAgICAqIEBwYXJhbSB7aW50fSBlbmQgVGhlIGVuZGluZyBjaGFyYWN0ZXIgb2YgdGhlIGhpZ2hsaWdodGluZy5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBbY29sb3JdIEhUTUwgY29sb3IgY29kZS5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBbYmFja2dyb3VuZF0gSFRNTCBjb2xvciBjb2RlLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IFtpZF0gQ3VzdG9tIGlkZW50aWZpZXIuXG4gICAgKiBcbiAgICAqIEByZXR1cm4ge2ludH0gcmVwcmVzZW50aW5nIHRoZSBpZCBvZiB0aGUgaGlnaGxpZ2h0IG9uIHRoZSBpbnRlcm5hbCBhcnJheS4gUmV0dXJucyAtMSBvbiBmYWlsdXJlICBcbiAgICAqL1xuXHRoaWdobGlnaHQgOiBmdW5jdGlvbiAoc3RhcnQsIGVuZCwgY29sb3IsIGJhY2tncm91bmQsIGlkICkge1xuXHRcdHJldHVybiB0aGlzLmFkZEhpZ2hsaWdodCh7IFwic3RhcnRcIjogc3RhcnQsIFwiZW5kXCI6IGVuZCwgXCJjb2xvclwiOiBjb2xvciwgXCJiYWNrZ3JvdW5kXCI6IGJhY2tncm91bmQsIFwiaWRcIjogaWQgfSk7XG5cdH0sXG5cdFxuXHQvKipcbiAgICAqIEhpZ2hsaWdodHMgYSByZWdpb24gdXNpbmcgdGhlIGZvbnQgY29sb3IgZGVmaW5lZCBpbiB7U2VxdWVuY2UjaGlnaGxpZ2h0Rm9udENvbG9yfSBieSBkZWZhdWx0IGlzIHJlZC5cbiAgICAqXG4gICAgKiBAZXhhbXBsZVxuICAgICogLy8gaGlnaGxpZ2h0IHRoZSBjaGFyYWN0ZXJzIHdpdGhpbiB0aGUgcG9zaXRpb24gMTAwIHRvIDE1MCwgaW5jbHVkZWQuXG4gICAgKiBteVNlcXVlbmNlLmFkZEhpZ2hsaWdodCggeyBcInN0YXJ0XCI6IDEwMCwgXCJlbmRcIjogMTUwLCBcImNvbG9yXCI6IFwid2hpdGVcIiwgXCJiYWNrZ3JvdW5kXCI6IFwicmVkXCIsIFwiaWRcIjogXCJhYWFcIiB9ICk7XG4gICAgKiBcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBoIFRoZSBoaWdobGlnaHQgZGVmaW5lZCBhcyBmb2xsb3dzOlxuICAgICogXHRcbiAgICAqIFxuICAgICogQHJldHVybiB7aW50fSByZXByZXNlbnRpbmcgdGhlIGlkIG9mIHRoZSBoaWdobGlnaHQgb24gdGhlIGludGVybmFsIGFycmF5LiBSZXR1cm5zIC0xIG9uIGZhaWx1cmUgIFxuICAgICovXG5cdGFkZEhpZ2hsaWdodCA6IGZ1bmN0aW9uICggaCApIHtcblx0XHR2YXIgaWQgPSAnLTEnO1xuXHRcdHZhciBjb2xvciA9IFwiXCI7XG5cdFx0dmFyIGJhY2tncm91bmQgPSBcIlwiO1xuXHRcdHZhciBoaWdobGlnaHQgPSB7fTtcblx0XHRcblx0XHRpZiAoIGggaW5zdGFuY2VvZiBPYmplY3QgJiYgaC5zdGFydCA8PSBoLmVuZCApIHtcblx0XHRcdFxuXHRcdFx0Y29sb3IgPSAoIFwic3RyaW5nXCIgPT0gdHlwZW9mIGguY29sb3IgKT8gaC5jb2xvciA6IHRoaXMub3B0LmhpZ2hsaWdodEZvbnRDb2xvcjtcblx0XHRcdGJhY2tncm91bmQgPSAoIFwic3RyaW5nXCIgPT0gdHlwZW9mIGguYmFja2dyb3VuZCApPyBoLmJhY2tncm91bmQgOiB0aGlzLm9wdC5oaWdobGlnaHRCYWNrZ3JvdW5kQ29sb3I7XG5cdFx0XHRpZCA9ICggXCJzdHJpbmdcIiA9PSB0eXBlb2YgaC5pZCApPyBoLmlkIDogKG5ldyBOdW1iZXIodGhpcy5faGlnaGxpZ2h0c0NvdW50KyspKS50b1N0cmluZygpO1xuXHRcdFx0XG5cdFx0XHRoaWdobGlnaHQgPSB7IFwic3RhcnRcIjogaC5zdGFydCwgXCJlbmRcIjogaC5lbmQsIFwiY29sb3JcIjogY29sb3IsIFwiYmFja2dyb3VuZFwiOiBiYWNrZ3JvdW5kLCBcImlkXCI6IGlkIH07XG5cdFx0XHRcblx0XHRcdHRoaXMuX2hpZ2hsaWdodHMucHVzaChoaWdobGlnaHQpO1xuXHRcdFx0dGhpcy5fYXBwbHlIaWdobGlnaHQoaGlnaGxpZ2h0KTtcblx0XHRcdHRoaXMuX3Jlc3RvcmVTZWxlY3Rpb24oaC5zdGFydCxoLmVuZCk7XG5cdFx0fSBcblx0XHRcblx0XHRyZXR1cm4gaWQ7XG5cdH0sXG5cdC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fYXBwbHlIaWdobGlnaHRcbiAgICAgKiBQdXJwb3NlOiAgQXBwbHkgdGhlIHNwZWNpZmllZCBjb2xvciBhbmQgYmFja2dyb3VuZCB0byBhIHJlZ2lvbiBiZXR3ZWVuICdzdGFydCcgYW5kICdlbmQnLlxuICAgICAqIFJldHVybnM6ICAtXG4gICAgICogSW5wdXRzOiBoaWdobGlnaHQgLT4ge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGZpZWxkcyBzdGFydCAoaW50KSwgZW5kIChpbnQpLCBcbiAgICAgKiBcdFx0XHRcdFx0XHRjb2xvciAoSFRNTCBjb2xvciBzdHJpbmcpIGFuZCBiYWNrZ3JvdW5kIChIVE1MIGNvbG9yIHN0cmluZykuXG4gICAgICovXG5cdF9hcHBseUhpZ2hsaWdodDogZnVuY3Rpb24gKCBoaWdobGlnaHQgKSB7XHRcdFxuXHRcdHZhciBzZXEgPSB0aGlzLl9jb250ZW50RGl2LmZpbmQoJy5zZXF1ZW5jZScpO1xuXHRcdGZvciAoIHZhciBpID0gaGlnaGxpZ2h0LnN0YXJ0IC0gMTsgaSA8IGhpZ2hsaWdodC5lbmQ7IGkrKyApe1xuXHRcdFx0emluZGV4ID0galF1ZXJ5KHNlcVtpXSkuY3NzKFwiei1pbmRleFwiKTtcblx0XHRcdGlmICh6aW5kZXg9PVwiYXV0b1wiKXtcblx0XHRcdFx0IHogPSAxO1xuXHRcdFx0XHQgbyA9IDE7XG5cdFx0XHQgfVxuXHRcdFx0IGVsc2V7XG5cdFx0XHRcdCB6ID0gMDtcblx0XHRcdFx0IG8gPSAwLjU7XG5cdFx0XHQgfVxuXHRcdFx0alF1ZXJ5KHNlcVtpXSlcblx0XHRcdFx0LmNzcyh7IFxuXHRcdFx0XHRcdFwiY29sb3JcIjogaGlnaGxpZ2h0LmNvbG9yLFxuXHRcdFx0XHRcdFwiYmFja2dyb3VuZC1jb2xvclwiOiBoaWdobGlnaHQuYmFja2dyb3VuZCxcblx0XHRcdFx0XHRcInotaW5kZXhcIjogeixcblx0XHRcdFx0XHRcIm9wYWNpdHlcIjogb1xuXHRcdFx0XHRcdH0pXG5cdFx0XHRcdC5hZGRDbGFzcyhcImhpZ2hsaWdodGVkXCIpO1xuXHRcdH1cblx0fSxcblx0LyogXG4gICAgICogRnVuY3Rpb246IFNlcXVlbmNlLl9hcHBseUhpZ2hsaWdodHNcbiAgICAgKiBQdXJwb3NlOiAgQXBwbHkgdGhlIHNwZWNpZmllZCBoaWdobGlnaHRzLlxuICAgICAqIFJldHVybnM6ICAtXG4gICAgICogSW5wdXRzOiBoaWdobGlnaHRzIC0+IHtPYmplY3RbXX0gQW4gYXJyYXkgY29udGFpbmluZyB0aGUgaGlnaGxpZ2h0cyB0byBiZSBhcHBsaWVkLlxuICAgICAqL1xuXHRfYXBwbHlIaWdobGlnaHRzOiBmdW5jdGlvbiAoIGhpZ2hsaWdodHMgKSB7XG5cdFx0Zm9yICggdmFyIGkgaW4gaGlnaGxpZ2h0cyApIHtcblx0XHRcdHRoaXMuX2FwcGx5SGlnaGxpZ2h0KGhpZ2hsaWdodHNbaV0pO1xuXHRcdH1cblx0fSxcblx0LyogXG4gICAgICogRnVuY3Rpb246IFNlcXVlbmNlLl9yZXN0b3JlSGlnaGxpZ2h0c1xuICAgICAqIFB1cnBvc2U6ICBSZXBhaW50IHRoZSBoaWdobGlnaHRzIGluIHRoZSBzcGVjaWZpZWQgcmVnaW9uLlxuICAgICAqIFJldHVybnM6ICAtXG4gICAgICogSW5wdXRzOiBzdGFydCAtPiB7aW50fSBTdGFydCBvZiB0aGUgcmVnaW9uIHRvIGJlIHJlc3RvcmVkLlxuICAgICAqIFx0XHQgICBlbmQgLT4ge2ludH0gRW5kIG9mIHRoZSByZWdpb24gdG8gYmUgcmVzdG9yZWQuXG4gICAgICovXG5cdF9yZXN0b3JlSGlnaGxpZ2h0czogZnVuY3Rpb24gKCBzdGFydCwgZW5kICkge1xuXHRcdHZhciBoID0gdGhpcy5faGlnaGxpZ2h0cztcblx0XHQvLyBwYWludCB0aGUgcmVnaW9uIHVzaW5nIGRlZmF1bHQgYmxhbmsgc2V0dGluZ3Ncblx0XHR0aGlzLl9hcHBseUhpZ2hsaWdodCh7XG5cdFx0XHRcInN0YXJ0XCI6IHN0YXJ0LCBcblx0XHRcdFwiZW5kXCI6IGVuZCwgXG5cdFx0XHRcImNvbG9yXCI6IHRoaXMub3B0LmZvbnRDb2xvciwgXG5cdFx0XHRcImJhY2tncm91bmRcIjogdGhpcy5vcHQuYmFja2dyb3VuZENvbG9yIFxuXHRcdH0pO1xuXHRcdC8vIHJlc3RvcmUgaGlnaGxpZ2h0cyBpbiB0aGF0IHJlZ2lvblxuXHRcdGZvciAoIHZhciBpIGluIGggKSB7XG5cdFx0XHQvLyBpbnRlcnZhbCBpbnRlcnNlY3RzIHdpdGggaGlnaGxpZ2h0IGkgP1xuXHRcdFx0aWYgKCAhKCBoW2ldLnN0YXJ0ID4gZW5kIHx8IGhbaV0uZW5kIDwgc3RhcnQgKSApIHtcblx0XHRcdFx0YSA9ICggaFtpXS5zdGFydCA8IHN0YXJ0ICkgPyBzdGFydCA6IGhbaV0uc3RhcnQ7XG5cdFx0XHRcdGIgPSAoIGhbaV0uZW5kID4gZW5kICkgPyBlbmQgOiBoW2ldLmVuZDtcblx0XHRcdFx0dGhpcy5fYXBwbHlIaWdobGlnaHQoe1xuXHRcdFx0XHRcdFwic3RhcnRcIjogYSwgXG5cdFx0XHRcdFx0XCJlbmRcIjogYiwgXG5cdFx0XHRcdFx0XCJjb2xvclwiOiBoW2ldLmNvbG9yLCBcblx0XHRcdFx0XHRcImJhY2tncm91bmRcIjogaFtpXS5iYWNrZ3JvdW5kIFxuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fcmVzdG9yZVNlbGVjdGlvblxuICAgICAqIFB1cnBvc2U6ICBSZXBhaW50IHRoZSBjdXJyZW50IHNlbGVjdGlvbiBpbiB0aGUgc3BlY2lmaWVkIHJlZ2lvbi4gXG4gICAgICogXHRcdFx0IEl0IGlzIHVzZWQgaW4gdGhlIGNhc2Ugb2YgYW55IGhpZ2hsaWdodCBkbyBvdmVycmlkaW5nIG9mIHRoZSBjdXJyZW50IHNlbGVjdGlvbi4gXG4gICAgICogUmV0dXJuczogIC1cbiAgICAgKiBJbnB1dHM6IHN0YXJ0IC0+IHtpbnR9IFN0YXJ0IG9mIHRoZSByZWdpb24gdG8gYmUgcmVzdG9yZWQuXG4gICAgICogXHRcdCAgIGVuZCAtPiB7aW50fSBFbmQgb2YgdGhlIHJlZ2lvbiB0byBiZSByZXN0b3JlZC5cbiAgICAgKi9cblx0X3Jlc3RvcmVTZWxlY3Rpb246IGZ1bmN0aW9uICggc3RhcnQsIGVuZCApIHtcblx0XHR2YXIgc2VsID0gdGhpcy5vcHQuc2VsZWN0aW9uO1xuXHRcdC8vIGludGVydmFsIGludGVyc2VjdHMgd2l0aCBjdXJyZW50IHNlbGVjdGlvbiA/XG5cdFx0Ly8gcmVzdG9yZSBzZWxlY3Rpb25cblx0XHRpZiAoICEoIHN0YXJ0ID4gc2VsLmVuZCB8fCBlbmQgPCBzZWwuc3RhcnQgKSApIHtcblx0XHRcdGEgPSAoIHN0YXJ0IDwgc2VsLnN0YXJ0ICkgPyBzZWwuc3RhcnQgOiBzdGFydDtcblx0XHRcdGIgPSAoIGVuZCA+IHNlbC5lbmQgKSA/IHNlbC5lbmQgOiBlbmQ7XG5cdFx0XHRcblx0XHRcdHRoaXMuX2FwcGx5SGlnaGxpZ2h0KHtcblx0XHRcdFx0XCJzdGFydFwiOiBhLCBcblx0XHRcdFx0XCJlbmRcIjogYiwgXG5cdFx0XHRcdFwiY29sb3JcIjogdGhpcy5vcHQuc2VsZWN0aW9uRm9udENvbG9yLCBcblx0XHRcdFx0XCJiYWNrZ3JvdW5kXCI6IHRoaXMub3B0LnNlbGVjdGlvbkNvbG9yLFxuXHRcdFx0fSk7XG5cdFx0fVxuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBDbGVhciBhIGhpZ2hsaWdodGVkIHJlZ2lvbiB1c2luZy5cbiAgICAqXG4gICAgKiBAZGVwcmVjYXRlZCB1c2UgcmVtb3ZlSGlnaGxpZ2h0IGluc3RlYWQuXG4gICAgKiBcbiAgICAqIEBwYXJhbSB7aW50fSBpZCBUaGUgaWQgb2YgdGhlIGhpZ2hsaWdodCBvbiB0aGUgaW50ZXJuYWwgYXJyYXkuIFRoaXMgdmFsdWUgaXMgcmV0dXJuZWQgYnkgbWV0aG9kIGhpZ2hsaWdodC5cbiAgICAqL1xuXHR1bkhpZ2hsaWdodCA6IGZ1bmN0aW9uIChpZCkge1x0XG5cdFx0dGhpcy5yZW1vdmVIaWdobGlnaHQoaWQpO1xuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBSZW1vdmUgYSBoaWdobGlnaHQuXG4gICAgKlxuICAgICogQGV4YW1wbGVcbiAgICAqIC8vIENsZWFyIHRoZSBoaWdobGlnaHRlZCBjaGFyYWN0ZXJzIHdpdGhpbiB0aGUgcG9zaXRpb24gMTAwIHRvIDE1MCwgaW5jbHVkZWQuXG4gICAgKiBteVNlcXVlbmNlLnJlbW92ZUhpZ2hsaWdodChcInNwaW4xXCIpO1xuICAgICogXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgVGhlIGlkIG9mIHRoZSBoaWdobGlnaHQgb24gdGhlIGludGVybmFsIGFycmF5LiBUaGlzIHZhbHVlIGlzIHJldHVybmVkIGJ5IG1ldGhvZCBoaWdobGlnaHQuXG4gICAgKi9cblx0cmVtb3ZlSGlnaGxpZ2h0IDogZnVuY3Rpb24gKGlkKSB7XHRcblx0XHR2YXIgaCA9IHRoaXMuX2hpZ2hsaWdodHM7XG5cdFx0Zm9yICggaSBpbiBoICkge1xuXHRcdFx0aWYgKCBoW2ldLmlkID09IGlkICkge1xuXHRcdFx0XHRzdGFydCA9IGhbaV0uc3RhcnQ7XG5cdFx0XHRcdGVuZCA9IGhbaV0uZW5kO1xuXHRcdFx0XHRoLnNwbGljZShpLDEpO1xuXHRcdFx0XHRcblx0XHRcdFx0dGhpcy5fcmVzdG9yZUhpZ2hsaWdodHMoc3RhcnQsZW5kKTtcblx0XHRcdFx0dGhpcy5fcmVzdG9yZVNlbGVjdGlvbihzdGFydCxlbmQpO1xuXHRcdFx0XHRcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBDbGVhciB0aGUgaGlnaGxpZ2h0cyBvZiB3aG9sZSBzZXF1ZW5jZS5cbiAgICAqIEBkZXByZWNhdGVkIHVzZSByZW1vdmVBbGxIaWdobGlnaHRzIGluc3RlYWQuXG4gICAgKi9cblx0dW5IaWdobGlnaHRBbGwgOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5yZW1vdmVBbGxIaWdobGlnaHRzKCk7XG5cdH0sXG5cdFxuXHQvKipcbiAgICAqIFJlbW92ZSBhbGwgdGhlIGhpZ2hsaWdodHMgb2Ygd2hvbGUgc2VxdWVuY2UuXG4gICAgKlxuICAgICogQGV4YW1wbGVcbiAgICAqIG15U2VxdWVuY2UucmVtb3ZlQWxsSGlnaGxpZ2h0cygpO1xuICAgICovXG5cdHJlbW92ZUFsbEhpZ2hsaWdodHMgOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5faGlnaGxpZ2h0cyA9IFtdO1xuXHRcdHRoaXMuX3Jlc3RvcmVIaWdobGlnaHRzKDEsdGhpcy5vcHQuc2VxdWVuY2UubGVuZ3RoKTtcblx0XHR0aGlzLl9yZXN0b3JlU2VsZWN0aW9uKDEsdGhpcy5vcHQuc2VxdWVuY2UubGVuZ3RoKTtcblx0fSxcblx0XG5cdC8qKlxuICAgICogQ2hhbmdlcyB0aGUgY3VycmVudCBkaXNwbGF5aW5nIGZvcm1hdCBvZiB0aGUgc2VxdWVuY2UuXG4gICAgKlxuICAgICogQGV4YW1wbGVcbiAgICAqIC8vIFNldCBmb3JtYXQgdG8gJ0ZBU1RBJy5cbiAgICAqIG15U2VxdWVuY2Uuc2V0Rm9ybWF0KCdGQVNUQScpO1xuICAgICogXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gZm9ybWF0IFRoZSBmb3JtYXQgZm9yIHRoZSBzZXF1ZW5jZSB0byBiZSBkaXNwbGF5ZWQuXG4gICAgKi9cblx0c2V0Rm9ybWF0IDogZnVuY3Rpb24oZm9ybWF0KSB7XG5cdFx0aWYgKCB0aGlzLm9wdC5mb3JtYXQgIT0gZm9ybWF0LnRvVXBwZXJDYXNlKCkgKSB7XG5cdFx0XHR0aGlzLm9wdC5mb3JtYXQgPSBmb3JtYXQudG9VcHBlckNhc2UoKTtcblx0XHRcdHRoaXMuX3JlZHJhdygpO1xuXHRcdH1cblxuXHRcdHZhciBzZWxmID0gdGhpcztcblx0XHQvLyBDaGFuZ2VzIHRoZSBvcHRpb24gaW4gdGhlIGNvbWJvIGJveFxuXHRcdHRoaXMuX2hlYWRlckRpdi5maW5kKCdvcHRpb24nKS5lYWNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYoalF1ZXJ5KHRoaXMpLnZhbCgpID09IHNlbGYub3B0LmZvcm1hdC50b1VwcGVyQ2FzZSgpKSB7XG5cdFx0XHRcdGpRdWVyeSh0aGlzKS5hdHRyKCdzZWxlY3RlZCcsICdzZWxlY3RlZCcpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBDaGFuZ2VzIHRoZSBjdXJyZW50IG51bWJlciBvZiBjb2x1bW5zIGluIHRoZSBkaXNwbGF5ZWQgc2VxdWVuY2UuXG4gICAgKlxuICAgICogQGV4YW1wbGVcbiAgICAqIC8vIFNldCB0aGUgbnVtYmVyIG9mIGNvbHVtbnMgdG8gNzAuXG4gICAgKiBteVNlcXVlbmNlLnNldE51bUNvbHMoNzApO1xuICAgICogXG4gICAgKiBAcGFyYW0ge2ludH0gbnVtQ29scyBUaGUgbnVtYmVyIG9mIGNvbHVtbnMuXG4gICAgKi9cblx0c2V0TnVtQ29scyA6IGZ1bmN0aW9uKG51bUNvbHMpIHtcblx0XHR0aGlzLm9wdC5jb2x1bW5zLnNpemUgPSBudW1Db2xzO1xuXHRcdHRoaXMuX3JlZHJhdygpO1xuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBTZXQgdGhlIHZpc2liaWxpdHkgb2YgdGhlIGRyb3AtZG93biBsaXN0IG9mIGZvcm1hdHMuXG4gICAgKiBcbiAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gdmlzaWJsZSB0cnVlOiBzaG93OyBmYWxzZTogaGlkZS5cbiAgICAqL1xuXHRmb3JtYXRTZWxlY3RvclZpc2libGUgOiBmdW5jdGlvbiAodmlzaWJsZSl7XG5cdFx0aWYgKHZpc2libGUpIHtcblx0XHRcdHRoaXMuX2hlYWRlckRpdi5zaG93KCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX2hlYWRlckRpdi5oaWRlKCk7XG5cdFx0fVxuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBUaGlzIGlzIHNpbWlsYXIgdG8gYSB7QmlvanMuUHJvdGVpbjNEI2Zvcm1hdFNlbGVjdG9yVmlzaWJsZX0gd2l0aCB0aGUgJ3RydWUnIGFyZ3VtZW50LlxuICAgICpcbiAgICAqIEBleGFtcGxlXG4gICAgKiAvLyBTaG93cyB0aGUgZm9ybWF0IHNlbGVjdG9yLlxuICAgICogbXlTZXF1ZW5jZS5zaG93Rm9ybWF0U2VsZWN0b3IoKTtcbiAgICAqIFxuICAgICovXG5cdHNob3dGb3JtYXRTZWxlY3RvciA6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2hlYWRlckRpdi5zaG93KCk7XG5cdH0sXG5cdFxuXHQvKipcbiAgICAqIFRoaXMgaXMgc2ltaWxhciB0byBhIHtCaW9qcy5Qcm90ZWluM0QjZm9ybWF0U2VsZWN0b3JWaXNpYmxlfSB3aXRoIHRoZSAnZmFsc2UnIGFyZ3VtZW50LlxuICAgICogXG4gICAgKiBAZXhhbXBsZVxuICAgICogLy8gSGlkZXMgdGhlIGZvcm1hdCBzZWxlY3Rvci5cbiAgICAqIG15U2VxdWVuY2UuaGlkZUZvcm1hdFNlbGVjdG9yKCk7XG4gICAgKiBcbiAgICAqL1xuXHRoaWRlRm9ybWF0U2VsZWN0b3IgOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9oZWFkZXJEaXYuaGlkZSgpO1xuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBIaWRlcyB0aGUgd2hvbGUgY29tcG9uZW50LlxuICAgICogXG4gICAgKi9cblx0aGlkZSA6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9oZWFkZXJEaXYuaGlkZSgpO1xuXHRcdHRoaXMuX2NvbnRlbnREaXYuaGlkZSgpO1xuXHR9LFxuXG5cdC8qKlxuICAgICogU2hvd3MgdGhlIHdob2xlIGNvbXBvbmVudC5cbiAgICAqIFxuICAgICovXG5cdHNob3cgOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5faGVhZGVyRGl2LnNob3coKTtcblx0XHR0aGlzLl9jb250ZW50RGl2LnNob3coKTtcblx0fSxcblx0LyogXG4gICAgICogRnVuY3Rpb246IFNlcXVlbmNlLl9zZXRTZWxlY3Rpb25cbiAgICAgKiBQdXJwb3NlOiAgVXBkYXRlIHRoZSBjdXJyZW50IHNlbGVjdGlvbi4gXG4gICAgICogUmV0dXJuczogIC1cbiAgICAgKiBJbnB1dHM6IHN0YXJ0IC0+IHtpbnR9IFN0YXJ0IG9mIHRoZSByZWdpb24gdG8gYmUgc2VsZWN0ZWQuXG4gICAgICogXHRcdCAgIGVuZCAtPiB7aW50fSBFbmQgb2YgdGhlIHJlZ2lvbiB0byBiZSBzZWxlY3RlZC5cbiAgICAgKi9cblx0X3NldFNlbGVjdGlvbiA6IGZ1bmN0aW9uKHN0YXJ0LCBlbmQpIHtcblx0XHQvL2FsZXJ0KFwiYWRzYXNcIik7XG5cdFx0XG5cdFx0dmFyIGN1cnJlbnQgPSB0aGlzLm9wdC5zZWxlY3Rpb247XG5cdFx0dmFyIGNoYW5nZSA9IHt9O1xuXHRcdFxuXHRcdC8vIFdoaWNoIGlzIHRoZSBjaGFuZ2Ugb24gc2VsZWN0aW9uP1xuXHRcdGlmICggY3VycmVudC5zdGFydCA9PSBzdGFydCApIHtcblx0XHRcdC8vIGZvcndhcmQ/XG5cdFx0XHRpZiAoIGN1cnJlbnQuZW5kIDwgZW5kICkge1xuXHRcdFx0XHRjaGFuZ2Uuc3RhcnQgPSBjdXJyZW50LmVuZDtcblx0XHRcdFx0Y2hhbmdlLmVuZCA9IGVuZDtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuX3Jlc3RvcmVIaWdobGlnaHRzKGVuZCsxLCBjdXJyZW50LmVuZCk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIGlmICggY3VycmVudC5lbmQgPT0gZW5kICkge1xuXHRcdFx0Ly8gZm9yd2FyZD9cblx0XHRcdGlmICggY3VycmVudC5zdGFydCA+IHN0YXJ0ICkge1xuXHRcdFx0XHRjaGFuZ2Uuc3RhcnQgPSBzdGFydDtcblx0XHRcdFx0Y2hhbmdlLmVuZCA9IGN1cnJlbnQuc3RhcnQ7XHRcdFx0XHRcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuX3Jlc3RvcmVIaWdobGlnaHRzKGN1cnJlbnQuc3RhcnQsIHN0YXJ0LTEpO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9yZXN0b3JlSGlnaGxpZ2h0cyhjdXJyZW50LnN0YXJ0LCBjdXJyZW50LmVuZCk7XG5cdFx0XHRjaGFuZ2Uuc3RhcnQgPSBzdGFydDtcblx0XHRcdGNoYW5nZS5lbmQgPSBlbmQ7XG5cdFx0fVxuXG5cdFx0Y3VycmVudC5zdGFydCA9IHN0YXJ0O1xuXHRcdGN1cnJlbnQuZW5kID0gZW5kO1xuXG5cdFx0aWYgKCBjaGFuZ2Uuc3RhcnQgIT0gdW5kZWZpbmVkICkge1xuXHRcdFx0dGhpcy5fYXBwbHlIaWdobGlnaHQoe1xuXHRcdFx0XHRcInN0YXJ0XCI6IGNoYW5nZS5zdGFydCwgXG5cdFx0XHRcdFwiZW5kXCI6IGNoYW5nZS5lbmQsIFxuXHRcdFx0XHRcImNvbG9yXCI6IHRoaXMub3B0LnNlbGVjdGlvbkZvbnRDb2xvciwgXG5cdFx0XHRcdFwiYmFja2dyb3VuZFwiOiB0aGlzLm9wdC5zZWxlY3Rpb25Db2xvciBcblx0XHRcdH0pO1xuXHRcdH1cblx0XHRcblx0fSxcblx0XG5cdC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fcmVwYWludFNlbGVjdGlvblxuICAgICAqIFB1cnBvc2U6ICBSZXBhaW50IHRoZSB3aG9sZSBjdXJyZW50IHNlbGVjdGlvbi4gXG4gICAgICogUmV0dXJuczogIC1cbiAgICAgKiBJbnB1dHM6IC1cbiAgICAgKi9cblx0X3JlcGFpbnRTZWxlY3Rpb246IGZ1bmN0aW9uKCl7XG5cdFx0dmFyIHMgPSB0aGlzLm9wdC5zZWxlY3Rpb247XG5cdFx0dGhpcy5fc2V0U2VsZWN0aW9uKDAsMCk7XG5cdFx0dGhpcy5fc2V0U2VsZWN0aW9uKHMuc3RhcnQscy5lbmQpO1xuXHR9LFxuXHRcblx0LyogXG4gICAgICogRnVuY3Rpb246IFNlcXVlbmNlLl9yZWRyYXdcbiAgICAgKiBQdXJwb3NlOiAgUmVwYWludCB0aGUgY3VycmVudCBzZXF1ZW5jZS4gXG4gICAgICogUmV0dXJuczogIC1cbiAgICAgKiBJbnB1dHM6IC1cbiAgICAgKi9cblx0X3JlZHJhdyA6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpID0gMDtcdFxuXHRcdHZhciBzZWxmID0gdGhpcztcblx0XHRcblx0XHQvLyBSZXNldCB0aGUgY29udGVudFxuXHRcdC8vdGhpcy5fY29udGVudERpdi50ZXh0KCcnKTtcblx0XHR0aGlzLl9jb250ZW50RGl2LmNoaWxkcmVuKCkucmVtb3ZlKCk7XG5cdFx0XG5cdFx0Ly8gUmVidWlsZCB0aGUgc3BhbnMgb2YgdGhlIHNlcXVlbmNlIFxuXHRcdC8vIGFjY29yZGluZyB0byBmb3JtYXRcblx0XHRpZih0aGlzLm9wdC5mb3JtYXQgPT0gJ1JBVycpIHtcblx0XHRcdHRoaXMuX2RyYXdSYXcoKTtcblx0XHR9IGVsc2UgaWYodGhpcy5vcHQuZm9ybWF0ID09ICdDT0RBVEEnKSB7XG5cdFx0XHR0aGlzLl9kcmF3Q29kYXRhKCk7XG5cdFx0fSBlbHNlIGlmICh0aGlzLm9wdC5mb3JtYXQgPT0gJ0ZBU1RBJyl7XG5cdFx0XHR0aGlzLl9kcmF3RmFzdGEoKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5vcHQuZm9ybWF0ID0gJ1BSSURFJztcblx0XHRcdHRoaXMuX2RyYXdQcmlkZSgpO1xuXHRcdH1cblx0XHRcblx0XHQvLyBSZXN0b3JlIHRoZSBoaWdobGlnaHRlZCByZWdpb25zXG5cdFx0dGhpcy5fYXBwbHlIaWdobGlnaHRzKHRoaXMuX2hpZ2hsaWdodHMpO1xuXHRcdHRoaXMuX3JlcGFpbnRTZWxlY3Rpb24oKTtcblx0XHR0aGlzLl9hZGRTcGFuRXZlbnRzKCk7XG5cdH0sXG5cdC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fZHJhd0Zhc3RhXG4gICAgICogUHVycG9zZTogIFJlcGFpbnQgdGhlIGN1cnJlbnQgc2VxdWVuY2UgdXNpbmcgRkFTVEEgZm9ybWF0LiAgXG4gICAgICogUmV0dXJuczogIC1cbiAgICAgKiBJbnB1dHM6IC1cbiAgICAgKi9cblx0X2RyYXdGYXN0YSA6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBzZWxmID0gdGhpcztcblx0XHR2YXIgYSA9IHRoaXMub3B0LnNlcXVlbmNlLnRvVXBwZXJDYXNlKCkuc3BsaXQoJycpO1xuXHRcdHZhciBwcmUgPSBqUXVlcnkoJzxwcmU+PC9wcmU+JykuYXBwZW5kVG8odGhpcy5fY29udGVudERpdik7XG5cblx0XHR2YXIgaSA9IDE7XG5cdFx0dmFyIGFyciA9IFtdO1xuXHQgICAgdmFyIHN0ciA9ICc+JyArIHRoaXMub3B0LmlkICsgJyAnICsgYS5sZW5ndGggKyAnIGJwPGJyLz4nO1xuXHRcdFxuXHRcdC8qIENvcnJlY3QgY29sdW1uIHNpemUgaW4gY2FzZSB0aGUgc2VxdWVuY2UgaXMgYXMgc21hbGwgcGVwdGlkZSAqL1xuXHRcdHZhciBudW1Db2xzID0gdGhpcy5vcHQuY29sdW1ucy5zaXplO1xuXHRcdGlmICggdGhpcy5vcHQuc2VxdWVuY2UubGVuZ3RoIDwgdGhpcy5vcHQuY29sdW1ucy5zaXplICkge1xuXHRcdFx0bnVtQ29scyA9IHRoaXMub3B0LnNlcXVlbmNlLmxlbmd0aDtcdFxuXHRcdH1cblx0XHRcblx0ICAgIHZhciBvcHQgPSB7XG5cdFx0XHRudW1Db2xzOiBudW1Db2xzLFxuXHRcdCAgICBudW1Db2xzRm9yU3BhY2U6IDBcblx0XHR9O1xuXG5cdFx0c3RyICs9IHRoaXMuX2RyYXdTZXF1ZW5jZShhLCBvcHQpO1xuXHRcdHByZS5odG1sKHN0cik7XG5cdFx0XG5cdFx0dGhpcy5fZHJhd0Fubm90YXRpb25zKG9wdCk7XG5cdH0sXG5cdC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fZHJhd0NvZGF0YVxuICAgICAqIFB1cnBvc2U6ICBSZXBhaW50IHRoZSBjdXJyZW50IHNlcXVlbmNlIHVzaW5nIENPREFUQSBmb3JtYXQuICBcbiAgICAgKiBSZXR1cm5zOiAgLVxuICAgICAqIElucHV0czogLVxuICAgICAqL1xuXHRfZHJhd0NvZGF0YSA6IGZ1bmN0aW9uKCkge1xuXHRcdFxuXHRcdHZhciBzZWxmID0gdGhpcztcblx0XHR2YXIgYSA9IHRoaXMub3B0LnNlcXVlbmNlLnRvVXBwZXJDYXNlKCkuc3BsaXQoJycpO1xuXHRcdHZhciBwcmUgPSBqUXVlcnkoJzxwcmUgc3R5bGU9XCJ3aGl0ZS1zcGFjZTpwcmVcIj48L3ByZT4nKS5hcHBlbmRUbyh0aGlzLl9jb250ZW50RGl2KTtcblxuXHRcdHZhciBpID0gMDtcblx0XHR2YXIgc3RyID0gJ0VOVFJZICAgICAgICAgICAnICsgdGhpcy5vcHQuaWQgKyAnPGJyLz4nO1xuXHRcdHN0ciArPSAnU0VRVUVOQ0U8YnIvPic7XG5cdFx0aWYgKCB0aGlzLm9wdC5mb3JtYXRPcHRpb25zICE9PSB1bmRlZmluZWQgKXtcblx0XHRcdGlmKHRoaXMub3B0LmZvcm1hdE9wdGlvbnMudGl0bGUgIT09IHVuZGVmaW5lZCApe1xuXHRcdFx0XHRpZiAodGhpcy5vcHQuZm9ybWF0T3B0aW9ucy50aXRsZSA9PSBmYWxzZSkge1xuXHRcdFx0XHRcdHN0ciA9ICcnO1xuXHRcdFx0XHR9XHRcdFx0XG5cdFx0XHR9XG5cdFx0fSBcblx0XHRcblx0XHQvKiBDb3JyZWN0IGNvbHVtbiBzaXplIGluIGNhc2UgdGhlIHNlcXVlbmNlIGlzIGFzIHNtYWxsIHBlcHRpZGUgKi9cblx0XHR2YXIgbnVtQ29scyA9IHRoaXMub3B0LmNvbHVtbnMuc2l6ZTtcblx0XHRpZiAoIHRoaXMub3B0LnNlcXVlbmNlLmxlbmd0aCA8IHRoaXMub3B0LmNvbHVtbnMuc2l6ZSApIHtcblx0XHRcdG51bUNvbHMgPSB0aGlzLm9wdC5zZXF1ZW5jZS5sZW5ndGg7XHRcblx0XHR9XG5cdFx0XG5cdFx0dmFyIG9wdCA9IHtcblx0XHRcdFx0bnVtTGVmdDogdHJ1ZSxcblx0XHRcdFx0bnVtTGVmdFNpemU6IDcsXG5cdFx0XHRcdG51bUxlZnRQYWQ6JyAnLFxuXHRcdFx0XHRudW1Ub3A6IHRydWUsXG5cdFx0XHRcdG51bVRvcEVhY2g6IDUsXG5cdFx0XHRcdG51bUNvbHM6IG51bUNvbHMsXG5cdFx0XHQgICAgbnVtQ29sc0ZvclNwYWNlOiAwLFxuXHRcdFx0ICAgIHNwYWNlQmV0d2VlbkNoYXJzOiB0cnVlXG5cdFx0fTtcblx0XHRcblx0XHRzdHIgKz0gdGhpcy5fZHJhd1NlcXVlbmNlKGEsIG9wdCk7XG5cdFx0XG5cdFx0dmFyIGZvb3RlciA9ICc8YnIvPi8vLyc7XG5cdFx0aWYgKHRoaXMub3B0LmZvcm1hdE9wdGlvbnMgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0aWYgKHRoaXMub3B0LmZvcm1hdE9wdGlvbnMuZm9vdGVyICE9PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0aWYgKHRoaXMub3B0LmZvcm1hdE9wdGlvbnMuZm9vdGVyID09IGZhbHNlKSB7XG5cdFx0XHRcdFx0Zm9vdGVyID0gJyc7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0c3RyICs9IGZvb3Rlcjtcblx0XHRwcmUuaHRtbChzdHIpO1xuXHRcdFxuXHRcdHRoaXMuX2RyYXdBbm5vdGF0aW9ucyhvcHQpO1xuXHR9LFxuXHQvKiBcbiAgICAgKiBGdW5jdGlvbjogU2VxdWVuY2UuX2RyYXdBbm5vdGF0aW9uc1xuICAgICAqIFB1cnBvc2U6ICBQYWludCB0aGUgYW5ub3RhdGlvbnMgb24gdGhlIHNlcXVlbmNlLiAgXG4gICAgICogUmV0dXJuczogIC1cbiAgICAgKiBJbnB1dHM6IHNldHRpbmdzIC0+IHtvYmplY3R9IFxuICAgICAqL1xuICAgIF9kcmF3QW5ub3RhdGlvbnM6IGZ1bmN0aW9uICggc2V0dGluZ3MgKXsgXG4gICAgXHRcbiAgICBcdHZhciBzZWxmID0gdGhpcztcbiAgICBcdHZhciBhID0gdGhpcy5vcHQuc2VxdWVuY2UudG9Mb3dlckNhc2UoKS5zcGxpdCgnJyk7ICAgIFx0XG4gICAgXHR2YXIgYW5ub3RhdGlvbnMgPSB0aGlzLl9hbm5vdGF0aW9ucztcbiAgICBcdHZhciBsZWZ0U3BhY2VzID0gJyc7XG4gICAgXHR2YXIgcm93ID0gJyc7XG4gICAgXHR2YXIgYW5ub3QgPSAnJztcbiAgICBcdFxuICAgIFx0Ly8gSW5kZXggYXQgdGhlIGxlZnQ/XG5cdFx0aWYgKCBzZXR0aW5ncy5udW1MZWZ0ICkge1xuXHRcdFx0bGVmdFNwYWNlcyArPSB0aGlzLl9mb3JtYXRJbmRleCgnICcsIHNldHRpbmdzLm51bUxlZnRTaXplKzIsICcgJyk7XG5cdFx0fVxuXG5cdFx0Zm9yICggdmFyIGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkgKz0gc2V0dGluZ3MubnVtQ29scyApe1xuXHRcdFx0cm93ID0gJyc7XG5cdFx0XHRmb3IgKCB2YXIga2V5IGluIGFubm90YXRpb25zICl7XG5cdFx0XHRcdGFubm90YXRpb25zW2tleV0uaWQgPSB0aGlzLmdldElkKCkgKyBcIl9cIiArIGtleTtcblx0XHRcdFx0YW5ub3QgPSB0aGlzLl9nZXRIVE1MUm93QW5ub3QoaSsxLCBhbm5vdGF0aW9uc1trZXldLCBzZXR0aW5ncyk7XHRcdFx0XHRcblx0XHRcdFx0aWYgKGFubm90Lmxlbmd0aCA+IDApIHtcblx0XHRcdFx0XHRyb3cgKz0gJzxici8+Jztcblx0XHRcdFx0XHRyb3cgKz0gbGVmdFNwYWNlcztcblx0XHRcdFx0XHRyb3cgKz0gYW5ub3Q7XG5cdFx0XHRcdFx0cm93ICs9ICc8YnIvPic7XG5cdFx0XHRcdH0gXG5cdFx0XHR9XG5cdFx0XHRcblx0XHRcdHZhciBudW1Db2xzID0gc2V0dGluZ3MubnVtQ29scztcblx0XHRcdHZhciBjaGFyUmVtYWluaW5nID0gYS5sZW5ndGgtaTtcblx0XHRcdGlmKGNoYXJSZW1haW5pbmcgPCBudW1Db2xzKXtcblx0XHRcdFx0bnVtQ29sc1x0PSBjaGFyUmVtYWluaW5nO1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHRpZiAoIHNldHRpbmdzLm51bVJpZ2h0ICkge1xuXHRcdFx0XHRqUXVlcnkocm93KS5pbnNlcnRBZnRlcignZGl2Iycrc2VsZi5vcHQudGFyZ2V0KycgZGl2IHByZSBzcGFuI251bVJpZ2h0XycgKyB0aGlzLmdldElkKCkgKyAnXycgKyAoaSArIG51bUNvbHMpICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRqUXVlcnkocm93KS5pbnNlcnRBZnRlcignZGl2Iycrc2VsZi5vcHQudGFyZ2V0KycgZGl2IHByZSBzcGFuIycrIHRoaXMuZ2V0SWQoKSArICdfJyArIChpICsgbnVtQ29scykgKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0XG5cdFx0Ly8gYWRkIHRvb2wgdGlwcyBhbmQgYmFja2dyb3VuZCcgY29sb3JpbmcgZWZmZWN0XG5cdFx0alF1ZXJ5KHRoaXMuX2NvbnRlbnREaXYpLmZpbmQoJy5hbm5vdGF0aW9uJykuZWFjaCggZnVuY3Rpb24oKXtcblx0XHRcdHNlbGYuX2FkZFRvb2xUaXAoIHRoaXMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gc2VsZi5fZ2V0QW5ub3RhdGlvblN0cmluZyggalF1ZXJ5KHRoaXMpLmF0dHIoXCJpZFwiKSApO1xuXHRcdFx0fSk7XG5cdFx0XHRcblx0XHRcdGpRdWVyeSh0aGlzKS5tb3VzZW92ZXIoZnVuY3Rpb24oZSkge1xuXHRcdFx0XHRqUXVlcnkoJy5hbm5vdGF0aW9uLicralF1ZXJ5KGUudGFyZ2V0KS5hdHRyKFwiaWRcIikpLmVhY2goZnVuY3Rpb24oKXtcblx0XHRcdFx0XHRqUXVlcnkodGhpcykuY3NzKFwiYmFja2dyb3VuZC1jb2xvclwiLCBqUXVlcnkodGhpcykuYXR0cihcImNvbG9yXCIpICk7XG5cdFx0XHRcdH0pO1xuXHRcdCAgICB9KS5tb3VzZW91dChmdW5jdGlvbigpIHtcblx0XHQgICAgXHRqUXVlcnkoJy5hbm5vdGF0aW9uJykuY3NzKFwiYmFja2dyb3VuZC1jb2xvclwiLCBcInRyYW5zcGFyZW50XCIpOyBcblx0XHQgICAgXHRcblx0XHQgICAgfSkuY2xpY2soZnVuY3Rpb24oZSkge1xuXHRcdCAgICBcdFx0dmFyIG5hbWUgPSB1bmRlZmluZWQ7XG5cdFx0ICAgIFx0XHR2YXIgaWQgPSBqUXVlcnkoZS50YXJnZXQpLmF0dHIoXCJpZFwiKTtcblx0XHQgICAgXHRcdGZvcih2YXIgaSA9MDsgaSA8IHNlbGYuX2Fubm90YXRpb25zLmxlbmd0aDtpKyspe1xuICAgICAgICAgICAgICBpZihzZWxmLl9hbm5vdGF0aW9uc1tpXS5pZCA9PSBpZCl7XG4gICAgICAgICAgICAgICAgbmFtZSA9IHNlbGYuX2Fubm90YXRpb25zW2ldLm5hbWU7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblx0XHQgICAgXHRzZWxmLnRyaWdnZXIoIEVWVF9PTl9BTk5PVEFUSU9OX0NMSUNLRUQsIHtcblx0ICAgIFx0XHRcIm5hbWVcIjogbmFtZSxcblx0XHQgICAgXHRcdC8vXCJwb3NcIjogcGFyc2VJbnQoIGpRdWVyeShlLnRhcmdldCkuYXR0cihcInBvc1wiKSApXG5cdFx0ICAgIFx0fSk7XG5cdFx0ICAgIH0pO1xuXHRcdFx0XG5cdFx0fSk7XG5cbiAgICB9LFxuICAgIC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fZ2V0QW5ub3RhdGlvblN0cmluZ1xuICAgICAqIFB1cnBvc2U6ICBHZXQgdGhlIGFubm90YXRpb24gdGV4dCBtZXNzYWdlIGZvciB0aGUgdG9vbHRpcCBcbiAgICAgKiBSZXR1cm5zOiAge3N0cmluZ30gQW5ub3RhdGlvbiB0ZXh0IGZvciB0aGUgYW5ub3RhdGlvblxuICAgICAqIElucHV0czogICBpZCAtPiB7aW50fSBpbmRleCBvZiB0aGUgaW50ZXJuYWwgYW5ub3RhdGlvbiBhcnJheVxuICAgICAqL1xuICAgIF9nZXRBbm5vdGF0aW9uU3RyaW5nOiBmdW5jdGlvbiAoIGlkICkge1xuXHRcdHZhciBhbm5vdGF0aW9uID0gdGhpcy5fYW5ub3RhdGlvbnNbaWQuc3Vic3RyKGlkLmluZGV4T2YoXCJfXCIpICsgMSldO1xuXHRcdHJldHVybiBhbm5vdGF0aW9uLm5hbWUgKyBcIjxici8+XCIgKyAoKGFubm90YXRpb24uaHRtbCk/IGFubm90YXRpb24uaHRtbCA6ICcnKTtcbiAgICB9LFxuICAgIFxuICAgIC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fZ2V0SFRNTFJvd0Fubm90XG4gICAgICogUHVycG9zZTogIEJ1aWxkIGFuIGFubm90YXRpb25cbiAgICAgKiBSZXR1cm5zOiAgSFRNTCBvZiB0aGUgYW5ub3RhdGlvblxuICAgICAqIElucHV0czogICBjdXJyZW50UG9zIC0+IHtpbnR9XG4gICAgICogXHRcdFx0IGFubm90YXRpb24gLT4ge09iamVjdH0gXG4gICAgICogIFx0XHQgc2V0dGluZ3MgLT4ge09iamVjdH1cbiAgICAgKi9cbiAgICBfZ2V0SFRNTFJvd0Fubm90IDogZnVuY3Rpb24gKGN1cnJlbnRQb3MsIGFubm90YXRpb24sIHNldHRpbmdzKSB7XG4gICAgXHR2YXIgc3R5bGVCZWdpbiA9ICdib3JkZXItbGVmdDoxcHggc29saWQ7IGJvcmRlci1ib3R0b206MXB4IHNvbGlkOyBib3JkZXItY29sb3I6JztcbiAgICBcdHZhciBzdHlsZU9uID0gJ2JvcmRlci1ib3R0b206MXB4IHNvbGlkOyBib3JkZXItY29sb3I6JztcbiAgICBcdHZhciBzdHlsZUVuZCA9ICdib3JkZXItYm90dG9tOjFweCBzb2xpZDsgYm9yZGVyLXJpZ2h0OjFweCBzb2xpZDsgYm9yZGVyLWNvbG9yOic7XG5cdFx0dmFyIHN0eWxlQmVnaW5BbmRFbmQgPSAnYm9yZGVyLWxlZnQ6MXB4IHNvbGlkOyBib3JkZXItcmlnaHQ6MXB4IHNvbGlkOyBib3JkZXItYm90dG9tOjFweCBzb2xpZDsgYm9yZGVyLWNvbG9yOic7XG4gICAgXHRcbiAgICBcdHZhciByb3cgPSBbXTtcbiAgICBcdHZhciBlbmQgPSAoY3VycmVudFBvcyArIHNldHRpbmdzLm51bUNvbHMpO1xuICAgIFx0dmFyIHNwYWNlQmV0d2VlbkNoYXJzID0gKHNldHRpbmdzLnNwYWNlQmV0d2VlbkNoYXJzKT8gJyAnIDogJyc7ICAgIFx0XG4gICAgXHR2YXIgZGVmYXVsdENvbG9yID0gYW5ub3RhdGlvbi5jb2xvcjtcbiAgICBcdHZhciBpZCA9IGFubm90YXRpb24uaWQ7XG4gICAgXHRmb3IgKCB2YXIgcG9zPWN1cnJlbnRQb3M7IHBvcyA8IGVuZCA7IHBvcysrICkge1xuXHRcdFx0Ly8gcmVnaW9uc1xuXHRcdFx0Zm9yICggdmFyIHIgaW4gYW5ub3RhdGlvbi5yZWdpb25zICkge1xuXHRcdFx0XHRyZWdpb24gPSBhbm5vdGF0aW9uLnJlZ2lvbnNbcl07XG5cdFx0XHRcdFxuXHRcdFx0XHRzcGFjZUFmdGVyID0gJyc7XG5cdFx0XHRcdHNwYWNlQWZ0ZXIgKz0gKHBvcyAlIHNldHRpbmdzLm51bUNvbHNGb3JTcGFjZSA9PSAwICk/ICcgJyA6ICcnO1xuXHRcdFx0XHRzcGFjZUFmdGVyICs9IHNwYWNlQmV0d2VlbkNoYXJzO1xuXHRcdFx0XHRcblx0XHRcdFx0Y29sb3IgPSAoKHJlZ2lvbi5jb2xvcik/IHJlZ2lvbi5jb2xvciA6IGRlZmF1bHRDb2xvcik7XG5cdFx0XHRcdGRhdGEgPSAnY2xhc3M9XCJhbm5vdGF0aW9uICcraWQrJ1wiIGlkPVwiJytpZCsnXCIgY29sb3I9XCInK2NvbG9yKydcIiBwb3M9XCInK3BvcysnXCInO1xuXHRcdFx0XHRcblx0XHRcdFx0aWYgKCBwb3MgPT0gcmVnaW9uLnN0YXJ0ICYmIHBvcyA9PSByZWdpb24uZW5kKSB7XG5cdFx0XHRcdFx0cm93W3Bvc10gPSAnPHNwYW4gc3R5bGU9XCInK3N0eWxlQmVnaW5BbmRFbmQrY29sb3IrJ1wiICcrZGF0YSsnPiAnO1xuXHRcdFx0XHRcdHJvd1twb3NdICs9IHNwYWNlQWZ0ZXI7XG5cdFx0XHRcdFx0cm93W3Bvc10gKz0gJzwvc3Bhbj4nO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBwb3MgPT0gcmVnaW9uLnN0YXJ0ICkge1xuXHRcdFx0XHRcdHJvd1twb3NdID0gJzxzcGFuIHN0eWxlPVwiJytzdHlsZUJlZ2luK2NvbG9yKydcIiAnK2RhdGErJz4gJztcblx0XHRcdFx0XHRyb3dbcG9zXSArPSBzcGFjZUFmdGVyO1xuXHRcdFx0XHRcdHJvd1twb3NdICs9ICc8L3NwYW4+Jztcblx0XHRcdFx0fSBlbHNlIGlmICggcG9zID09IHJlZ2lvbi5lbmQgKSB7XG5cdFx0XHRcdFx0cm93W3Bvc10gPSAnPHNwYW4gc3R5bGU9XCInK3N0eWxlRW5kK2NvbG9yKycgXCIgJytkYXRhKyc+ICc7XG5cdFx0XHRcdFx0Ly9yb3dbcG9zXSArPSBzcGFjZUFmdGVyO1xuXHRcdFx0XHRcdHJvd1twb3NdICs9ICc8L3NwYW4+Jztcblx0XHRcdFx0fSBlbHNlIGlmICggcG9zID4gcmVnaW9uLnN0YXJ0ICYmIHBvcyA8IHJlZ2lvbi5lbmQgKSB7XG5cdFx0XHRcdFx0cm93W3Bvc10gPSAnPHNwYW4gc3R5bGU9XCInK3N0eWxlT24rY29sb3IrJ1wiICcrZGF0YSsnPiAnO1xuXHRcdFx0XHRcdHJvd1twb3NdICs9IHNwYWNlQWZ0ZXI7XG5cdFx0XHRcdFx0cm93W3Bvc10gKz0gJzwvc3Bhbj4nO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCFyb3dbcG9zXSkge1xuXHRcdFx0XHRcdHJvd1twb3NdID0gJyAnO1xuXHRcdFx0XHRcdHJvd1twb3NdICs9IHNwYWNlQWZ0ZXI7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cbiAgICAgICBcdHZhciBzdHIgPSByb3cuam9pbihcIlwiKTtcbiAgICBcdFxuICAgIFx0cmV0dXJuICggc3RyLmluZGV4T2YoXCJzcGFuXCIpID09IC0xICk/IFwiXCIgOiBzdHI7XG4gICAgfSxcbiAgICAvKiBcbiAgICAgKiBGdW5jdGlvbjogU2VxdWVuY2UuX2RyYXdSYXdcbiAgICAgKiBQdXJwb3NlOiAgUmVwYWludCB0aGUgY3VycmVudCBzZXF1ZW5jZSB1c2luZyBSQVcgZm9ybWF0LiAgXG4gICAgICogUmV0dXJuczogIC1cbiAgICAgKiBJbnB1dHM6IC1cbiAgICAgKi9cblx0X2RyYXdSYXcgOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cdFx0dmFyIGEgPSB0aGlzLm9wdC5zZXF1ZW5jZS50b0xvd2VyQ2FzZSgpLnNwbGl0KCcnKTtcblx0XHR2YXIgaSA9IDA7XG5cdFx0dmFyIGFyciA9IFtdO1xuXHRcdHZhciBwcmUgPSBqUXVlcnkoJzxwcmU+PC9wcmU+JykuYXBwZW5kVG8odGhpcy5fY29udGVudERpdik7XG5cdFx0XG5cdFx0LyogQ29ycmVjdCBjb2x1bW4gc2l6ZSBpbiBjYXNlIHRoZSBzZXF1ZW5jZSBpcyBhcyBzbWFsbCBwZXB0aWRlICovXG5cdFx0dmFyIG51bUNvbHMgPSB0aGlzLm9wdC5jb2x1bW5zLnNpemU7XG5cdFx0aWYgKCB0aGlzLm9wdC5zZXF1ZW5jZS5sZW5ndGggPCB0aGlzLm9wdC5jb2x1bW5zLnNpemUgKSB7XG5cdFx0XHRudW1Db2xzID0gdGhpcy5vcHQuc2VxdWVuY2UubGVuZ3RoO1x0XG5cdFx0fVxuXG5cdFx0dmFyIG9wdCA9IHtcblx0XHRcdG51bUNvbHM6IG51bUNvbHNcblx0XHR9O1xuXHRcdFxuXHRcdHByZS5odG1sKFxuXHRcdFx0dGhpcy5fZHJhd1NlcXVlbmNlKGEsIG9wdClcblx0XHQpO1xuXHRcdFxuXHRcdHRoaXMuX2RyYXdBbm5vdGF0aW9ucyhvcHQpO1xuXHR9LFxuXHQvKiBcbiAgICAgKiBGdW5jdGlvbjogU2VxdWVuY2UuX2RyYXdQcmlkZVxuICAgICAqIFB1cnBvc2U6ICBSZXBhaW50IHRoZSBjdXJyZW50IHNlcXVlbmNlIHVzaW5nIFBSSURFIGZvcm1hdC4gIFxuICAgICAqIFJldHVybnM6ICAtXG4gICAgICogSW5wdXRzOiAtXG4gICAgICovXG5cdF9kcmF3UHJpZGUgOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cdFx0dmFyIGEgPSB0aGlzLm9wdC5zZXF1ZW5jZS50b1VwcGVyQ2FzZSgpLnNwbGl0KCcnKTtcblx0XHR2YXIgcHJlID0galF1ZXJ5KCc8cHJlPjwvcHJlPicpLmFwcGVuZFRvKHRoaXMuX2NvbnRlbnREaXYpO1xuXHRcdFxuXHRcdC8qIENvcnJlY3QgY29sdW1uIHNpemUgaW4gY2FzZSB0aGUgc2VxdWVuY2UgaXMgYXMgc21hbGwgcGVwdGlkZSAqL1xuXHRcdHZhciBudW1Db2xzID0gdGhpcy5vcHQuY29sdW1ucy5zaXplO1xuXHRcdGlmICggdGhpcy5vcHQuc2VxdWVuY2UubGVuZ3RoIDwgdGhpcy5vcHQuY29sdW1ucy5zaXplICkge1xuXHRcdFx0bnVtQ29scyA9IHRoaXMub3B0LnNlcXVlbmNlLmxlbmd0aDtcdFxuXHRcdH1cblx0XG5cdFx0b3B0ID0ge1xuXHRcdFx0bnVtTGVmdDogdHJ1ZSxcblx0XHRcdG51bUxlZnRTaXplOiA1LFxuXHRcdFx0bnVtTGVmdFBhZDonMCcsXG5cdFx0XHRudW1SaWdodDogdHJ1ZSxcblx0XHRcdG51bVJpZ2h0U2l6ZTogNSxcblx0XHRcdG51bVJpZ2h0UGFkOiAnMCcsXG5cdFx0XHRudW1Db2xzOiBudW1Db2xzLFxuXHRcdCAgICBudW1Db2xzRm9yU3BhY2U6IHNlbGYub3B0LmNvbHVtbnMuc3BhY2VkRWFjaFxuXHRcdH07XG5cdFx0XG5cdFx0cHJlLmh0bWwoXG5cdFx0XHR0aGlzLl9kcmF3U2VxdWVuY2UoYSwgb3B0KVxuXHRcdCk7XG5cdFx0XG5cdFx0dGhpcy5fZHJhd0Fubm90YXRpb25zKG9wdCk7XG5cdH0sXG5cdC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fZHJhd1NlcXVlbmNlXG4gICAgICogUHVycG9zZTogIFJlcGFpbnQgdGhlIGN1cnJlbnQgc2VxdWVuY2UgdXNpbmcgQ1VTVE9NIGZvcm1hdC4gIFxuICAgICAqIFJldHVybnM6ICAtXG4gICAgICogSW5wdXRzOiAgIGEgLT4ge2NoYXJbXX0gYSBUaGUgc2VxdWVuY2Ugc3RyYW5kLlxuICAgICAqIFx0XHRcdCBvcHQgLT4ge09iamVjdH0gb3B0IFRoZSBDVVNUT00gZm9ybWF0LlxuICAgICAqL1xuXHRfZHJhd1NlcXVlbmNlIDogZnVuY3Rpb24oYSwgb3B0KSB7XG5cdFx0dmFyIHN0ciA9ICcnO1xuXG5cdFx0dmFyIHNwYWNlU3R5bGUgPSAgXCJ3aGl0ZS1zcGFjZTogcHJlO1wiO1xuXHRcdFxuXHRcdC8vIEluZGV4IGF0IHRvcD9cblx0XHRpZiggb3B0Lm51bVRvcCApXG5cdFx0e1xuXHRcdFx0c3RyICs9ICc8c3BhbiBzdHlsZT1cIicrc3BhY2VTdHlsZSsnXCIgY2xhc3M9XCJudW1Ub3BcIj4nXG5cdFx0XHR2YXIgc2l6ZSA9IChvcHQuc3BhY2VCZXR3ZWVuQ2hhcnMpPyBvcHQubnVtVG9wRWFjaCoyOiBvcHQubnVtVG9wRWFjaDtcblx0XHRcdFxuXHRcdFx0aWYgKG9wdC5udW1MZWZ0KSB7XG5cdFx0XHRcdHN0ciArPSB0aGlzLl9mb3JtYXRJbmRleCgnICcsIG9wdC5udW1MZWZ0U2l6ZSwgJyAnKTtcblx0XHRcdH1cblx0XHRcdFxuXHRcdFx0c3RyICs9IHRoaXMuX2Zvcm1hdEluZGV4KCcgJywgc2l6ZSwgJyAnKTtcblx0XHRcdFxuXHRcdFx0Zm9yKHZhciB4ID0gb3B0Lm51bVRvcEVhY2g7IHggPCBvcHQubnVtQ29sczsgeCArPSBvcHQubnVtVG9wRWFjaCkge1xuXHRcdFx0XHRzdHIgKz0gdGhpcy5fZm9ybWF0SW5kZXgoeCwgc2l6ZSwgJyAnLCB0cnVlKTtcblx0XHRcdH1cblx0XHRcdHN0ciArPSAnPC9zcGFuPjxici8+J1xuXHRcdH1cblx0XHRcblx0XHRcblx0XHQvLyBJbmRleCBhdCB0aGUgbGVmdD9cblx0XHRpZiAob3B0Lm51bUxlZnQpIHtcblx0XHRcdHN0ciArPSB0aGlzLl9mb3JtYXRJbmRleCgxLCBvcHQubnVtTGVmdFNpemUsIG9wdC5udW1MZWZ0UGFkKTtcblx0XHRcdHN0ciArPSAnICAnO1xuXHRcdH1cblxuXHRcdHZhciBqPTE7XG5cdFx0Zm9yICh2YXIgaT0xOyBpIDw9IGEubGVuZ3RoOyBpKyspIHtcblxuXHRcdFx0aWYoIGkgJSBvcHQubnVtQ29scyA9PSAwKSB7XHRcblx0XHRcdFx0c3RyICs9ICc8c3BhbiBjbGFzcz1cInNlcXVlbmNlXCIgaWQ9XCInICsgdGhpcy5nZXRJZCgpICsgJ18nICsgaSArICdcIj4nICsgYVtpLTFdICsgJzwvc3Bhbj4nO1xuXHRcdFx0XHRcblx0XHRcdFx0aWYgKG9wdC5udW1SaWdodCkge1xuXHRcdFx0XHRcdHN0ciArPSAnPHNwYW4gc3R5bGU9XCInK3NwYWNlU3R5bGUrJ1wiIGlkPVwibnVtUmlnaHRfJyArIHRoaXMuZ2V0SWQoKSArICdfJyArIGkgKyAnXCI+Jztcblx0XHRcdFx0XHRzdHIgKz0gJyAgJztcblx0XHRcdFx0XHRzdHIgKz0gdGhpcy5fZm9ybWF0SW5kZXgoaSwgb3B0Lm51bVJpZ2h0U2l6ZSwgb3B0Lm51bVJpZ2h0UGFkKTtcdFxuXHRcdFx0XHRcdHN0ciArPSAnPC9zcGFuPic7XG5cdFx0XHRcdH1cblx0XHRcdFx0XG5cdFx0XHRcdHN0ciArPSAnPGJyLz4nO1xuXHRcdFx0XHRcblx0XHRcdFx0dmFyIGFhUmVtYWluaW5nID0gYS5sZW5ndGggLSBpO1xuXHRcdFx0XHRpZiAob3B0Lm51bUxlZnQgJiYgYWFSZW1haW5pbmcgPiAwKSB7XG5cdFx0XHRcdFx0c3RyICs9ICc8c3BhbiBpZD1cIm51bUxlZnRfJyArIHRoaXMuZ2V0SWQoKSArICdfJyArIGkgKyAnXCI+Jztcblx0XHRcdFx0XHRzdHIgKz0gdGhpcy5fZm9ybWF0SW5kZXgoaSsxLCBvcHQubnVtTGVmdFNpemUsIG9wdC5udW1MZWZ0UGFkKTtcblx0XHRcdFx0XHRzdHIgKz0gJyAgJztcblx0XHRcdFx0XHRzdHIgKz0gJzwvc3Bhbj4nO1xuXHRcdFx0XHR9XG5cdFx0XHRcdFxuXHRcdFx0XHRqID0gMTtcblx0XHRcdFx0XG5cdFx0XHR9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHN0ciArPSAnPHNwYW4gY2xhc3M9XCJzZXF1ZW5jZVwiIHN0eWxlPVwiJytzcGFjZVN0eWxlKydcIiBpZD1cIicgKyB0aGlzLmdldElkKCkgKyAnXycgKyBpICsgJ1wiPicgKyBhW2ktMV07XG5cdFx0XHRcdHN0ciArPSAoIGogJSBvcHQubnVtQ29sc0ZvclNwYWNlID09IDApPyAnICcgOiAnJztcblx0XHRcdFx0c3RyICs9IChvcHQuc3BhY2VCZXR3ZWVuQ2hhcnMpPyAnICcgOiAnJztcblx0XHRcdFx0c3RyICs9ICc8L3NwYW4+Jztcblx0XHRcdFx0aisrO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRcblx0XHRzdHIgKz0gJzxici8+J1x0XG5cdFx0XHRcblx0XHRpZiAoalF1ZXJ5LmJyb3dzZXIubXNpZSkge1xuXHRcdFx0c3RyID0gXCI8cHJlPlwiICsgc3RyICsgXCI8L3ByZT5cIjtcblx0XHR9XHRcblx0XHRcdFxuXHRcdHJldHVybiBzdHI7XG5cdH0sXG5cdC8qIFxuICAgICAqIEZ1bmN0aW9uOiBTZXF1ZW5jZS5fZm9ybWF0SW5kZXhcbiAgICAgKiBQdXJwb3NlOiAgQnVpbGQgdGhlIEhUTUwgY29ycmVzcG9uZGluZyB0byBjb3VudGluZyBudW1iZXJzICh0b3AsIGxlZnQsIHJpZ2h0KSBpbiB0aGUgc3RyYW5kLlxuICAgICAqIFJldHVybnM6ICAtXG4gICAgICogSW5wdXRzOiAgIG51bWJlciAtPiB7aW50fSBUaGUgbnVtYmVyIFxuICAgICAqIFx0XHRcdCBzaXplIC0+IHtpbnR9IE51bWJlciBvZiBiaW5zIHRvIHN1aXQgdGhlIG51bWJlci5cbiAgICAgKiBcdFx0XHQgZmlsbGluZ0NoYXIgLT4ge2NoYXJ9IENoYXJhY3RlciB0byBiZSB1c2VkIGZvciBmaWxsaW5nIG91dCBibGFuayBiaW5zLlxuICAgICAqIFx0XHRcdCBhbGlnbkxlZnQgLT4ge2Jvb2x9IFRlbGwgaWYgYWxpZ25lZCB0byB0aGUgbGVmdC5cbiAgICAgKi9cblx0X2Zvcm1hdEluZGV4IDogZnVuY3Rpb24oIG51bWJlciwgc2l6ZSwgZmlsbGluZ0NoYXIsIGFsaWduTGVmdCkge1xuXHRcdHZhciBzdHIgPSBudW1iZXIudG9TdHJpbmcoKTtcblx0XHR2YXIgZmlsbGluZyA9ICcnO1xuXHRcdHZhciBwYWRkaW5nID0gc2l6ZSAtIHN0ci5sZW5ndGg7XHRcblx0XHRpZiAoIHBhZGRpbmcgPiAwICkge1xuXHRcdFx0d2hpbGUgKCBwYWRkaW5nLS0gPiAwICkge1xuXHRcdFx0XHRmaWxsaW5nICs9IChcIjxzcGFuPlwiK2ZpbGxpbmdDaGFyK1wiPC9zcGFuPlwiKTtcblx0XHRcdH1cblx0XHRcdGlmIChhbGlnbkxlZnQpe1xuXHRcdFx0XHRzdHIgPSBudW1iZXIrZmlsbGluZztcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHN0ciA9IGZpbGxpbmcrbnVtYmVyO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gc3RyO1xuXHR9LFxuXHQvKiBcbiAgICAgKiBGdW5jdGlvbjogU2VxdWVuY2UuX2FkZFNwYW5FdmVudHNcbiAgICAgKiBQdXJwb3NlOiAgQWRkIHRoZSBldmVudCBoYW5kbGVycyB0byB0aGUgc3RyYW5kLlxuICAgICAqIFJldHVybnM6ICAtXG4gICAgICogSW5wdXRzOiAgIC1cbiAgICAgKi9cblx0X2FkZFNwYW5FdmVudHMgOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgc2VsZiA9IHRoaXM7XG5cdFx0dmFyIGlzTW91c2VEb3duID0gZmFsc2U7XG5cdFx0dmFyIGN1cnJlbnRQb3M7XG5cblx0XHRzZWxmLl9jb250ZW50RGl2LmZpbmQoJy5zZXF1ZW5jZScpLmVhY2goIGZ1bmN0aW9uICgpIHtcdFxuXHRcdFx0XG5cdFx0XHQvLyBSZWdpc3RlciB0aGUgc3RhcnRpbmcgcG9zaXRpb25cblx0XHRcdGpRdWVyeSh0aGlzKS5tb3VzZWRvd24oZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBpZCA9IGpRdWVyeSh0aGlzKS5hdHRyKCdpZCcpO1xuXHRcdFx0XHRjdXJyZW50UG9zID0gcGFyc2VJbnQoaWQuc3Vic3RyKGlkLmluZGV4T2YoXCJfXCIpICsgMSkpO1xuXHRcdFx0XHRjbGlja1BvcyA9IGN1cnJlbnRQb3M7XG5cdFx0XHRcdHNlbGYuX3NldFNlbGVjdGlvbihjbGlja1BvcyxjdXJyZW50UG9zKTtcblx0XHRcdFx0aXNNb3VzZURvd24gPSB0cnVlO1xuXHRcdFx0XHRcblx0XHRcdFx0Ly8gU2VsZWN0aW9uIGlzIGhhcHBlbmluZywgcmFpc2UgYW4gZXZlbnRcblx0XHRcdFx0c2VsZi50cmlnZ2VyKFxuXHRcdFx0XHRcdEVWVF9PTl9TRUxFQ1RJT05fQ0hBTkdFLCBcblx0XHRcdFx0XHR7IFxuXHRcdFx0XHRcdFx0XCJzdGFydFwiIDogc2VsZi5vcHQuc2VsZWN0aW9uLnN0YXJ0LCBcblx0XHRcdFx0XHRcdFwiZW5kXCIgOiBzZWxmLm9wdC5zZWxlY3Rpb24uZW5kIFxuXHRcdFx0XHRcdH1cblx0XHRcdFx0KTtcblx0XHRcdFxuXHRcdFx0fSkubW91c2VvdmVyKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQvLyBVcGRhdGUgc2VsZWN0aW9uXG5cdFx0XHRcdC8vIFNob3cgdG9vbHRpcCBjb250YWluaW5nIHRoZSBwb3NpdGlvblxuXHRcdFx0XHR2YXIgaWQgPSBqUXVlcnkodGhpcykuYXR0cignaWQnKTtcblx0XHRcdFx0Y3VycmVudFBvcyA9IHBhcnNlSW50KGlkLnN1YnN0cihpZC5pbmRleE9mKFwiX1wiKSArIDEpKTtcblx0XHRcdFx0XG5cdFx0XHRcdGlmKGlzTW91c2VEb3duKSB7XG5cdFx0XHRcdFx0aWYoIGN1cnJlbnRQb3MgPiBjbGlja1BvcyApIHtcblx0XHRcdFx0XHRcdHNlbGYuX3NldFNlbGVjdGlvbihjbGlja1BvcywgY3VycmVudFBvcyk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHNlbGYuX3NldFNlbGVjdGlvbihjdXJyZW50UG9zLCBjbGlja1Bvcyk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFxuXHRcdFx0XHRcdC8vIFNlbGVjdGlvbiBpcyBoYXBwZW5pbmcsIHJhaXNlIGFuIGV2ZW50XG5cdFx0XHRcdFx0c2VsZi50cmlnZ2VyKCBFVlRfT05fU0VMRUNUSU9OX0NIQU5HRSwgeyBcblx0XHRcdFx0XHRcdFwic3RhcnRcIiA6IHNlbGYub3B0LnNlbGVjdGlvbi5zdGFydCwgXG5cdFx0XHRcdFx0XHRcImVuZFwiIDogc2VsZi5vcHQuc2VsZWN0aW9uLmVuZCBcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fSBcblx0XHRcdFx0XG5cdFx0XHR9KS5tb3VzZXVwKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpc01vdXNlRG93biA9IGZhbHNlO1xuXHRcdFx0XHQvLyBTZWxlY3Rpb24gaXMgZG9uZSwgcmFpc2UgYW4gZXZlbnRcblx0XHRcdFx0c2VsZi50cmlnZ2VyKCBFVlRfT05fU0VMRUNUSU9OX0NIQU5HRUQsIHsgXG5cdFx0XHRcdFx0XCJzdGFydFwiIDogc2VsZi5vcHQuc2VsZWN0aW9uLnN0YXJ0LCBcblx0XHRcdFx0XHRcImVuZFwiIDogc2VsZi5vcHQuc2VsZWN0aW9uLmVuZCBcblx0XHRcdFx0fSk7XG5cdFx0XHR9KTtcblx0XHRcdFxuXHRcdFx0Ly8gQWRkIGEgdG9vbHRpcCBmb3IgdGhpcyBzZXF1ZW5jZSBiYXNlLlxuXHRcdFx0c2VsZi5fYWRkVG9vbFRpcC5jYWxsKCBzZWxmLCB0aGlzLCBmdW5jdGlvbiggKSB7XG5cdFx0XHRcdGlmIChpc01vdXNlRG93bikge1xuXHQgICAgIFx0XHRcdHJldHVybiBcIltcIiArIHNlbGYub3B0LnNlbGVjdGlvbi5zdGFydCArXCIsIFwiICsgc2VsZi5vcHQuc2VsZWN0aW9uLmVuZCArIFwiXVwiO1xuXHQgICAgIFx0XHR9IGVsc2Uge1xuXHQgICAgIFx0XHRcdHJldHVybiBjdXJyZW50UG9zO1xuXHQgICAgIFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdFxuXHRcdH0pXG5cdFx0LmNzcygnY3Vyc29yJywgJ3BvaW50ZXInKTtcblx0fSxcblx0LyogXG4gICAgICogRnVuY3Rpb246IFNlcXVlbmNlLl9hZGRUb29sdGlwXG4gICAgICogUHVycG9zZTogIEFkZCBhIHRvb2x0aXAgYXJvdW5kIHRoZSB0YXJnZXQgRE9NIGVsZW1lbnQgcHJvdmlkZWQgYXMgYXJndW1lbnRcbiAgICAgKiBSZXR1cm5zOiAgLVxuICAgICAqIElucHV0czogICB0YXJnZXQgLT4ge0VsZW1lbnR9IERPTSBlbGVtZW50IHdpY2ggaXMgdGhlIHRhcmdldGVkIGZvY3VzIGZvciB0aGUgdG9vbHRpcC5cbiAgICAgKiBcdFx0XHQgY2JHZXRNZXNzYWdlRnVuY3Rpb24gLT4ge2Z1bmN0aW9ufSBBIGNhbGxiYWNrIGZ1bmN0aW9uIHdpY2ggcmV0dXJucyB0aGUgbWVzc2FnZSB0byBiZSBkaXNwbGF5ZWQgaW4gdGhlIHRpcC5cbiAgICAgKi9cblx0X2FkZFRvb2xUaXAgOiBmdW5jdGlvbiAoIHRhcmdldCwgY2JHZXRNZXNzYWdlRnVuY3Rpb24gKSB7XG5cdFx0XG4gXHRcdHZhciB0aXBJZCA9IHRoaXMub3B0Ll90b29sdGlwO1xuXHRcdFxuXHRcdGpRdWVyeSh0YXJnZXQpLm1vdXNlb3ZlcihmdW5jdGlvbihlKSB7XG5cdFx0XHRcblx0IFx0XHR2YXIgb2Zmc2V0ID0galF1ZXJ5KGUudGFyZ2V0KS5vZmZzZXQoKTtcblxuXHRcdFx0aWYgKCAhIGpRdWVyeSggdGlwSWQgKS5pcygnOnZpc2libGUnKSApIHtcblx0XHQgICAgICAgIGpRdWVyeSggdGlwSWQgKSBcblx0XHQgICAgICAgIFx0LmNzcyh7XG5cdFx0ICAgICAgICBcdFx0J2JhY2tncm91bmQtY29sb3InOiBcIiMwMDBcIixcblx0XHQgICAgICAgIFx0XHQncGFkZGluZyc6IFwiM3B4IDEwcHggM3B4IDEwcHhcIixcblx0XHQgICAgICAgIFx0XHQndG9wJzogb2Zmc2V0LnRvcCArIGpRdWVyeShlLnRhcmdldCkuaGVpZ2h0KCkgKyBcInB4XCIsXG5cdFx0ICAgICAgICBcdFx0J2xlZnQnOiBvZmZzZXQubGVmdCArIGpRdWVyeShlLnRhcmdldCkud2lkdGgoKSArIFwicHhcIlxuXHRcdCAgICAgICAgXHR9KVxuXHRcdFx0ICAgICAgICAuYW5pbWF0ZSgge29wYWNpdHk6ICcwLjg1J30sIDEwKVxuXHRcdFx0ICAgICAgICAuaHRtbCggY2JHZXRNZXNzYWdlRnVuY3Rpb24uY2FsbCggdGFyZ2V0ICkgKVxuXHRcdFx0ICAgICAgICAuc2hvdygpO1xuXHRcdFx0fVxuXG5cdCAgICB9KS5tb3VzZW91dChmdW5jdGlvbigpIHtcblx0ICAgICAgICAvL1JlbW92ZSB0aGUgYXBwZW5kZWQgdG9vbHRpcCB0ZW1wbGF0ZVxuXHQgICAgICAgIGpRdWVyeSggdGlwSWQgKS5oaWRlKCk7XHQgICAgICAgICBcblx0ICAgIH0pO1xuXHR9LFxuXHRcbiAgIC8qKlxuICAgICogQW5ub3RhdGUgYSBzZXQgb2YgaW50ZXJ2YWxzIHByb3ZpZGVkIGluIHRoZSBhcmd1bWVudC5cblx0KiBcblx0KiBAZGVwcmVjYXRlZCBVc2UgYWRkQW5ub3RhdGlvbigpIGluc3RlYWQuXG4gICAgKiBcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBhbm5vdGF0aW9uIFRoZSBpbnRlcnZhbHMgYmVsb25naW5nIHRvIHRoZSBzYW1lIGFubm90YXRpb24uIFxuICAgICogU3ludGF4OiB7IG5hbWU6ICZsdDt2YWx1ZSZndDssIGNvbG9yOiAmbHQ7SFRNTENvbG9yQ29kZSZndDssIGh0bWw6ICZsdDtIVE1MU3RyaW5nJmd0OywgcmVnaW9uczogW3sgc3RhcnQ6ICZsdDtzdGFydFZhbDEmZ3Q7LCBlbmQ6ICZsdDtlbmRWYWwxJmd0O30sIC4uLiwgIHsgc3RhcnQ6ICZsdDtzdGFydFZhbE4mZ3Q7LCBlbmQ6ICZsdDtlbmRWYWxOJmd0O31dIH1cbiAgICAqL1xuXHRzZXRBbm5vdGF0aW9uOiBmdW5jdGlvbiAoIGFubm90YXRpb24gKSB7XG5cdFx0dGhpcy5hZGRBbm5vdGF0aW9uKGFubm90YXRpb24pO1xuXHR9LFxuXHRcblx0LyoqXG4gICAgKiBBbm5vdGF0ZSBhIHNldCBvZiBpbnRlcnZhbHMgcHJvdmlkZWQgaW4gdGhlIGFyZ3VtZW50LlxuICAgICogXG4gICAgKiBAZXhhbXBsZVxuICAgICogLy8gQW5ub3RhdGlvbnMgdXNpbmcgcmVnaW9ucyB3aXRoIGRpZmZlcmVudCBjb2xvcnMuXG4gICAgKiBteVNlcXVlbmNlLmFkZEFubm90YXRpb24oe1xuXHQqICAgIG5hbWU6XCJVTklQUk9UXCIsIFxuXHQqICAgIGh0bWw6XCImbHQ7YnImZ3Q7IEV4YW1wbGUgb2YgJmx0O2ImZ3Q7SFRNTCZsdDsvYiZndDtcIiwgXG5cdCogICAgY29sb3I6XCJncmVlblwiLCBcblx0KiAgICByZWdpb25zOiBbXG5cdCogICAgICAge3N0YXJ0OiA1NDAsIGVuZDogNTYwfSxcblx0KiAgICAgICB7c3RhcnQ6IDU2MSwgZW5kOjU4MCwgY29sb3I6IFwiI0ZGQTAxMFwifSwgXG5cdCogICAgICAge3N0YXJ0OiA1ODEsIGVuZDo1OTAsIGNvbG9yOiBcInJlZFwifSwgXG5cdCogICAgICAge3N0YXJ0OiA2OTAsIGVuZDo3MTB9XVxuXHQqIH0pO1xuXHQqIFxuICAgICogXG4gICAgKiBAcGFyYW0ge09iamVjdH0gYW5ub3RhdGlvbiBUaGUgaW50ZXJ2YWxzIGJlbG9uZ2luZyB0byB0aGUgc2FtZSBhbm5vdGF0aW9uLiBcbiAgICAqIFN5bnRheDogeyBuYW1lOiAmbHQ7dmFsdWUmZ3Q7LCBjb2xvcjogJmx0O0hUTUxDb2xvckNvZGUmZ3Q7LCBodG1sOiAmbHQ7SFRNTFN0cmluZyZndDssIHJlZ2lvbnM6IFt7IHN0YXJ0OiAmbHQ7c3RhcnRWYWwxJmd0OywgZW5kOiAmbHQ7ZW5kVmFsMSZndDt9LCAuLi4sICB7IHN0YXJ0OiAmbHQ7c3RhcnRWYWxOJmd0OywgZW5kOiAmbHQ7ZW5kVmFsTiZndDt9XSB9XG4gICAgKi9cblx0YWRkQW5ub3RhdGlvbjogZnVuY3Rpb24gKCBhbm5vdGF0aW9uICkge1xuXHRcdHRoaXMuX2Fubm90YXRpb25zLnB1c2goYW5ub3RhdGlvbik7XG5cdFx0dGhpcy5fcmVkcmF3KCk7XG5cdH0sXG5cdFxuXHQvKipcbiAgICAqIFJlbW92ZXMgYW4gYW5ub3RhdGlvbiBieSBtZWFucyBvZiBpdHMgbmFtZS5cbiAgICAqIFxuICAgICogQGV4YW1wbGUgXG4gICAgKiAvLyBSZW1vdmUgdGhlIFVOSVBST1QgYW5ub3RhdGlvbi5cbiAgICAqIG15U2VxdWVuY2UucmVtb3ZlQW5ub3RhdGlvbignVU5JUFJPVCcpOyBcbiAgICAqIFxuICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgVGhlIG5hbWUgb2YgdGhlIGFubm90YXRpb24gdG8gYmUgcmVtb3ZlZC5cbiAgICAqIFxuICAgICovXG5cdHJlbW92ZUFubm90YXRpb246IGZ1bmN0aW9uICggbmFtZSApIHtcblx0XHRmb3IgKHZhciBpPTA7IGkgPCB0aGlzLl9hbm5vdGF0aW9ucy5sZW5ndGggOyBpKysgKXtcblx0XHRcdGlmKG5hbWUgIT0gdGhpcy5fYW5ub3RhdGlvbnNbaV0ubmFtZSl7XG5cdFx0XHRcdHRoaXMuX2Fubm90YXRpb25zLnNwbGljZShpLDEpO1xuXHRcdFx0XHR0aGlzLl9yZWRyYXcoKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHQvKipcbiAgICAqIFJlbW92ZXMgYWxsIHRoZSBjdXJyZW50IGFubm90YXRpb25zLlxuICAgICogXG4gICAgKiBAZXhhbXBsZSBcbiAgICAqIG15U2VxdWVuY2UucmVtb3ZlQWxsQW5ub3RhdGlvbnMoKTsgXG4gICAgKiBcbiAgICAqL1xuXHRyZW1vdmVBbGxBbm5vdGF0aW9uczogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX2Fubm90YXRpb25zID0gW107XG5cdFx0dGhpcy5fcmVkcmF3KCk7XG5cdH0sXG5cblx0XG59KTtcblxucmVxdWlyZShcImJpb2pzLWV2ZW50c1wiKS5taXhpbihTZXF1ZW5jZS5wcm90b3R5cGUpO1xubW9kdWxlLmV4cG9ydHMgPSBTZXF1ZW5jZTtcbiIsInZhciBldmVudHMgPSByZXF1aXJlKFwiYmFja2JvbmUtZXZlbnRzLXN0YW5kYWxvbmVcIik7XG5cbmV2ZW50cy5vbkFsbCA9IGZ1bmN0aW9uKGNhbGxiYWNrLGNvbnRleHQpe1xuICB0aGlzLm9uKFwiYWxsXCIsIGNhbGxiYWNrLGNvbnRleHQpO1xuICByZXR1cm4gdGhpcztcbn07XG5cbi8vIE1peGluIHV0aWxpdHlcbmV2ZW50cy5vbGRNaXhpbiA9IGV2ZW50cy5taXhpbjtcbmV2ZW50cy5taXhpbiA9IGZ1bmN0aW9uKHByb3RvKSB7XG4gIGV2ZW50cy5vbGRNaXhpbihwcm90byk7XG4gIC8vIGFkZCBjdXN0b20gb25BbGxcbiAgdmFyIGV4cG9ydHMgPSBbJ29uQWxsJ107XG4gIGZvcih2YXIgaT0wOyBpIDwgZXhwb3J0cy5sZW5ndGg7aSsrKXtcbiAgICB2YXIgbmFtZSA9IGV4cG9ydHNbaV07XG4gICAgcHJvdG9bbmFtZV0gPSB0aGlzW25hbWVdO1xuICB9XG4gIHJldHVybiBwcm90bztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZXZlbnRzO1xuIiwiLyoqXG4gKiBTdGFuZGFsb25lIGV4dHJhY3Rpb24gb2YgQmFja2JvbmUuRXZlbnRzLCBubyBleHRlcm5hbCBkZXBlbmRlbmN5IHJlcXVpcmVkLlxuICogRGVncmFkZXMgbmljZWx5IHdoZW4gQmFja29uZS91bmRlcnNjb3JlIGFyZSBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudFxuICogZ2xvYmFsIGNvbnRleHQuXG4gKlxuICogTm90ZSB0aGF0IGRvY3Mgc3VnZ2VzdCB0byB1c2UgdW5kZXJzY29yZSdzIGBfLmV4dGVuZCgpYCBtZXRob2QgdG8gYWRkIEV2ZW50c1xuICogc3VwcG9ydCB0byBzb21lIGdpdmVuIG9iamVjdC4gQSBgbWl4aW4oKWAgbWV0aG9kIGhhcyBiZWVuIGFkZGVkIHRvIHRoZSBFdmVudHNcbiAqIHByb3RvdHlwZSB0byBhdm9pZCB1c2luZyB1bmRlcnNjb3JlIGZvciB0aGF0IHNvbGUgcHVycG9zZTpcbiAqXG4gKiAgICAgdmFyIG15RXZlbnRFbWl0dGVyID0gQmFja2JvbmVFdmVudHMubWl4aW4oe30pO1xuICpcbiAqIE9yIGZvciBhIGZ1bmN0aW9uIGNvbnN0cnVjdG9yOlxuICpcbiAqICAgICBmdW5jdGlvbiBNeUNvbnN0cnVjdG9yKCl7fVxuICogICAgIE15Q29uc3RydWN0b3IucHJvdG90eXBlLmZvbyA9IGZ1bmN0aW9uKCl7fVxuICogICAgIEJhY2tib25lRXZlbnRzLm1peGluKE15Q29uc3RydWN0b3IucHJvdG90eXBlKTtcbiAqXG4gKiAoYykgMjAwOS0yMDEzIEplcmVteSBBc2hrZW5hcywgRG9jdW1lbnRDbG91ZCBJbmMuXG4gKiAoYykgMjAxMyBOaWNvbGFzIFBlcnJpYXVsdFxuICovXG4vKiBnbG9iYWwgZXhwb3J0czp0cnVlLCBkZWZpbmUsIG1vZHVsZSAqL1xuKGZ1bmN0aW9uKCkge1xuICB2YXIgcm9vdCA9IHRoaXMsXG4gICAgICBicmVha2VyID0ge30sXG4gICAgICBuYXRpdmVGb3JFYWNoID0gQXJyYXkucHJvdG90eXBlLmZvckVhY2gsXG4gICAgICBoYXNPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHksXG4gICAgICBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZSxcbiAgICAgIGlkQ291bnRlciA9IDA7XG5cbiAgLy8gUmV0dXJucyBhIHBhcnRpYWwgaW1wbGVtZW50YXRpb24gbWF0Y2hpbmcgdGhlIG1pbmltYWwgQVBJIHN1YnNldCByZXF1aXJlZFxuICAvLyBieSBCYWNrYm9uZS5FdmVudHNcbiAgZnVuY3Rpb24gbWluaXNjb3JlKCkge1xuICAgIHJldHVybiB7XG4gICAgICBrZXlzOiBPYmplY3Qua2V5cyB8fCBmdW5jdGlvbiAob2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqICE9PSBcIm9iamVjdFwiICYmIHR5cGVvZiBvYmogIT09IFwiZnVuY3Rpb25cIiB8fCBvYmogPT09IG51bGwpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwia2V5cygpIGNhbGxlZCBvbiBhIG5vbi1vYmplY3RcIik7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGtleSwga2V5cyA9IFtdO1xuICAgICAgICBmb3IgKGtleSBpbiBvYmopIHtcbiAgICAgICAgICBpZiAob2JqLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgIGtleXNba2V5cy5sZW5ndGhdID0ga2V5O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ga2V5cztcbiAgICAgIH0sXG5cbiAgICAgIHVuaXF1ZUlkOiBmdW5jdGlvbihwcmVmaXgpIHtcbiAgICAgICAgdmFyIGlkID0gKytpZENvdW50ZXIgKyAnJztcbiAgICAgICAgcmV0dXJuIHByZWZpeCA/IHByZWZpeCArIGlkIDogaWQ7XG4gICAgICB9LFxuXG4gICAgICBoYXM6IGZ1bmN0aW9uKG9iaiwga2V5KSB7XG4gICAgICAgIHJldHVybiBoYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KTtcbiAgICAgIH0sXG5cbiAgICAgIGVhY2g6IGZ1bmN0aW9uKG9iaiwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICAgICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm47XG4gICAgICAgIGlmIChuYXRpdmVGb3JFYWNoICYmIG9iai5mb3JFYWNoID09PSBuYXRpdmVGb3JFYWNoKSB7XG4gICAgICAgICAgb2JqLmZvckVhY2goaXRlcmF0b3IsIGNvbnRleHQpO1xuICAgICAgICB9IGVsc2UgaWYgKG9iai5sZW5ndGggPT09ICtvYmoubGVuZ3RoKSB7XG4gICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBvYmoubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpbaV0sIGksIG9iaikgPT09IGJyZWFrZXIpIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZm9yICh2YXIga2V5IGluIG9iaikge1xuICAgICAgICAgICAgaWYgKHRoaXMuaGFzKG9iaiwga2V5KSkge1xuICAgICAgICAgICAgICBpZiAoaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpba2V5XSwga2V5LCBvYmopID09PSBicmVha2VyKSByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICBvbmNlOiBmdW5jdGlvbihmdW5jKSB7XG4gICAgICAgIHZhciByYW4gPSBmYWxzZSwgbWVtbztcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICAgIGlmIChyYW4pIHJldHVybiBtZW1vO1xuICAgICAgICAgIHJhbiA9IHRydWU7XG4gICAgICAgICAgbWVtbyA9IGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICBmdW5jID0gbnVsbDtcbiAgICAgICAgICByZXR1cm4gbWVtbztcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgdmFyIF8gPSBtaW5pc2NvcmUoKSwgRXZlbnRzO1xuXG4gIC8vIEJhY2tib25lLkV2ZW50c1xuICAvLyAtLS0tLS0tLS0tLS0tLS1cblxuICAvLyBBIG1vZHVsZSB0aGF0IGNhbiBiZSBtaXhlZCBpbiB0byAqYW55IG9iamVjdCogaW4gb3JkZXIgdG8gcHJvdmlkZSBpdCB3aXRoXG4gIC8vIGN1c3RvbSBldmVudHMuIFlvdSBtYXkgYmluZCB3aXRoIGBvbmAgb3IgcmVtb3ZlIHdpdGggYG9mZmAgY2FsbGJhY2tcbiAgLy8gZnVuY3Rpb25zIHRvIGFuIGV2ZW50OyBgdHJpZ2dlcmAtaW5nIGFuIGV2ZW50IGZpcmVzIGFsbCBjYWxsYmFja3MgaW5cbiAgLy8gc3VjY2Vzc2lvbi5cbiAgLy9cbiAgLy8gICAgIHZhciBvYmplY3QgPSB7fTtcbiAgLy8gICAgIF8uZXh0ZW5kKG9iamVjdCwgQmFja2JvbmUuRXZlbnRzKTtcbiAgLy8gICAgIG9iamVjdC5vbignZXhwYW5kJywgZnVuY3Rpb24oKXsgYWxlcnQoJ2V4cGFuZGVkJyk7IH0pO1xuICAvLyAgICAgb2JqZWN0LnRyaWdnZXIoJ2V4cGFuZCcpO1xuICAvL1xuICBFdmVudHMgPSB7XG5cbiAgICAvLyBCaW5kIGFuIGV2ZW50IHRvIGEgYGNhbGxiYWNrYCBmdW5jdGlvbi4gUGFzc2luZyBgXCJhbGxcImAgd2lsbCBiaW5kXG4gICAgLy8gdGhlIGNhbGxiYWNrIHRvIGFsbCBldmVudHMgZmlyZWQuXG4gICAgb246IGZ1bmN0aW9uKG5hbWUsIGNhbGxiYWNrLCBjb250ZXh0KSB7XG4gICAgICBpZiAoIWV2ZW50c0FwaSh0aGlzLCAnb24nLCBuYW1lLCBbY2FsbGJhY2ssIGNvbnRleHRdKSB8fCAhY2FsbGJhY2spIHJldHVybiB0aGlzO1xuICAgICAgdGhpcy5fZXZlbnRzIHx8ICh0aGlzLl9ldmVudHMgPSB7fSk7XG4gICAgICB2YXIgZXZlbnRzID0gdGhpcy5fZXZlbnRzW25hbWVdIHx8ICh0aGlzLl9ldmVudHNbbmFtZV0gPSBbXSk7XG4gICAgICBldmVudHMucHVzaCh7Y2FsbGJhY2s6IGNhbGxiYWNrLCBjb250ZXh0OiBjb250ZXh0LCBjdHg6IGNvbnRleHQgfHwgdGhpc30pO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIEJpbmQgYW4gZXZlbnQgdG8gb25seSBiZSB0cmlnZ2VyZWQgYSBzaW5nbGUgdGltZS4gQWZ0ZXIgdGhlIGZpcnN0IHRpbWVcbiAgICAvLyB0aGUgY2FsbGJhY2sgaXMgaW52b2tlZCwgaXQgd2lsbCBiZSByZW1vdmVkLlxuICAgIG9uY2U6IGZ1bmN0aW9uKG5hbWUsIGNhbGxiYWNrLCBjb250ZXh0KSB7XG4gICAgICBpZiAoIWV2ZW50c0FwaSh0aGlzLCAnb25jZScsIG5hbWUsIFtjYWxsYmFjaywgY29udGV4dF0pIHx8ICFjYWxsYmFjaykgcmV0dXJuIHRoaXM7XG4gICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICB2YXIgb25jZSA9IF8ub25jZShmdW5jdGlvbigpIHtcbiAgICAgICAgc2VsZi5vZmYobmFtZSwgb25jZSk7XG4gICAgICAgIGNhbGxiYWNrLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICB9KTtcbiAgICAgIG9uY2UuX2NhbGxiYWNrID0gY2FsbGJhY2s7XG4gICAgICByZXR1cm4gdGhpcy5vbihuYW1lLCBvbmNlLCBjb250ZXh0KTtcbiAgICB9LFxuXG4gICAgLy8gUmVtb3ZlIG9uZSBvciBtYW55IGNhbGxiYWNrcy4gSWYgYGNvbnRleHRgIGlzIG51bGwsIHJlbW92ZXMgYWxsXG4gICAgLy8gY2FsbGJhY2tzIHdpdGggdGhhdCBmdW5jdGlvbi4gSWYgYGNhbGxiYWNrYCBpcyBudWxsLCByZW1vdmVzIGFsbFxuICAgIC8vIGNhbGxiYWNrcyBmb3IgdGhlIGV2ZW50LiBJZiBgbmFtZWAgaXMgbnVsbCwgcmVtb3ZlcyBhbGwgYm91bmRcbiAgICAvLyBjYWxsYmFja3MgZm9yIGFsbCBldmVudHMuXG4gICAgb2ZmOiBmdW5jdGlvbihuYW1lLCBjYWxsYmFjaywgY29udGV4dCkge1xuICAgICAgdmFyIHJldGFpbiwgZXYsIGV2ZW50cywgbmFtZXMsIGksIGwsIGosIGs7XG4gICAgICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhZXZlbnRzQXBpKHRoaXMsICdvZmYnLCBuYW1lLCBbY2FsbGJhY2ssIGNvbnRleHRdKSkgcmV0dXJuIHRoaXM7XG4gICAgICBpZiAoIW5hbWUgJiYgIWNhbGxiYWNrICYmICFjb250ZXh0KSB7XG4gICAgICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgbmFtZXMgPSBuYW1lID8gW25hbWVdIDogXy5rZXlzKHRoaXMuX2V2ZW50cyk7XG4gICAgICBmb3IgKGkgPSAwLCBsID0gbmFtZXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgIG5hbWUgPSBuYW1lc1tpXTtcbiAgICAgICAgaWYgKGV2ZW50cyA9IHRoaXMuX2V2ZW50c1tuYW1lXSkge1xuICAgICAgICAgIHRoaXMuX2V2ZW50c1tuYW1lXSA9IHJldGFpbiA9IFtdO1xuICAgICAgICAgIGlmIChjYWxsYmFjayB8fCBjb250ZXh0KSB7XG4gICAgICAgICAgICBmb3IgKGogPSAwLCBrID0gZXZlbnRzLmxlbmd0aDsgaiA8IGs7IGorKykge1xuICAgICAgICAgICAgICBldiA9IGV2ZW50c1tqXTtcbiAgICAgICAgICAgICAgaWYgKChjYWxsYmFjayAmJiBjYWxsYmFjayAhPT0gZXYuY2FsbGJhY2sgJiYgY2FsbGJhY2sgIT09IGV2LmNhbGxiYWNrLl9jYWxsYmFjaykgfHxcbiAgICAgICAgICAgICAgICAgIChjb250ZXh0ICYmIGNvbnRleHQgIT09IGV2LmNvbnRleHQpKSB7XG4gICAgICAgICAgICAgICAgcmV0YWluLnB1c2goZXYpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICghcmV0YWluLmxlbmd0aCkgZGVsZXRlIHRoaXMuX2V2ZW50c1tuYW1lXTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgLy8gVHJpZ2dlciBvbmUgb3IgbWFueSBldmVudHMsIGZpcmluZyBhbGwgYm91bmQgY2FsbGJhY2tzLiBDYWxsYmFja3MgYXJlXG4gICAgLy8gcGFzc2VkIHRoZSBzYW1lIGFyZ3VtZW50cyBhcyBgdHJpZ2dlcmAgaXMsIGFwYXJ0IGZyb20gdGhlIGV2ZW50IG5hbWVcbiAgICAvLyAodW5sZXNzIHlvdSdyZSBsaXN0ZW5pbmcgb24gYFwiYWxsXCJgLCB3aGljaCB3aWxsIGNhdXNlIHlvdXIgY2FsbGJhY2sgdG9cbiAgICAvLyByZWNlaXZlIHRoZSB0cnVlIG5hbWUgb2YgdGhlIGV2ZW50IGFzIHRoZSBmaXJzdCBhcmd1bWVudCkuXG4gICAgdHJpZ2dlcjogZnVuY3Rpb24obmFtZSkge1xuICAgICAgaWYgKCF0aGlzLl9ldmVudHMpIHJldHVybiB0aGlzO1xuICAgICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgICBpZiAoIWV2ZW50c0FwaSh0aGlzLCAndHJpZ2dlcicsIG5hbWUsIGFyZ3MpKSByZXR1cm4gdGhpcztcbiAgICAgIHZhciBldmVudHMgPSB0aGlzLl9ldmVudHNbbmFtZV07XG4gICAgICB2YXIgYWxsRXZlbnRzID0gdGhpcy5fZXZlbnRzLmFsbDtcbiAgICAgIGlmIChldmVudHMpIHRyaWdnZXJFdmVudHMoZXZlbnRzLCBhcmdzKTtcbiAgICAgIGlmIChhbGxFdmVudHMpIHRyaWdnZXJFdmVudHMoYWxsRXZlbnRzLCBhcmd1bWVudHMpO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIFRlbGwgdGhpcyBvYmplY3QgdG8gc3RvcCBsaXN0ZW5pbmcgdG8gZWl0aGVyIHNwZWNpZmljIGV2ZW50cyAuLi4gb3JcbiAgICAvLyB0byBldmVyeSBvYmplY3QgaXQncyBjdXJyZW50bHkgbGlzdGVuaW5nIHRvLlxuICAgIHN0b3BMaXN0ZW5pbmc6IGZ1bmN0aW9uKG9iaiwgbmFtZSwgY2FsbGJhY2spIHtcbiAgICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XG4gICAgICBpZiAoIWxpc3RlbmVycykgcmV0dXJuIHRoaXM7XG4gICAgICB2YXIgZGVsZXRlTGlzdGVuZXIgPSAhbmFtZSAmJiAhY2FsbGJhY2s7XG4gICAgICBpZiAodHlwZW9mIG5hbWUgPT09ICdvYmplY3QnKSBjYWxsYmFjayA9IHRoaXM7XG4gICAgICBpZiAob2JqKSAobGlzdGVuZXJzID0ge30pW29iai5fbGlzdGVuZXJJZF0gPSBvYmo7XG4gICAgICBmb3IgKHZhciBpZCBpbiBsaXN0ZW5lcnMpIHtcbiAgICAgICAgbGlzdGVuZXJzW2lkXS5vZmYobmFtZSwgY2FsbGJhY2ssIHRoaXMpO1xuICAgICAgICBpZiAoZGVsZXRlTGlzdGVuZXIpIGRlbGV0ZSB0aGlzLl9saXN0ZW5lcnNbaWRdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gIH07XG5cbiAgLy8gUmVndWxhciBleHByZXNzaW9uIHVzZWQgdG8gc3BsaXQgZXZlbnQgc3RyaW5ncy5cbiAgdmFyIGV2ZW50U3BsaXR0ZXIgPSAvXFxzKy87XG5cbiAgLy8gSW1wbGVtZW50IGZhbmN5IGZlYXR1cmVzIG9mIHRoZSBFdmVudHMgQVBJIHN1Y2ggYXMgbXVsdGlwbGUgZXZlbnRcbiAgLy8gbmFtZXMgYFwiY2hhbmdlIGJsdXJcImAgYW5kIGpRdWVyeS1zdHlsZSBldmVudCBtYXBzIGB7Y2hhbmdlOiBhY3Rpb259YFxuICAvLyBpbiB0ZXJtcyBvZiB0aGUgZXhpc3RpbmcgQVBJLlxuICB2YXIgZXZlbnRzQXBpID0gZnVuY3Rpb24ob2JqLCBhY3Rpb24sIG5hbWUsIHJlc3QpIHtcbiAgICBpZiAoIW5hbWUpIHJldHVybiB0cnVlO1xuXG4gICAgLy8gSGFuZGxlIGV2ZW50IG1hcHMuXG4gICAgaWYgKHR5cGVvZiBuYW1lID09PSAnb2JqZWN0Jykge1xuICAgICAgZm9yICh2YXIga2V5IGluIG5hbWUpIHtcbiAgICAgICAgb2JqW2FjdGlvbl0uYXBwbHkob2JqLCBba2V5LCBuYW1lW2tleV1dLmNvbmNhdChyZXN0KSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIHNwYWNlIHNlcGFyYXRlZCBldmVudCBuYW1lcy5cbiAgICBpZiAoZXZlbnRTcGxpdHRlci50ZXN0KG5hbWUpKSB7XG4gICAgICB2YXIgbmFtZXMgPSBuYW1lLnNwbGl0KGV2ZW50U3BsaXR0ZXIpO1xuICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBuYW1lcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgb2JqW2FjdGlvbl0uYXBwbHkob2JqLCBbbmFtZXNbaV1dLmNvbmNhdChyZXN0KSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gQSBkaWZmaWN1bHQtdG8tYmVsaWV2ZSwgYnV0IG9wdGltaXplZCBpbnRlcm5hbCBkaXNwYXRjaCBmdW5jdGlvbiBmb3JcbiAgLy8gdHJpZ2dlcmluZyBldmVudHMuIFRyaWVzIHRvIGtlZXAgdGhlIHVzdWFsIGNhc2VzIHNwZWVkeSAobW9zdCBpbnRlcm5hbFxuICAvLyBCYWNrYm9uZSBldmVudHMgaGF2ZSAzIGFyZ3VtZW50cykuXG4gIHZhciB0cmlnZ2VyRXZlbnRzID0gZnVuY3Rpb24oZXZlbnRzLCBhcmdzKSB7XG4gICAgdmFyIGV2LCBpID0gLTEsIGwgPSBldmVudHMubGVuZ3RoLCBhMSA9IGFyZ3NbMF0sIGEyID0gYXJnc1sxXSwgYTMgPSBhcmdzWzJdO1xuICAgIHN3aXRjaCAoYXJncy5sZW5ndGgpIHtcbiAgICAgIGNhc2UgMDogd2hpbGUgKCsraSA8IGwpIChldiA9IGV2ZW50c1tpXSkuY2FsbGJhY2suY2FsbChldi5jdHgpOyByZXR1cm47XG4gICAgICBjYXNlIDE6IHdoaWxlICgrK2kgPCBsKSAoZXYgPSBldmVudHNbaV0pLmNhbGxiYWNrLmNhbGwoZXYuY3R4LCBhMSk7IHJldHVybjtcbiAgICAgIGNhc2UgMjogd2hpbGUgKCsraSA8IGwpIChldiA9IGV2ZW50c1tpXSkuY2FsbGJhY2suY2FsbChldi5jdHgsIGExLCBhMik7IHJldHVybjtcbiAgICAgIGNhc2UgMzogd2hpbGUgKCsraSA8IGwpIChldiA9IGV2ZW50c1tpXSkuY2FsbGJhY2suY2FsbChldi5jdHgsIGExLCBhMiwgYTMpOyByZXR1cm47XG4gICAgICBkZWZhdWx0OiB3aGlsZSAoKytpIDwgbCkgKGV2ID0gZXZlbnRzW2ldKS5jYWxsYmFjay5hcHBseShldi5jdHgsIGFyZ3MpO1xuICAgIH1cbiAgfTtcblxuICB2YXIgbGlzdGVuTWV0aG9kcyA9IHtsaXN0ZW5UbzogJ29uJywgbGlzdGVuVG9PbmNlOiAnb25jZSd9O1xuXG4gIC8vIEludmVyc2lvbi1vZi1jb250cm9sIHZlcnNpb25zIG9mIGBvbmAgYW5kIGBvbmNlYC4gVGVsbCAqdGhpcyogb2JqZWN0IHRvXG4gIC8vIGxpc3RlbiB0byBhbiBldmVudCBpbiBhbm90aGVyIG9iamVjdCAuLi4ga2VlcGluZyB0cmFjayBvZiB3aGF0IGl0J3NcbiAgLy8gbGlzdGVuaW5nIHRvLlxuICBfLmVhY2gobGlzdGVuTWV0aG9kcywgZnVuY3Rpb24oaW1wbGVtZW50YXRpb24sIG1ldGhvZCkge1xuICAgIEV2ZW50c1ttZXRob2RdID0gZnVuY3Rpb24ob2JqLCBuYW1lLCBjYWxsYmFjaykge1xuICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVycyB8fCAodGhpcy5fbGlzdGVuZXJzID0ge30pO1xuICAgICAgdmFyIGlkID0gb2JqLl9saXN0ZW5lcklkIHx8IChvYmouX2xpc3RlbmVySWQgPSBfLnVuaXF1ZUlkKCdsJykpO1xuICAgICAgbGlzdGVuZXJzW2lkXSA9IG9iajtcbiAgICAgIGlmICh0eXBlb2YgbmFtZSA9PT0gJ29iamVjdCcpIGNhbGxiYWNrID0gdGhpcztcbiAgICAgIG9ialtpbXBsZW1lbnRhdGlvbl0obmFtZSwgY2FsbGJhY2ssIHRoaXMpO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcbiAgfSk7XG5cbiAgLy8gQWxpYXNlcyBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkuXG4gIEV2ZW50cy5iaW5kICAgPSBFdmVudHMub247XG4gIEV2ZW50cy51bmJpbmQgPSBFdmVudHMub2ZmO1xuXG4gIC8vIE1peGluIHV0aWxpdHlcbiAgRXZlbnRzLm1peGluID0gZnVuY3Rpb24ocHJvdG8pIHtcbiAgICB2YXIgZXhwb3J0cyA9IFsnb24nLCAnb25jZScsICdvZmYnLCAndHJpZ2dlcicsICdzdG9wTGlzdGVuaW5nJywgJ2xpc3RlblRvJyxcbiAgICAgICAgICAgICAgICAgICAnbGlzdGVuVG9PbmNlJywgJ2JpbmQnLCAndW5iaW5kJ107XG4gICAgXy5lYWNoKGV4cG9ydHMsIGZ1bmN0aW9uKG5hbWUpIHtcbiAgICAgIHByb3RvW25hbWVdID0gdGhpc1tuYW1lXTtcbiAgICB9LCB0aGlzKTtcbiAgICByZXR1cm4gcHJvdG87XG4gIH07XG5cbiAgLy8gRXhwb3J0IEV2ZW50cyBhcyBCYWNrYm9uZUV2ZW50cyBkZXBlbmRpbmcgb24gY3VycmVudCBjb250ZXh0XG4gIGlmICh0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICBkZWZpbmUoZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gRXZlbnRzO1xuICAgIH0pO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBleHBvcnRzICE9PSAndW5kZWZpbmVkJykge1xuICAgIGlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyAmJiBtb2R1bGUuZXhwb3J0cykge1xuICAgICAgZXhwb3J0cyA9IG1vZHVsZS5leHBvcnRzID0gRXZlbnRzO1xuICAgIH1cbiAgICBleHBvcnRzLkJhY2tib25lRXZlbnRzID0gRXZlbnRzO1xuICB9IGVsc2Uge1xuICAgIHJvb3QuQmFja2JvbmVFdmVudHMgPSBFdmVudHM7XG4gIH1cbn0pKHRoaXMpO1xuIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2JhY2tib25lLWV2ZW50cy1zdGFuZGFsb25lJyk7XG4iLCIvLyBHZW5lcmF0ZWQgYnkgQ29mZmVlU2NyaXB0IDEuOC4wXG52YXIgR2VuZXJpY1JlYWRlciwgeGhyO1xuXG54aHIgPSByZXF1aXJlKCduZXRzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gR2VuZXJpY1JlYWRlciA9IChmdW5jdGlvbigpIHtcbiAgZnVuY3Rpb24gR2VuZXJpY1JlYWRlcigpIHt9XG5cbiAgR2VuZXJpY1JlYWRlci5yZWFkID0gZnVuY3Rpb24odXJsLCBjYWxsYmFjaykge1xuICAgIHZhciBvbnJldDtcbiAgICBvbnJldCA9IChmdW5jdGlvbihfdGhpcykge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uKGVyciwgcmVzcG9uc2UsIHRleHQpIHtcbiAgICAgICAgcmV0dXJuIF90aGlzLl9vblJldHJpZXZhbCh0ZXh0LCBjYWxsYmFjayk7XG4gICAgICB9O1xuICAgIH0pKHRoaXMpO1xuICAgIHJldHVybiB4aHIodXJsLCBvbnJldCk7XG4gIH07XG5cbiAgR2VuZXJpY1JlYWRlci5fb25SZXRyaWV2YWwgPSBmdW5jdGlvbih0ZXh0LCBjYWxsYmFjaykge1xuICAgIHZhciByVGV4dDtcbiAgICByVGV4dCA9IHRoaXMucGFyc2UodGV4dCk7XG4gICAgcmV0dXJuIGNhbGxiYWNrKHJUZXh0KTtcbiAgfTtcblxuICByZXR1cm4gR2VuZXJpY1JlYWRlcjtcblxufSkoKTtcbiIsIi8vIEdlbmVyYXRlZCBieSBDb2ZmZWVTY3JpcHQgMS44LjBcbnZhciBGYXN0YSwgR2VuZXJpY1JlYWRlciwgU2VxLCBTdHIsXG4gIF9faGFzUHJvcCA9IHt9Lmhhc093blByb3BlcnR5LFxuICBfX2V4dGVuZHMgPSBmdW5jdGlvbihjaGlsZCwgcGFyZW50KSB7IGZvciAodmFyIGtleSBpbiBwYXJlbnQpIHsgaWYgKF9faGFzUHJvcC5jYWxsKHBhcmVudCwga2V5KSkgY2hpbGRba2V5XSA9IHBhcmVudFtrZXldOyB9IGZ1bmN0aW9uIGN0b3IoKSB7IHRoaXMuY29uc3RydWN0b3IgPSBjaGlsZDsgfSBjdG9yLnByb3RvdHlwZSA9IHBhcmVudC5wcm90b3R5cGU7IGNoaWxkLnByb3RvdHlwZSA9IG5ldyBjdG9yKCk7IGNoaWxkLl9fc3VwZXJfXyA9IHBhcmVudC5wcm90b3R5cGU7IHJldHVybiBjaGlsZDsgfTtcblxuU3RyID0gcmVxdWlyZShcIi4vc3RyaW5nc1wiKTtcblxuR2VuZXJpY1JlYWRlciA9IHJlcXVpcmUoXCIuL2dlbmVyaWNfcmVhZGVyXCIpO1xuXG5TZXEgPSByZXF1aXJlKFwiYmlvanMtbW9kZWxcIikuc2VxO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZhc3RhID0gKGZ1bmN0aW9uKF9zdXBlcikge1xuICBfX2V4dGVuZHMoRmFzdGEsIF9zdXBlcik7XG5cbiAgZnVuY3Rpb24gRmFzdGEoKSB7XG4gICAgcmV0dXJuIEZhc3RhLl9fc3VwZXJfXy5jb25zdHJ1Y3Rvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICB9XG5cbiAgRmFzdGEucGFyc2UgPSBmdW5jdGlvbih0ZXh0KSB7XG4gICAgdmFyIGN1cnJlbnRTZXEsIGRhdGFiYXNlLCBkYXRhYmFzZUlELCBpZGVudGlmaWVycywgaywgbGFiZWwsIGxpbmUsIHNlcXMsIF9pLCBfbGVuO1xuICAgIHNlcXMgPSBbXTtcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHRleHQpICE9PSAnW29iamVjdCBBcnJheV0nKSB7XG4gICAgICB0ZXh0ID0gdGV4dC5zcGxpdChcIlxcblwiKTtcbiAgICB9XG4gICAgZm9yIChfaSA9IDAsIF9sZW4gPSB0ZXh0Lmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICBsaW5lID0gdGV4dFtfaV07XG4gICAgICBpZiAobGluZVswXSA9PT0gXCI+XCIgfHwgbGluZVswXSA9PT0gXCI7XCIpIHtcbiAgICAgICAgbGFiZWwgPSBsaW5lLnNsaWNlKDEpO1xuICAgICAgICBjdXJyZW50U2VxID0gbmV3IFNlcShcIlwiLCBsYWJlbCwgc2Vxcy5sZW5ndGgpO1xuICAgICAgICBzZXFzLnB1c2goY3VycmVudFNlcSk7XG4gICAgICAgIGlmIChTdHIuY29udGFpbnMoXCJ8XCIsIGxpbmUpKSB7XG4gICAgICAgICAgaWRlbnRpZmllcnMgPSBsYWJlbC5zcGxpdChcInxcIik7XG4gICAgICAgICAgayA9IDE7XG4gICAgICAgICAgd2hpbGUgKGsgPCBpZGVudGlmaWVycy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGRhdGFiYXNlID0gaWRlbnRpZmllcnNba107XG4gICAgICAgICAgICBkYXRhYmFzZUlEID0gaWRlbnRpZmllcnNbayArIDFdO1xuICAgICAgICAgICAgY3VycmVudFNlcS5tZXRhW2RhdGFiYXNlXSA9IGRhdGFiYXNlSUQ7XG4gICAgICAgICAgICBrICs9IDI7XG4gICAgICAgICAgfVxuICAgICAgICAgIGN1cnJlbnRTZXEubmFtZSA9IGlkZW50aWZpZXJzW2lkZW50aWZpZXJzLmxlbmd0aCAtIDFdO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjdXJyZW50U2VxLnNlcSArPSBsaW5lO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gc2VxcztcbiAgfTtcblxuICByZXR1cm4gRmFzdGE7XG5cbn0pKEdlbmVyaWNSZWFkZXIpO1xuIiwiLy8gR2VuZXJhdGVkIGJ5IENvZmZlZVNjcmlwdCAxLjguMFxudmFyIHN0cmluZ3M7XG5cbnN0cmluZ3MgPSB7XG4gIGNvbnRhaW5zOiBmdW5jdGlvbih0ZXh0LCBzZWFyY2gpIHtcbiAgICByZXR1cm4gJycuaW5kZXhPZi5jYWxsKHRleHQsIHNlYXJjaCwgMCkgIT09IC0xO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0cmluZ3M7XG4iLCIvLyBHZW5lcmF0ZWQgYnkgQ29mZmVlU2NyaXB0IDEuOC4wXG52YXIgVXRpbHM7XG5cblV0aWxzID0ge307XG5cblV0aWxzLnNwbGl0TkNoYXJzID0gZnVuY3Rpb24odHh0LCBudW0pIHtcbiAgdmFyIGksIHJlc3VsdCwgX2ksIF9yZWY7XG4gIHJlc3VsdCA9IFtdO1xuICBmb3IgKGkgPSBfaSA9IDAsIF9yZWYgPSB0eHQubGVuZ3RoIC0gMTsgbnVtID4gMCA/IF9pIDw9IF9yZWYgOiBfaSA+PSBfcmVmOyBpID0gX2kgKz0gbnVtKSB7XG4gICAgcmVzdWx0LnB1c2godHh0LnN1YnN0cihpLCBudW0pKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBVdGlscztcbiIsIi8vIEdlbmVyYXRlZCBieSBDb2ZmZWVTY3JpcHQgMS44LjBcbnZhciBGYXN0YUV4cG9ydGVyLCBVdGlscztcblxuVXRpbHMgPSByZXF1aXJlKFwiLi91dGlsc1wiKTtcblxubW9kdWxlLmV4cG9ydHMgPSBGYXN0YUV4cG9ydGVyID0gKGZ1bmN0aW9uKCkge1xuICBmdW5jdGlvbiBGYXN0YUV4cG9ydGVyKCkge31cblxuICBGYXN0YUV4cG9ydGVyW1wiZXhwb3J0XCJdID0gZnVuY3Rpb24oc2VxcywgYWNjZXNzKSB7XG4gICAgdmFyIHNlcSwgdGV4dCwgX2ksIF9sZW47XG4gICAgdGV4dCA9IFwiXCI7XG4gICAgZm9yIChfaSA9IDAsIF9sZW4gPSBzZXFzLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICBzZXEgPSBzZXFzW19pXTtcbiAgICAgIGlmIChhY2Nlc3MgIT0gbnVsbCkge1xuICAgICAgICBzZXEgPSBhY2Nlc3Moc2VxKTtcbiAgICAgIH1cbiAgICAgIHRleHQgKz0gXCI+XCIgKyBzZXEubmFtZSArIFwiXFxuXCI7XG4gICAgICB0ZXh0ICs9IChVdGlscy5zcGxpdE5DaGFycyhzZXEuc2VxLCA4MCkpLmpvaW4oXCJcXG5cIik7XG4gICAgICB0ZXh0ICs9IFwiXFxuXCI7XG4gICAgfVxuICAgIHJldHVybiB0ZXh0O1xuICB9O1xuXG4gIHJldHVybiBGYXN0YUV4cG9ydGVyO1xuXG59KSgpO1xuIiwibW9kdWxlLmV4cG9ydHMuc2VxID0gcmVxdWlyZShcIi4vc2VxXCIpO1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihzZXEsIG5hbWUsIGlkKSB7XG4gICAgdGhpcy5zZXEgPSBzZXE7XG4gICAgdGhpcy5uYW1lID0gbmFtZTtcbiAgICB0aGlzLmlkID0gaWQ7XG4gICAgdGhpcy5tZXRhID0ge307XG59O1xuIiwidmFyIHJlcSA9IHJlcXVpcmUoJ3JlcXVlc3QnKVxuXG5tb2R1bGUuZXhwb3J0cyA9IE5ldHNcblxuZnVuY3Rpb24gTmV0cyh1cmksIG9wdHMsIGNiKSB7XG4gIHJlcSh1cmksIG9wdHMsIGNiKVxufSIsInZhciB3aW5kb3cgPSByZXF1aXJlKFwiZ2xvYmFsL3dpbmRvd1wiKVxudmFyIG9uY2UgPSByZXF1aXJlKFwib25jZVwiKVxudmFyIHBhcnNlSGVhZGVycyA9IHJlcXVpcmUoJ3BhcnNlLWhlYWRlcnMnKVxuXG52YXIgbWVzc2FnZXMgPSB7XG4gICAgXCIwXCI6IFwiSW50ZXJuYWwgWE1MSHR0cFJlcXVlc3QgRXJyb3JcIixcbiAgICBcIjRcIjogXCI0eHggQ2xpZW50IEVycm9yXCIsXG4gICAgXCI1XCI6IFwiNXh4IFNlcnZlciBFcnJvclwiXG59XG5cbnZhciBYSFIgPSB3aW5kb3cuWE1MSHR0cFJlcXVlc3QgfHwgbm9vcFxudmFyIFhEUiA9IFwid2l0aENyZWRlbnRpYWxzXCIgaW4gKG5ldyBYSFIoKSkgPyBYSFIgOiB3aW5kb3cuWERvbWFpblJlcXVlc3RcblxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVYSFJcblxuZnVuY3Rpb24gY3JlYXRlWEhSKG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG9wdGlvbnMgPSB7IHVyaTogb3B0aW9ucyB9XG4gICAgfVxuXG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge31cbiAgICBjYWxsYmFjayA9IG9uY2UoY2FsbGJhY2spXG5cbiAgICB2YXIgeGhyID0gb3B0aW9ucy54aHIgfHwgbnVsbFxuXG4gICAgaWYgKCF4aHIpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuY29ycyB8fCBvcHRpb25zLnVzZVhEUikge1xuICAgICAgICAgICAgeGhyID0gbmV3IFhEUigpXG4gICAgICAgIH1lbHNle1xuICAgICAgICAgICAgeGhyID0gbmV3IFhIUigpXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgdXJpID0geGhyLnVybCA9IG9wdGlvbnMudXJpIHx8IG9wdGlvbnMudXJsXG4gICAgdmFyIG1ldGhvZCA9IHhoci5tZXRob2QgPSBvcHRpb25zLm1ldGhvZCB8fCBcIkdFVFwiXG4gICAgdmFyIGJvZHkgPSBvcHRpb25zLmJvZHkgfHwgb3B0aW9ucy5kYXRhXG4gICAgdmFyIGhlYWRlcnMgPSB4aHIuaGVhZGVycyA9IG9wdGlvbnMuaGVhZGVycyB8fCB7fVxuICAgIHZhciBzeW5jID0gISFvcHRpb25zLnN5bmNcbiAgICB2YXIgaXNKc29uID0gZmFsc2VcbiAgICB2YXIga2V5XG4gICAgdmFyIGxvYWQgPSBvcHRpb25zLnJlc3BvbnNlID8gbG9hZFJlc3BvbnNlIDogbG9hZFhoclxuXG4gICAgaWYgKFwianNvblwiIGluIG9wdGlvbnMpIHtcbiAgICAgICAgaXNKc29uID0gdHJ1ZVxuICAgICAgICBoZWFkZXJzW1wiQWNjZXB0XCJdID0gXCJhcHBsaWNhdGlvbi9qc29uXCJcbiAgICAgICAgaWYgKG1ldGhvZCAhPT0gXCJHRVRcIiAmJiBtZXRob2QgIT09IFwiSEVBRFwiKSB7XG4gICAgICAgICAgICBoZWFkZXJzW1wiQ29udGVudC1UeXBlXCJdID0gXCJhcHBsaWNhdGlvbi9qc29uXCJcbiAgICAgICAgICAgIGJvZHkgPSBKU09OLnN0cmluZ2lmeShvcHRpb25zLmpzb24pXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB4aHIub25yZWFkeXN0YXRlY2hhbmdlID0gcmVhZHlzdGF0ZWNoYW5nZVxuICAgIHhoci5vbmxvYWQgPSBsb2FkXG4gICAgeGhyLm9uZXJyb3IgPSBlcnJvclxuICAgIC8vIElFOSBtdXN0IGhhdmUgb25wcm9ncmVzcyBiZSBzZXQgdG8gYSB1bmlxdWUgZnVuY3Rpb24uXG4gICAgeGhyLm9ucHJvZ3Jlc3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIElFIG11c3QgZGllXG4gICAgfVxuICAgIC8vIGhhdGUgSUVcbiAgICB4aHIub250aW1lb3V0ID0gbm9vcFxuICAgIHhoci5vcGVuKG1ldGhvZCwgdXJpLCAhc3luYylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vYmFja3dhcmQgY29tcGF0aWJpbGl0eVxuICAgIGlmIChvcHRpb25zLndpdGhDcmVkZW50aWFscyB8fCAob3B0aW9ucy5jb3JzICYmIG9wdGlvbnMud2l0aENyZWRlbnRpYWxzICE9PSBmYWxzZSkpIHtcbiAgICAgICAgeGhyLndpdGhDcmVkZW50aWFscyA9IHRydWVcbiAgICB9XG5cbiAgICAvLyBDYW5ub3Qgc2V0IHRpbWVvdXQgd2l0aCBzeW5jIHJlcXVlc3RcbiAgICBpZiAoIXN5bmMpIHtcbiAgICAgICAgeGhyLnRpbWVvdXQgPSBcInRpbWVvdXRcIiBpbiBvcHRpb25zID8gb3B0aW9ucy50aW1lb3V0IDogNTAwMFxuICAgIH1cblxuICAgIGlmICh4aHIuc2V0UmVxdWVzdEhlYWRlcikge1xuICAgICAgICBmb3Ioa2V5IGluIGhlYWRlcnMpe1xuICAgICAgICAgICAgaWYoaGVhZGVycy5oYXNPd25Qcm9wZXJ0eShrZXkpKXtcbiAgICAgICAgICAgICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcihrZXksIGhlYWRlcnNba2V5XSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0gZWxzZSBpZiAob3B0aW9ucy5oZWFkZXJzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkhlYWRlcnMgY2Fubm90IGJlIHNldCBvbiBhbiBYRG9tYWluUmVxdWVzdCBvYmplY3RcIilcbiAgICB9XG5cbiAgICBpZiAoXCJyZXNwb25zZVR5cGVcIiBpbiBvcHRpb25zKSB7XG4gICAgICAgIHhoci5yZXNwb25zZVR5cGUgPSBvcHRpb25zLnJlc3BvbnNlVHlwZVxuICAgIH1cbiAgICBcbiAgICBpZiAoXCJiZWZvcmVTZW5kXCIgaW4gb3B0aW9ucyAmJiBcbiAgICAgICAgdHlwZW9mIG9wdGlvbnMuYmVmb3JlU2VuZCA9PT0gXCJmdW5jdGlvblwiXG4gICAgKSB7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCh4aHIpXG4gICAgfVxuXG4gICAgeGhyLnNlbmQoYm9keSlcblxuICAgIHJldHVybiB4aHJcblxuICAgIGZ1bmN0aW9uIHJlYWR5c3RhdGVjaGFuZ2UoKSB7XG4gICAgICAgIGlmICh4aHIucmVhZHlTdGF0ZSA9PT0gNCkge1xuICAgICAgICAgICAgbG9hZCgpXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRCb2R5KCkge1xuICAgICAgICAvLyBDaHJvbWUgd2l0aCByZXF1ZXN0VHlwZT1ibG9iIHRocm93cyBlcnJvcnMgYXJyb3VuZCB3aGVuIGV2ZW4gdGVzdGluZyBhY2Nlc3MgdG8gcmVzcG9uc2VUZXh0XG4gICAgICAgIHZhciBib2R5ID0gbnVsbFxuXG4gICAgICAgIGlmICh4aHIucmVzcG9uc2UpIHtcbiAgICAgICAgICAgIGJvZHkgPSB4aHIucmVzcG9uc2VcbiAgICAgICAgfSBlbHNlIGlmICh4aHIucmVzcG9uc2VUeXBlID09PSAndGV4dCcgfHwgIXhoci5yZXNwb25zZVR5cGUpIHtcbiAgICAgICAgICAgIGJvZHkgPSB4aHIucmVzcG9uc2VUZXh0IHx8IHhoci5yZXNwb25zZVhNTFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzSnNvbikge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBib2R5ID0gSlNPTi5wYXJzZShib2R5KVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge31cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBib2R5XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0U3RhdHVzQ29kZSgpIHtcbiAgICAgICAgcmV0dXJuIHhoci5zdGF0dXMgPT09IDEyMjMgPyAyMDQgOiB4aHIuc3RhdHVzXG4gICAgfVxuXG4gICAgLy8gaWYgd2UncmUgZ2V0dGluZyBhIG5vbmUtb2sgc3RhdHVzQ29kZSwgYnVpbGQgJiByZXR1cm4gYW4gZXJyb3JcbiAgICBmdW5jdGlvbiBlcnJvckZyb21TdGF0dXNDb2RlKHN0YXR1cywgYm9keSkge1xuICAgICAgICB2YXIgZXJyb3IgPSBudWxsXG4gICAgICAgIGlmIChzdGF0dXMgPT09IDAgfHwgKHN0YXR1cyA+PSA0MDAgJiYgc3RhdHVzIDwgNjAwKSkge1xuICAgICAgICAgICAgdmFyIG1lc3NhZ2UgPSAodHlwZW9mIGJvZHkgPT09IFwic3RyaW5nXCIgPyBib2R5IDogZmFsc2UpIHx8XG4gICAgICAgICAgICAgICAgbWVzc2FnZXNbU3RyaW5nKHN0YXR1cykuY2hhckF0KDApXVxuICAgICAgICAgICAgZXJyb3IgPSBuZXcgRXJyb3IobWVzc2FnZSlcbiAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGUgPSBzdGF0dXNcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlcnJvclxuICAgIH1cblxuICAgIC8vIHdpbGwgbG9hZCB0aGUgZGF0YSAmIHByb2Nlc3MgdGhlIHJlc3BvbnNlIGluIGEgc3BlY2lhbCByZXNwb25zZSBvYmplY3RcbiAgICBmdW5jdGlvbiBsb2FkUmVzcG9uc2UoKSB7XG4gICAgICAgIHZhciBzdGF0dXMgPSBnZXRTdGF0dXNDb2RlKClcbiAgICAgICAgdmFyIGJvZHkgPSBnZXRCb2R5KClcbiAgICAgICAgdmFyIGVycm9yID0gZXJyb3JGcm9tU3RhdHVzQ29kZShzdGF0dXMsIGJvZHkpXG4gICAgICAgIHZhciByZXNwb25zZSA9IHtcbiAgICAgICAgICAgIGJvZHk6IGJvZHksXG4gICAgICAgICAgICBzdGF0dXNDb2RlOiBzdGF0dXMsXG4gICAgICAgICAgICBzdGF0dXNUZXh0OiB4aHIuc3RhdHVzVGV4dCxcbiAgICAgICAgICAgIHJhdzogeGhyXG4gICAgICAgIH1cbiAgICAgICAgaWYoeGhyLmdldEFsbFJlc3BvbnNlSGVhZGVycyl7IC8vcmVtZW1iZXIgeGhyIGNhbiBpbiBmYWN0IGJlIFhEUiBmb3IgQ09SUyBpbiBJRVxuICAgICAgICAgICAgcmVzcG9uc2UuaGVhZGVycyA9IHBhcnNlSGVhZGVycyh4aHIuZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCkpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNwb25zZS5oZWFkZXJzID0ge31cbiAgICAgICAgfVxuXG4gICAgICAgIGNhbGxiYWNrKGVycm9yLCByZXNwb25zZSwgcmVzcG9uc2UuYm9keSlcbiAgICB9XG5cbiAgICAvLyB3aWxsIGxvYWQgdGhlIGRhdGEgYW5kIGFkZCBzb21lIHJlc3BvbnNlIHByb3BlcnRpZXMgdG8gdGhlIHNvdXJjZSB4aHJcbiAgICAvLyBhbmQgdGhlbiByZXNwb25kIHdpdGggdGhhdFxuICAgIGZ1bmN0aW9uIGxvYWRYaHIoKSB7XG4gICAgICAgIHZhciBzdGF0dXMgPSBnZXRTdGF0dXNDb2RlKClcbiAgICAgICAgdmFyIGVycm9yID0gZXJyb3JGcm9tU3RhdHVzQ29kZShzdGF0dXMpXG5cbiAgICAgICAgeGhyLnN0YXR1cyA9IHhoci5zdGF0dXNDb2RlID0gc3RhdHVzXG4gICAgICAgIHhoci5ib2R5ID0gZ2V0Qm9keSgpXG4gICAgICAgIHhoci5oZWFkZXJzID0gcGFyc2VIZWFkZXJzKHhoci5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSlcblxuICAgICAgICBjYWxsYmFjayhlcnJvciwgeGhyLCB4aHIuYm9keSlcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBlcnJvcihldnQpIHtcbiAgICAgICAgY2FsbGJhY2soZXZ0LCB4aHIpXG4gICAgfVxufVxuXG5cbmZ1bmN0aW9uIG5vb3AoKSB7fVxuIiwiaWYgKHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHdpbmRvdztcbn0gZWxzZSBpZiAodHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZ2xvYmFsO1xufSBlbHNlIGlmICh0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIil7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBzZWxmO1xufSBlbHNlIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHt9O1xufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBvbmNlXG5cbm9uY2UucHJvdG8gPSBvbmNlKGZ1bmN0aW9uICgpIHtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEZ1bmN0aW9uLnByb3RvdHlwZSwgJ29uY2UnLCB7XG4gICAgdmFsdWU6IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBvbmNlKHRoaXMpXG4gICAgfSxcbiAgICBjb25maWd1cmFibGU6IHRydWVcbiAgfSlcbn0pXG5cbmZ1bmN0aW9uIG9uY2UgKGZuKSB7XG4gIHZhciBjYWxsZWQgPSBmYWxzZVxuICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgIGlmIChjYWxsZWQpIHJldHVyblxuICAgIGNhbGxlZCA9IHRydWVcbiAgICByZXR1cm4gZm4uYXBwbHkodGhpcywgYXJndW1lbnRzKVxuICB9XG59XG4iLCJ2YXIgaXNGdW5jdGlvbiA9IHJlcXVpcmUoJ2lzLWZ1bmN0aW9uJylcblxubW9kdWxlLmV4cG9ydHMgPSBmb3JFYWNoXG5cbnZhciB0b1N0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmdcbnZhciBoYXNPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHlcblxuZnVuY3Rpb24gZm9yRWFjaChsaXN0LCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIGlmICghaXNGdW5jdGlvbihpdGVyYXRvcikpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignaXRlcmF0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uJylcbiAgICB9XG5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA8IDMpIHtcbiAgICAgICAgY29udGV4dCA9IHRoaXNcbiAgICB9XG4gICAgXG4gICAgaWYgKHRvU3RyaW5nLmNhbGwobGlzdCkgPT09ICdbb2JqZWN0IEFycmF5XScpXG4gICAgICAgIGZvckVhY2hBcnJheShsaXN0LCBpdGVyYXRvciwgY29udGV4dClcbiAgICBlbHNlIGlmICh0eXBlb2YgbGlzdCA9PT0gJ3N0cmluZycpXG4gICAgICAgIGZvckVhY2hTdHJpbmcobGlzdCwgaXRlcmF0b3IsIGNvbnRleHQpXG4gICAgZWxzZVxuICAgICAgICBmb3JFYWNoT2JqZWN0KGxpc3QsIGl0ZXJhdG9yLCBjb250ZXh0KVxufVxuXG5mdW5jdGlvbiBmb3JFYWNoQXJyYXkoYXJyYXksIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGFycmF5Lmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKGFycmF5LCBpKSkge1xuICAgICAgICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBhcnJheVtpXSwgaSwgYXJyYXkpXG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIGZvckVhY2hTdHJpbmcoc3RyaW5nLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBzdHJpbmcubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgLy8gbm8gc3VjaCB0aGluZyBhcyBhIHNwYXJzZSBzdHJpbmcuXG4gICAgICAgIGl0ZXJhdG9yLmNhbGwoY29udGV4dCwgc3RyaW5nLmNoYXJBdChpKSwgaSwgc3RyaW5nKVxuICAgIH1cbn1cblxuZnVuY3Rpb24gZm9yRWFjaE9iamVjdChvYmplY3QsIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgZm9yICh2YXIgayBpbiBvYmplY3QpIHtcbiAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBrKSkge1xuICAgICAgICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmplY3Rba10sIGssIG9iamVjdClcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gaXNGdW5jdGlvblxuXG52YXIgdG9TdHJpbmcgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nXG5cbmZ1bmN0aW9uIGlzRnVuY3Rpb24gKGZuKSB7XG4gIHZhciBzdHJpbmcgPSB0b1N0cmluZy5jYWxsKGZuKVxuICByZXR1cm4gc3RyaW5nID09PSAnW29iamVjdCBGdW5jdGlvbl0nIHx8XG4gICAgKHR5cGVvZiBmbiA9PT0gJ2Z1bmN0aW9uJyAmJiBzdHJpbmcgIT09ICdbb2JqZWN0IFJlZ0V4cF0nKSB8fFxuICAgICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAvLyBJRTggYW5kIGJlbG93XG4gICAgIChmbiA9PT0gd2luZG93LnNldFRpbWVvdXQgfHxcbiAgICAgIGZuID09PSB3aW5kb3cuYWxlcnQgfHxcbiAgICAgIGZuID09PSB3aW5kb3cuY29uZmlybSB8fFxuICAgICAgZm4gPT09IHdpbmRvdy5wcm9tcHQpKVxufTtcbiIsIlxuZXhwb3J0cyA9IG1vZHVsZS5leHBvcnRzID0gdHJpbTtcblxuZnVuY3Rpb24gdHJpbShzdHIpe1xuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMqfFxccyokL2csICcnKTtcbn1cblxuZXhwb3J0cy5sZWZ0ID0gZnVuY3Rpb24oc3RyKXtcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC9eXFxzKi8sICcnKTtcbn07XG5cbmV4cG9ydHMucmlnaHQgPSBmdW5jdGlvbihzdHIpe1xuICByZXR1cm4gc3RyLnJlcGxhY2UoL1xccyokLywgJycpO1xufTtcbiIsInZhciB0cmltID0gcmVxdWlyZSgndHJpbScpXG4gICwgZm9yRWFjaCA9IHJlcXVpcmUoJ2Zvci1lYWNoJylcbiAgLCBpc0FycmF5ID0gZnVuY3Rpb24oYXJnKSB7XG4gICAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGFyZykgPT09ICdbb2JqZWN0IEFycmF5XSc7XG4gICAgfVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChoZWFkZXJzKSB7XG4gIGlmICghaGVhZGVycylcbiAgICByZXR1cm4ge31cblxuICB2YXIgcmVzdWx0ID0ge31cblxuICBmb3JFYWNoKFxuICAgICAgdHJpbShoZWFkZXJzKS5zcGxpdCgnXFxuJylcbiAgICAsIGZ1bmN0aW9uIChyb3cpIHtcbiAgICAgICAgdmFyIGluZGV4ID0gcm93LmluZGV4T2YoJzonKVxuICAgICAgICAgICwga2V5ID0gdHJpbShyb3cuc2xpY2UoMCwgaW5kZXgpKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgICAgLCB2YWx1ZSA9IHRyaW0ocm93LnNsaWNlKGluZGV4ICsgMSkpXG5cbiAgICAgICAgaWYgKHR5cGVvZihyZXN1bHRba2V5XSkgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZVxuICAgICAgICB9IGVsc2UgaWYgKGlzQXJyYXkocmVzdWx0W2tleV0pKSB7XG4gICAgICAgICAgcmVzdWx0W2tleV0ucHVzaCh2YWx1ZSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXN1bHRba2V5XSA9IFsgcmVzdWx0W2tleV0sIHZhbHVlIF1cbiAgICAgICAgfVxuICAgICAgfVxuICApXG5cbiAgcmV0dXJuIHJlc3VsdFxufSIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9qcXVlcnkuYnJvd3NlcicpO1xuIiwiLyohXG4gKiBqUXVlcnkgQnJvd3NlciBQbHVnaW4gdjAuMC42XG4gKiBodHRwczovL2dpdGh1Yi5jb20vZ2FiY2ViL2pxdWVyeS1icm93c2VyLXBsdWdpblxuICpcbiAqIE9yaWdpbmFsIGpxdWVyeS1icm93c2VyIGNvZGUgQ29weXJpZ2h0IDIwMDUsIDIwMTMgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICpcbiAqIE1vZGlmaWNhdGlvbnMgQ29weXJpZ2h0IDIwMTMgR2FicmllbCBDZWJyaWFuXG4gKiBodHRwczovL2dpdGh1Yi5jb20vZ2FiY2ViXG4gKlxuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlXG4gKlxuICogRGF0ZTogMjAxMy0wNy0yOVQxNzoyMzoyNy0wNzowMFxuICovXG5cblxudmFyIG1hdGNoZWQsIGJyb3dzZXI7XG5cbnZhciB1YU1hdGNoID0gZnVuY3Rpb24oIHVhICkge1xuICB1YSA9IHVhLnRvTG93ZXJDYXNlKCk7XG5cbiAgdmFyIG1hdGNoID0gLyhvcHIpW1xcL10oW1xcdy5dKykvLmV4ZWMoIHVhICkgfHxcbiAgICAvKGNocm9tZSlbIFxcL10oW1xcdy5dKykvLmV4ZWMoIHVhICkgfHxcbiAgICAvKHZlcnNpb24pWyBcXC9dKFtcXHcuXSspLiooc2FmYXJpKVsgXFwvXShbXFx3Ll0rKS8uZXhlYyggdWEgKSB8fFxuICAgIC8od2Via2l0KVsgXFwvXShbXFx3Ll0rKS8uZXhlYyggdWEgKSB8fFxuICAgIC8ob3BlcmEpKD86Lip2ZXJzaW9ufClbIFxcL10oW1xcdy5dKykvLmV4ZWMoIHVhICkgfHxcbiAgICAvKG1zaWUpIChbXFx3Ll0rKS8uZXhlYyggdWEgKSB8fFxuICAgIHVhLmluZGV4T2YoXCJ0cmlkZW50XCIpID49IDAgJiYgLyhydikoPzo6fCApKFtcXHcuXSspLy5leGVjKCB1YSApIHx8XG4gICAgdWEuaW5kZXhPZihcImNvbXBhdGlibGVcIikgPCAwICYmIC8obW96aWxsYSkoPzouKj8gcnY6KFtcXHcuXSspfCkvLmV4ZWMoIHVhICkgfHxcbiAgICBbXTtcblxuICB2YXIgcGxhdGZvcm1fbWF0Y2ggPSAvKGlwYWQpLy5leGVjKCB1YSApIHx8XG4gICAgLyhpcGhvbmUpLy5leGVjKCB1YSApIHx8XG4gICAgLyhhbmRyb2lkKS8uZXhlYyggdWEgKSB8fFxuICAgIC8od2luZG93cyBwaG9uZSkvLmV4ZWMoIHVhICkgfHxcbiAgICAvKHdpbikvLmV4ZWMoIHVhICkgfHxcbiAgICAvKG1hYykvLmV4ZWMoIHVhICkgfHxcbiAgICAvKGxpbnV4KS8uZXhlYyggdWEgKSB8fFxuICAgIC8oY3JvcykvaS5leGVjKCB1YSApIHx8XG4gICAgW107XG5cbiAgcmV0dXJuIHtcbiAgICBicm93c2VyOiBtYXRjaFsgMyBdIHx8IG1hdGNoWyAxIF0gfHwgXCJcIixcbiAgICB2ZXJzaW9uOiBtYXRjaFsgMiBdIHx8IFwiMFwiLFxuICAgIHBsYXRmb3JtOiBwbGF0Zm9ybV9tYXRjaFsgMCBdIHx8IFwiXCJcbiAgfTtcbn07XG5cbm1hdGNoZWQgPSB1YU1hdGNoKCB3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudCApO1xuYnJvd3NlciA9IHt9O1xuYnJvd3Nlci51YU1hdGNoID0gdWFNYXRjaDtcblxuaWYgKCBtYXRjaGVkLmJyb3dzZXIgKSB7XG4gIGJyb3dzZXJbIG1hdGNoZWQuYnJvd3NlciBdID0gdHJ1ZTtcbiAgYnJvd3Nlci52ZXJzaW9uID0gbWF0Y2hlZC52ZXJzaW9uO1xuICBicm93c2VyLnZlcnNpb25OdW1iZXIgPSBwYXJzZUludChtYXRjaGVkLnZlcnNpb24pO1xufVxuXG5pZiAoIG1hdGNoZWQucGxhdGZvcm0gKSB7XG4gIGJyb3dzZXJbIG1hdGNoZWQucGxhdGZvcm0gXSA9IHRydWU7XG59XG5cbi8vIFRoZXNlIGFyZSBhbGwgY29uc2lkZXJlZCBtb2JpbGUgcGxhdGZvcm1zLCBtZWFuaW5nIHRoZXkgcnVuIGEgbW9iaWxlIGJyb3dzZXJcbmlmICggYnJvd3Nlci5hbmRyb2lkIHx8IGJyb3dzZXIuaXBhZCB8fCBicm93c2VyLmlwaG9uZSB8fCBicm93c2VyWyBcIndpbmRvd3MgcGhvbmVcIiBdICkge1xuICBicm93c2VyLm1vYmlsZSA9IHRydWU7XG59XG5cbi8vIFRoZXNlIGFyZSBhbGwgY29uc2lkZXJlZCBkZXNrdG9wIHBsYXRmb3JtcywgbWVhbmluZyB0aGV5IHJ1biBhIGRlc2t0b3AgYnJvd3NlclxuaWYgKCBicm93c2VyLmNyb3MgfHwgYnJvd3Nlci5tYWMgfHwgYnJvd3Nlci5saW51eCB8fCBicm93c2VyLndpbiApIHtcbiAgYnJvd3Nlci5kZXNrdG9wID0gdHJ1ZTtcbn1cblxuLy8gQ2hyb21lLCBPcGVyYSAxNSsgYW5kIFNhZmFyaSBhcmUgd2Via2l0IGJhc2VkIGJyb3dzZXJzXG5pZiAoIGJyb3dzZXIuY2hyb21lIHx8IGJyb3dzZXIub3ByIHx8IGJyb3dzZXIuc2FmYXJpICkge1xuICBicm93c2VyLndlYmtpdCA9IHRydWU7XG59XG5cbi8vIElFMTEgaGFzIGEgbmV3IHRva2VuIHNvIHdlIHdpbGwgYXNzaWduIGl0IG1zaWUgdG8gYXZvaWQgYnJlYWtpbmcgY2hhbmdlc1xuaWYgKCBicm93c2VyLnJ2IClcbntcbiAgdmFyIGllID0gXCJtc2llXCI7XG5cbiAgbWF0Y2hlZC5icm93c2VyID0gaWU7XG4gIGJyb3dzZXJbaWVdID0gdHJ1ZTtcbn1cblxuLy8gT3BlcmEgMTUrIGFyZSBpZGVudGlmaWVkIGFzIG9wclxuaWYgKCBicm93c2VyLm9wciApXG57XG4gIHZhciBvcGVyYSA9IFwib3BlcmFcIjtcblxuICBtYXRjaGVkLmJyb3dzZXIgPSBvcGVyYTtcbiAgYnJvd3NlcltvcGVyYV0gPSB0cnVlO1xufVxuXG4vLyBTdG9jayBBbmRyb2lkIGJyb3dzZXJzIGFyZSBtYXJrZWQgYXMgU2FmYXJpIG9uIEFuZHJvaWQuXG5pZiAoIGJyb3dzZXIuc2FmYXJpICYmIGJyb3dzZXIuYW5kcm9pZCApXG57XG4gIHZhciBhbmRyb2lkID0gXCJhbmRyb2lkXCI7XG5cbiAgbWF0Y2hlZC5icm93c2VyID0gYW5kcm9pZDtcbiAgYnJvd3NlclthbmRyb2lkXSA9IHRydWU7XG59XG5cbi8vIEFzc2lnbiB0aGUgbmFtZSBhbmQgcGxhdGZvcm0gdmFyaWFibGVcbmJyb3dzZXIubmFtZSA9IG1hdGNoZWQuYnJvd3NlcjtcbmJyb3dzZXIucGxhdGZvcm0gPSBtYXRjaGVkLnBsYXRmb3JtO1xuXG5cbm1vZHVsZS5leHBvcnRzID0gYnJvd3NlcjtcbiIsIi8qKiBAcHJlc2VydmUgaHR0cDovL2dpdGh1Yi5jb20vZWFzZXdheS9qcy1jbGFzcyAqL1xuXG4vLyBDbGFzcyBEZWZpbml0aW9uIHVzaW5nIEVDTUE1IHByb3RvdHlwZSBjaGFpblxuXG5mdW5jdGlvbiBpbmhlcml0KGRlc3QsIHNyYywgbm9QYXJlbnQpIHtcbiAgICB3aGlsZSAoc3JjICYmIHNyYyAhPT0gT2JqZWN0LnByb3RvdHlwZSkge1xuICAgICAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhzcmMpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgIGlmIChuYW1lICE9ICcuY2xhc3MnICYmICFkZXN0Lmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHNyYywgbmFtZSk7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGRlc3QsIG5hbWUsIGRlc2MpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKG5vUGFyZW50KSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBzcmMgPSBzcmMuX19wcm90b19fO1xuICAgIH1cbiAgICByZXR1cm4gZGVzdDtcbn1cblxudmFyIENsYXNzID0gZnVuY3Rpb24gKGJhc2UsIHByb3RvLCBvcHRpb25zKSB7XG4gICAgaWYgKHR5cGVvZihiYXNlKSAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIG9wdGlvbnMgPSBwcm90bztcbiAgICAgICAgcHJvdG8gPSBiYXNlO1xuICAgICAgICBiYXNlID0gT2JqZWN0O1xuICAgIH1cbiAgICBpZiAoIXByb3RvKSB7XG4gICAgICAgIHByb3RvID0ge307XG4gICAgfVxuICAgIGlmICghb3B0aW9ucykge1xuICAgICAgICBvcHRpb25zID0ge307XG4gICAgfVxuICAgIFxuICAgIHZhciBtZXRhID0ge1xuICAgICAgICBuYW1lOiBvcHRpb25zLm5hbWUsXG4gICAgICAgIGJhc2U6IGJhc2UsXG4gICAgICAgIGltcGxlbWVudHM6IFtdXG4gICAgfVxuICAgIHZhciBjbGFzc1Byb3RvID0gQ2xhc3MuY2xvbmUocHJvdG8pO1xuICAgIGlmIChvcHRpb25zLmltcGxlbWVudHMpIHtcbiAgICAgICAgKEFycmF5LmlzQXJyYXkob3B0aW9ucy5pbXBsZW1lbnRzKSA/IG9wdGlvbnMuaW1wbGVtZW50cyA6IFtvcHRpb25zLmltcGxlbWVudHNdKVxuICAgICAgICAgICAgLmZvckVhY2goZnVuY3Rpb24gKGltcGxlbWVudGVkVHlwZSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YoaW1wbGVtZW50ZWRUeXBlKSA9PSAnZnVuY3Rpb24nICYmIGltcGxlbWVudGVkVHlwZS5wcm90b3R5cGUpIHtcbiAgICAgICAgICAgICAgICAgICAgbWV0YS5pbXBsZW1lbnRzLnB1c2goaW1wbGVtZW50ZWRUeXBlKTtcbiAgICAgICAgICAgICAgICAgICAgQ2xhc3MuZXh0ZW5kKGNsYXNzUHJvdG8sIGltcGxlbWVudGVkVHlwZS5wcm90b3R5cGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgIH1cbiAgICBjbGFzc1Byb3RvLl9fcHJvdG9fXyA9IGJhc2UucHJvdG90eXBlO1xuICAgIHZhciB0aGVDbGFzcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHR5cGVvZih0aGlzLmNvbnN0cnVjdG9yKSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIG1ldGEudHlwZSA9IHRoZUNsYXNzO1xuICAgIHRoZUNsYXNzLnByb3RvdHlwZSA9IGNsYXNzUHJvdG87XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoZUNsYXNzLCAnLmNsYXNzLm1ldGEnLCB7IHZhbHVlOiBtZXRhLCBlbnVtZXJhYmxlOiBmYWxzZSwgY29uZmlndXJhYmxlOiBmYWxzZSwgd3JpdGFibGU6IGZhbHNlIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjbGFzc1Byb3RvLCAnLmNsYXNzJywgeyB2YWx1ZTogdGhlQ2xhc3MsIGVudW1lcmFibGU6IGZhbHNlLCBjb25maWd1cmFibGU6IGZhbHNlLCB3cml0YWJsZTogZmFsc2UgfSk7XG4gICAgaWYgKG9wdGlvbnMuc3RhdGljcykge1xuICAgICAgICBDbGFzcy5leHRlbmQodGhlQ2xhc3MsIG9wdGlvbnMuc3RhdGljcyk7XG4gICAgfVxuICAgIHJldHVybiB0aGVDbGFzcztcbn07XG5cbkNsYXNzLmV4dGVuZCA9IGluaGVyaXQ7XG5cbkNsYXNzLmNsb25lID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIHJldHVybiBpbmhlcml0KHt9LCBvYmplY3QpO1xufTtcblxuZnVuY3Rpb24gZmluZFR5cGUobWV0YSwgdHlwZSkge1xuICAgIHdoaWxlIChtZXRhKSB7XG4gICAgICAgIGlmIChtZXRhLnR5cGUucHJvdG90eXBlID09PSB0eXBlLnByb3RvdHlwZSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZm9yICh2YXIgaSBpbiBtZXRhLmltcGxlbWVudHMpIHtcbiAgICAgICAgICAgIHZhciBpbXBsVHlwZSA9IG1ldGEuaW1wbGVtZW50c1tpXTtcbiAgICAgICAgICAgIHZhciBpbXBsTWV0YSA9IGltcGxUeXBlWycuY2xhc3MubWV0YSddO1xuICAgICAgICAgICAgaWYgKGltcGxNZXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKGZpbmRUeXBlKGltcGxNZXRhLCB0eXBlKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIHByb3RvID0gaW1wbFR5cGUucHJvdG90eXBlOyBwcm90bzsgcHJvdG8gPSBwcm90by5fX3Byb3RvX18pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHByb3RvID09PSB0eXBlLnByb3RvdHlwZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbWV0YSA9IG1ldGEuYmFzZSA/IG1ldGEuYmFzZVsnLmNsYXNzLm1ldGEnXSA6IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuXG52YXIgQ2hlY2tlciA9IENsYXNzKHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9iamVjdCkge1xuICAgICAgICB0aGlzLm9iamVjdCA9IG9iamVjdDtcbiAgICB9LFxuICAgIFxuICAgIHR5cGVPZjogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgaWYgKHRoaXMub2JqZWN0IGluc3RhbmNlb2YgdHlwZSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIG1ldGEgPSBDbGFzcy50eXBlSW5mbyh0aGlzLm9iamVjdCk7XG4gICAgICAgIHJldHVybiBtZXRhICYmIGZpbmRUeXBlKG1ldGEsIHR5cGUpO1xuICAgIH1cbn0pO1xuXG4vLyBhbGlhc2VzXG5DaGVja2VyLnByb3RvdHlwZS5hID0gQ2hlY2tlci5wcm90b3R5cGUudHlwZU9mO1xuQ2hlY2tlci5wcm90b3R5cGUuYW4gPSBDaGVja2VyLnByb3RvdHlwZS50eXBlT2Y7XG5cbkNsYXNzLmlzID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIHJldHVybiBuZXcgQ2hlY2tlcihvYmplY3QpO1xufTtcblxuQ2xhc3MudHlwZUluZm8gPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgdmFyIHRoZUNsYXNzID0gb2JqZWN0Ll9fcHJvdG9fX1snLmNsYXNzJ107XG4gICAgcmV0dXJuIHRoZUNsYXNzID8gdGhlQ2xhc3NbJy5jbGFzcy5tZXRhJ10gOiB1bmRlZmluZWQ7XG59O1xuXG5DbGFzcy5WRVJTSU9OID0gWzAsIDAsIDJdO1xuXG5pZiAobW9kdWxlKSB7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBDbGFzcztcbn0gZWxzZSB7XG4gICAgZ2xvYmFsLkNsYXNzID0gQ2xhc3M7ICAgLy8gZm9yIGJyb3dzZXJcbn0iLCIvLyBHZW5lcmF0ZWQgYnkgQ29mZmVlU2NyaXB0IDEuOC4wXG5tb2R1bGUuZXhwb3J0cy5wYXJzZSA9IHJlcXVpcmUoXCIuL3BhcnNlclwiKTtcblxubW9kdWxlLmV4cG9ydHMud3JpdGVyID0gcmVxdWlyZShcIi4vd3JpdGVyXCIpO1xuIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiLi9saWIvaW5kZXhcIik7XG4iXX0=
|