wiki 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/wiki.rb +2 -0
- data/lib/wiki/ReadMe.md +89 -0
- data/lib/wiki/config.ru +2 -0
- data/lib/wiki/favicon.rb +31 -0
- data/lib/wiki/page.rb +74 -0
- data/lib/wiki/random_id.rb +5 -0
- data/lib/wiki/server.rb +336 -0
- data/lib/wiki/server_helpers.rb +66 -0
- data/lib/wiki/stores/ReadMe.md +26 -0
- data/lib/wiki/stores/all.rb +3 -0
- data/lib/wiki/stores/couch.rb +121 -0
- data/lib/wiki/stores/file.rb +53 -0
- data/lib/wiki/stores/store.rb +38 -0
- data/lib/wiki/version.rb +3 -0
- data/lib/wiki/views/client/Gruntfile.js +50 -0
- data/lib/wiki/views/client/ReadMe.md +67 -0
- data/lib/wiki/views/client/build-test.bat +10 -0
- data/lib/wiki/views/client/build.bat +8 -0
- data/lib/wiki/views/client/builder.pl +41 -0
- data/lib/wiki/views/client/client.coffee +3 -0
- data/lib/wiki/views/client/client.js +3607 -0
- data/lib/wiki/views/client/crosses.png +0 -0
- data/lib/wiki/views/client/images/external-link-ltr-icon.png +0 -0
- data/lib/wiki/views/client/images/noise.png +0 -0
- data/lib/wiki/views/client/images/oops.jpg +0 -0
- data/lib/wiki/views/client/js/d3/d3.behavior.js +198 -0
- data/lib/wiki/views/client/js/d3/d3.chart.js +984 -0
- data/lib/wiki/views/client/js/d3/d3.csv.js +92 -0
- data/lib/wiki/views/client/js/d3/d3.geo.js +566 -0
- data/lib/wiki/views/client/js/d3/d3.geom.js +825 -0
- data/lib/wiki/views/client/js/d3/d3.js +3597 -0
- data/lib/wiki/views/client/js/d3/d3.layout.js +1923 -0
- data/lib/wiki/views/client/js/d3/d3.time.js +660 -0
- data/lib/wiki/views/client/js/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/wiki/views/client/js/images/ui-icons_222222_256x240.png +0 -0
- data/lib/wiki/views/client/js/jquery-1.6.2.min.js +18 -0
- data/lib/wiki/views/client/js/jquery-1.7.1.min.js +4 -0
- data/lib/wiki/views/client/js/jquery-1.9.1.min.js +5 -0
- data/lib/wiki/views/client/js/jquery-migrate-1.1.1.min.js +3 -0
- data/lib/wiki/views/client/js/jquery-ui-1.10.1.custom.min.css +5 -0
- data/lib/wiki/views/client/js/jquery-ui-1.10.1.custom.min.js +6 -0
- data/lib/wiki/views/client/js/jquery-ui-1.8.16.custom.css +339 -0
- data/lib/wiki/views/client/js/jquery-ui-1.8.16.custom.min.js +315 -0
- data/lib/wiki/views/client/js/jquery.ie.cors.js +310 -0
- data/lib/wiki/views/client/js/jquery.ui.touch-punch.min.js +11 -0
- data/lib/wiki/views/client/js/modernizr.custom.63710.js +824 -0
- data/lib/wiki/views/client/js/sockjs-0.3.min.js +27 -0
- data/lib/wiki/views/client/js/underscore-min.js +30 -0
- data/lib/wiki/views/client/mkplugin.sh +97 -0
- data/lib/wiki/views/client/package.json +36 -0
- data/lib/wiki/views/client/runtests.html +26 -0
- data/lib/wiki/views/client/style.css +339 -0
- data/lib/wiki/views/client/test/mocha.css +231 -0
- data/lib/wiki/views/client/test/mocha.js +5340 -0
- data/lib/wiki/views/client/test/testclient.js +17133 -0
- data/lib/wiki/views/client/testclient.coffee +18 -0
- data/lib/wiki/views/client/theme/granite.css +59 -0
- data/lib/wiki/views/client/theme/stoneSeamless.jpg +0 -0
- data/lib/wiki/views/client/twitter-maintainance.jpg +0 -0
- data/lib/wiki/views/layout.haml +56 -0
- data/lib/wiki/views/oops.haml +5 -0
- data/lib/wiki/views/page.haml +20 -0
- data/lib/wiki/views/static.html +30 -0
- data/lib/wiki/views/view.haml +2 -0
- data/wiki.gemspec +28 -0
- metadata +121 -0
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            #!/usr/bin/perl
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #this script exists because the browserify -w option does not appear to work?
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            my ($old, $new);
         | 
| 6 | 
            +
            my $OSXsay = ($^O eq 'darwin');
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            sub say {
         | 
| 9 | 
            +
                my $msg = shift;
         | 
| 10 | 
            +
                if ($OSXsay) {
         | 
| 11 | 
            +
                    `say $msg&`;
         | 
| 12 | 
            +
                }
         | 
| 13 | 
            +
                print $msg."\n";
         | 
| 14 | 
            +
            }
         | 
| 15 | 
            +
            sub run {
         | 
| 16 | 
            +
              $trouble = `($_[0] || echo 'failed to run') 2>&1`;
         | 
| 17 | 
            +
              return unless $trouble;
         | 
| 18 | 
            +
              if ($trouble =~ /( on line \d+)/) {
         | 
| 19 | 
            +
                say("having trouble $1.");
         | 
| 20 | 
            +
                print "\n$_[0]\n$trouble";
         | 
| 21 | 
            +
              }elsif ($trouble =~ /failed to run/) {
         | 
| 22 | 
            +
                say('failed to run');
         | 
| 23 | 
            +
                print("\n$_[0]\n$trouble");
         | 
| 24 | 
            +
              }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            while (sleep 1) {
         | 
| 29 | 
            +
              $new = `ls -lt *.coffee lib/*.coffee test/*.coffee plugins/*/*.coffee`;
         | 
| 30 | 
            +
              next if $old eq $new;
         | 
| 31 | 
            +
              $old = $new;
         | 
| 32 | 
            +
              print `clear; date`;
         | 
| 33 | 
            +
              say('client.');
         | 
| 34 | 
            +
              run('./node_modules/.bin/browserify -t coffeeify client.coffee --debug > client.js');
         | 
| 35 | 
            +
              say('test.');
         | 
| 36 | 
            +
              run('./node_modules/.bin/browserify -t coffeeify testclient.coffee ./plugins/*/test.coffee --debug > test/testclient.js');
         | 
| 37 | 
            +
              say('plugins.');
         | 
| 38 | 
            +
              run('./node_modules/.bin/coffee -c ./plugins/*.coffee');
         | 
| 39 | 
            +
              run('./node_modules/.bin/coffee -c ./plugins/*/*.coffee');
         | 
| 40 | 
            +
              say('done.');
         | 
| 41 | 
            +
            }
         | 
| @@ -0,0 +1,3607 @@ | |
| 1 | 
            +
            ;(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
         | 
| 2 | 
            +
            window.wiki = require('wiki-client/lib/wiki');
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require('wiki-client/lib/legacy');
         | 
| 5 | 
            +
             | 
| 6 | 
            +
             | 
| 7 | 
            +
            },{"wiki-client/lib/legacy":3,"wiki-client/lib/wiki":2}],2:[function(require,module,exports){
         | 
| 8 | 
            +
            (function() {
         | 
| 9 | 
            +
              var createSynopsis, wiki,
         | 
| 10 | 
            +
                __slice = [].slice;
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              createSynopsis = require('./synopsis');
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              wiki = {
         | 
| 15 | 
            +
                createSynopsis: createSynopsis
         | 
| 16 | 
            +
              };
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              wiki.persona = require('./persona');
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              wiki.log = function() {
         | 
| 21 | 
            +
                var things;
         | 
| 22 | 
            +
                things = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
         | 
| 23 | 
            +
                if ((typeof console !== "undefined" && console !== null ? console.log : void 0) != null) {
         | 
| 24 | 
            +
                  return console.log.apply(console, things);
         | 
| 25 | 
            +
                }
         | 
| 26 | 
            +
              };
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              wiki.asSlug = function(name) {
         | 
| 29 | 
            +
                return name.replace(/\s/g, '-').replace(/[^A-Za-z0-9-]/g, '').toLowerCase();
         | 
| 30 | 
            +
              };
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              wiki.useLocalStorage = function() {
         | 
| 33 | 
            +
                return $(".login").length > 0;
         | 
| 34 | 
            +
              };
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              wiki.resolutionContext = [];
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              wiki.resolveFrom = function(addition, callback) {
         | 
| 39 | 
            +
                wiki.resolutionContext.push(addition);
         | 
| 40 | 
            +
                try {
         | 
| 41 | 
            +
                  return callback();
         | 
| 42 | 
            +
                } finally {
         | 
| 43 | 
            +
                  wiki.resolutionContext.pop();
         | 
| 44 | 
            +
                }
         | 
| 45 | 
            +
              };
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              wiki.getData = function(vis) {
         | 
| 48 | 
            +
                var idx, who;
         | 
| 49 | 
            +
                if (vis) {
         | 
| 50 | 
            +
                  idx = $('.item').index(vis);
         | 
| 51 | 
            +
                  who = $(".item:lt(" + idx + ")").filter('.chart,.data,.calculator').last();
         | 
| 52 | 
            +
                  if (who != null) {
         | 
| 53 | 
            +
                    return who.data('item').data;
         | 
| 54 | 
            +
                  } else {
         | 
| 55 | 
            +
                    return {};
         | 
| 56 | 
            +
                  }
         | 
| 57 | 
            +
                } else {
         | 
| 58 | 
            +
                  who = $('.chart,.data,.calculator').last();
         | 
| 59 | 
            +
                  if (who != null) {
         | 
| 60 | 
            +
                    return who.data('item').data;
         | 
| 61 | 
            +
                  } else {
         | 
| 62 | 
            +
                    return {};
         | 
| 63 | 
            +
                  }
         | 
| 64 | 
            +
                }
         | 
| 65 | 
            +
              };
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              wiki.getDataNodes = function(vis) {
         | 
| 68 | 
            +
                var idx, who;
         | 
| 69 | 
            +
                if (vis) {
         | 
| 70 | 
            +
                  idx = $('.item').index(vis);
         | 
| 71 | 
            +
                  who = $(".item:lt(" + idx + ")").filter('.chart,.data,.calculator').toArray().reverse();
         | 
| 72 | 
            +
                  return $(who);
         | 
| 73 | 
            +
                } else {
         | 
| 74 | 
            +
                  who = $('.chart,.data,.calculator').toArray().reverse();
         | 
| 75 | 
            +
                  return $(who);
         | 
| 76 | 
            +
                }
         | 
| 77 | 
            +
              };
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              wiki.createPage = function(name, loc) {
         | 
| 80 | 
            +
                var $page, site;
         | 
| 81 | 
            +
                if (loc && loc !== 'view') {
         | 
| 82 | 
            +
                  site = loc;
         | 
| 83 | 
            +
                }
         | 
| 84 | 
            +
                $page = $("<div class=\"page\" id=\"" + name + "\">\n  <div class=\"twins\"> <p> </p> </div>\n  <div class=\"header\">\n    <h1> <img class=\"favicon\" src=\"" + (site ? "//" + site : "") + "/favicon.png\" height=\"32px\"> " + name + " </h1>\n  </div>\n</div>");
         | 
| 85 | 
            +
                if (site) {
         | 
| 86 | 
            +
                  $page.data('site', site);
         | 
| 87 | 
            +
                }
         | 
| 88 | 
            +
                return $page;
         | 
| 89 | 
            +
              };
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              wiki.getItem = function(element) {
         | 
| 92 | 
            +
                if ($(element).length > 0) {
         | 
| 93 | 
            +
                  return $(element).data("item") || $(element).data('staticItem');
         | 
| 94 | 
            +
                }
         | 
| 95 | 
            +
              };
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              wiki.resolveLinks = function(string) {
         | 
| 98 | 
            +
                var renderInternalLink;
         | 
| 99 | 
            +
                renderInternalLink = function(match, name) {
         | 
| 100 | 
            +
                  var slug;
         | 
| 101 | 
            +
                  slug = wiki.asSlug(name);
         | 
| 102 | 
            +
                  return "<a class=\"internal\" href=\"/" + slug + ".html\" data-page-name=\"" + slug + "\" title=\"" + (wiki.resolutionContext.join(' => ')) + "\">" + name + "</a>";
         | 
| 103 | 
            +
                };
         | 
| 104 | 
            +
                return string.replace(/\[\[([^\]]+)\]\]/gi, renderInternalLink).replace(/\[(http.*?) (.*?)\]/gi, "<a class=\"external\" target=\"_blank\" href=\"$1\" title=\"$1\" rel=\"nofollow\">$2 <img src=\"/images/external-link-ltr-icon.png\"></a>");
         | 
| 105 | 
            +
              };
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              module.exports = wiki;
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            }).call(this);
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            },{"./persona":5,"./synopsis":4}],3:[function(require,module,exports){
         | 
| 112 | 
            +
            (function() {
         | 
| 113 | 
            +
              var active, newPage, pageHandler, plugin, refresh, state, util, wiki;
         | 
| 114 | 
            +
             | 
| 115 | 
            +
              wiki = require('./wiki');
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              util = require('./util');
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              pageHandler = wiki.pageHandler = require('./pageHandler');
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              plugin = require('./plugin');
         | 
| 122 | 
            +
             | 
| 123 | 
            +
              state = require('./state');
         | 
| 124 | 
            +
             | 
| 125 | 
            +
              active = require('./active');
         | 
| 126 | 
            +
             | 
| 127 | 
            +
              refresh = require('./refresh');
         | 
| 128 | 
            +
             | 
| 129 | 
            +
              newPage = require('./page').newPage;
         | 
| 130 | 
            +
             | 
| 131 | 
            +
              Array.prototype.last = function() {
         | 
| 132 | 
            +
                return this[this.length - 1];
         | 
| 133 | 
            +
              };
         | 
| 134 | 
            +
             | 
| 135 | 
            +
              $(function() {
         | 
| 136 | 
            +
                var LEFTARROW, RIGHTARROW, createTextElement, doInternalLink, finishClick, getTemplate, sleep, textEditor;
         | 
| 137 | 
            +
                window.dialog = $('<div></div>').html('This dialog will show every time!').dialog({
         | 
| 138 | 
            +
                  autoOpen: false,
         | 
| 139 | 
            +
                  title: 'Basic Dialog',
         | 
| 140 | 
            +
                  height: 600,
         | 
| 141 | 
            +
                  width: 800
         | 
| 142 | 
            +
                });
         | 
| 143 | 
            +
                wiki.dialog = function(title, html) {
         | 
| 144 | 
            +
                  window.dialog.html(html);
         | 
| 145 | 
            +
                  window.dialog.dialog("option", "title", wiki.resolveLinks(title));
         | 
| 146 | 
            +
                  return window.dialog.dialog('open');
         | 
| 147 | 
            +
                };
         | 
| 148 | 
            +
                sleep = function(time, done) {
         | 
| 149 | 
            +
                  return setTimeout(done, time);
         | 
| 150 | 
            +
                };
         | 
| 151 | 
            +
                wiki.removeItem = function($item, item) {
         | 
| 152 | 
            +
                  pageHandler.put($item.parents('.page:first'), {
         | 
| 153 | 
            +
                    type: 'remove',
         | 
| 154 | 
            +
                    id: item.id
         | 
| 155 | 
            +
                  });
         | 
| 156 | 
            +
                  return $item.remove();
         | 
| 157 | 
            +
                };
         | 
| 158 | 
            +
                wiki.createItem = function($page, $before, item) {
         | 
| 159 | 
            +
                  var $item, before;
         | 
| 160 | 
            +
                  if ($page == null) {
         | 
| 161 | 
            +
                    $page = $before.parents('.page');
         | 
| 162 | 
            +
                  }
         | 
| 163 | 
            +
                  item.id = util.randomBytes(8);
         | 
| 164 | 
            +
                  $item = $("<div class=\"item " + item.type + "\" data-id=\"" + "\"</div>");
         | 
| 165 | 
            +
                  $item.data('item', item).data('pageElement', $page);
         | 
| 166 | 
            +
                  if ($before != null) {
         | 
| 167 | 
            +
                    $before.after($item);
         | 
| 168 | 
            +
                  } else {
         | 
| 169 | 
            +
                    $page.find('.story').append($item);
         | 
| 170 | 
            +
                  }
         | 
| 171 | 
            +
                  plugin["do"]($item, item);
         | 
| 172 | 
            +
                  before = wiki.getItem($before);
         | 
| 173 | 
            +
                  sleep(500, function() {
         | 
| 174 | 
            +
                    return pageHandler.put($page, {
         | 
| 175 | 
            +
                      item: item,
         | 
| 176 | 
            +
                      id: item.id,
         | 
| 177 | 
            +
                      type: 'add',
         | 
| 178 | 
            +
                      after: before != null ? before.id : void 0
         | 
| 179 | 
            +
                    });
         | 
| 180 | 
            +
                  });
         | 
| 181 | 
            +
                  return $item;
         | 
| 182 | 
            +
                };
         | 
| 183 | 
            +
                createTextElement = function(pageElement, beforeElement, initialText) {
         | 
| 184 | 
            +
                  var item, itemBefore, itemElement;
         | 
| 185 | 
            +
                  item = {
         | 
| 186 | 
            +
                    type: 'paragraph',
         | 
| 187 | 
            +
                    id: util.randomBytes(8),
         | 
| 188 | 
            +
                    text: initialText
         | 
| 189 | 
            +
                  };
         | 
| 190 | 
            +
                  itemElement = $("<div class=\"item paragraph\" data-id=" + item.id + "></div>");
         | 
| 191 | 
            +
                  itemElement.data('item', item).data('pageElement', pageElement);
         | 
| 192 | 
            +
                  beforeElement.after(itemElement);
         | 
| 193 | 
            +
                  plugin["do"](itemElement, item);
         | 
| 194 | 
            +
                  itemBefore = wiki.getItem(beforeElement);
         | 
| 195 | 
            +
                  wiki.textEditor(itemElement, item);
         | 
| 196 | 
            +
                  return sleep(500, function() {
         | 
| 197 | 
            +
                    return pageHandler.put(pageElement, {
         | 
| 198 | 
            +
                      item: item,
         | 
| 199 | 
            +
                      id: item.id,
         | 
| 200 | 
            +
                      type: 'add',
         | 
| 201 | 
            +
                      after: itemBefore != null ? itemBefore.id : void 0
         | 
| 202 | 
            +
                    });
         | 
| 203 | 
            +
                  });
         | 
| 204 | 
            +
                };
         | 
| 205 | 
            +
                textEditor = wiki.textEditor = function(div, item, caretPos, doubleClicked) {
         | 
| 206 | 
            +
                  var original, textarea, _ref;
         | 
| 207 | 
            +
                  if (div.hasClass('textEditing')) {
         | 
| 208 | 
            +
                    return;
         | 
| 209 | 
            +
                  }
         | 
| 210 | 
            +
                  div.addClass('textEditing');
         | 
| 211 | 
            +
                  textarea = $("<textarea>" + (original = (_ref = item.text) != null ? _ref : '') + "</textarea>").focusout(function() {
         | 
| 212 | 
            +
                    div.removeClass('textEditing');
         | 
| 213 | 
            +
                    if (item.text = textarea.val()) {
         | 
| 214 | 
            +
                      plugin["do"](div.empty(), item);
         | 
| 215 | 
            +
                      if (item.text === original) {
         | 
| 216 | 
            +
                        return;
         | 
| 217 | 
            +
                      }
         | 
| 218 | 
            +
                      pageHandler.put(div.parents('.page:first'), {
         | 
| 219 | 
            +
                        type: 'edit',
         | 
| 220 | 
            +
                        id: item.id,
         | 
| 221 | 
            +
                        item: item
         | 
| 222 | 
            +
                      });
         | 
| 223 | 
            +
                    } else {
         | 
| 224 | 
            +
                      pageHandler.put(div.parents('.page:first'), {
         | 
| 225 | 
            +
                        type: 'remove',
         | 
| 226 | 
            +
                        id: item.id
         | 
| 227 | 
            +
                      });
         | 
| 228 | 
            +
                      div.remove();
         | 
| 229 | 
            +
                    }
         | 
| 230 | 
            +
                    return null;
         | 
| 231 | 
            +
                  }).bind('keydown', function(e) {
         | 
| 232 | 
            +
                    var middle, page, pageElement, prefix, prevItem, prevTextLen, sel, suffix, text;
         | 
| 233 | 
            +
                    if ((e.altKey || e.ctlKey || e.metaKey) && e.which === 83) {
         | 
| 234 | 
            +
                      textarea.focusout();
         | 
| 235 | 
            +
                      return false;
         | 
| 236 | 
            +
                    }
         | 
| 237 | 
            +
                    if ((e.altKey || e.ctlKey || e.metaKey) && e.which === 73) {
         | 
| 238 | 
            +
                      e.preventDefault();
         | 
| 239 | 
            +
                      if (!e.shiftKey) {
         | 
| 240 | 
            +
                        page = $(e.target).parents('.page');
         | 
| 241 | 
            +
                      }
         | 
| 242 | 
            +
                      doInternalLink("about " + item.type + " plugin", page);
         | 
| 243 | 
            +
                      return false;
         | 
| 244 | 
            +
                    }
         | 
| 245 | 
            +
                    if (item.type === 'paragraph') {
         | 
| 246 | 
            +
                      sel = util.getSelectionPos(textarea);
         | 
| 247 | 
            +
                      if (e.which === $.ui.keyCode.BACKSPACE && sel.start === 0 && sel.start === sel.end) {
         | 
| 248 | 
            +
                        prevItem = wiki.getItem(div.prev());
         | 
| 249 | 
            +
                        if (prevItem.type !== 'paragraph') {
         | 
| 250 | 
            +
                          return false;
         | 
| 251 | 
            +
                        }
         | 
| 252 | 
            +
                        prevTextLen = prevItem.text.length;
         | 
| 253 | 
            +
                        prevItem.text += textarea.val();
         | 
| 254 | 
            +
                        textarea.val('');
         | 
| 255 | 
            +
                        textEditor(div.prev(), prevItem, prevTextLen);
         | 
| 256 | 
            +
                        return false;
         | 
| 257 | 
            +
                      } else if (e.which === $.ui.keyCode.ENTER && item.type === 'paragraph') {
         | 
| 258 | 
            +
                        if (!sel) {
         | 
| 259 | 
            +
                          return false;
         | 
| 260 | 
            +
                        }
         | 
| 261 | 
            +
                        text = textarea.val();
         | 
| 262 | 
            +
                        prefix = text.substring(0, sel.start);
         | 
| 263 | 
            +
                        if (sel.start !== sel.end) {
         | 
| 264 | 
            +
                          middle = text.substring(sel.start, sel.end);
         | 
| 265 | 
            +
                        }
         | 
| 266 | 
            +
                        suffix = text.substring(sel.end);
         | 
| 267 | 
            +
                        if (prefix === '') {
         | 
| 268 | 
            +
                          textarea.val(' ');
         | 
| 269 | 
            +
                        } else {
         | 
| 270 | 
            +
                          textarea.val(prefix);
         | 
| 271 | 
            +
                        }
         | 
| 272 | 
            +
                        textarea.focusout();
         | 
| 273 | 
            +
                        pageElement = div.parent().parent();
         | 
| 274 | 
            +
                        createTextElement(pageElement, div, suffix);
         | 
| 275 | 
            +
                        if (middle != null) {
         | 
| 276 | 
            +
                          createTextElement(pageElement, div, middle);
         | 
| 277 | 
            +
                        }
         | 
| 278 | 
            +
                        if (prefix === '') {
         | 
| 279 | 
            +
                          createTextElement(pageElement, div, '');
         | 
| 280 | 
            +
                        }
         | 
| 281 | 
            +
                        return false;
         | 
| 282 | 
            +
                      }
         | 
| 283 | 
            +
                    }
         | 
| 284 | 
            +
                  });
         | 
| 285 | 
            +
                  div.html(textarea);
         | 
| 286 | 
            +
                  if (caretPos != null) {
         | 
| 287 | 
            +
                    return util.setCaretPosition(textarea, caretPos);
         | 
| 288 | 
            +
                  } else if (doubleClicked) {
         | 
| 289 | 
            +
                    util.setCaretPosition(textarea, textarea.val().length);
         | 
| 290 | 
            +
                    return textarea.scrollTop(textarea[0].scrollHeight - textarea.height());
         | 
| 291 | 
            +
                  } else {
         | 
| 292 | 
            +
                    return textarea.focus();
         | 
| 293 | 
            +
                  }
         | 
| 294 | 
            +
                };
         | 
| 295 | 
            +
                doInternalLink = wiki.doInternalLink = function(name, page, site) {
         | 
| 296 | 
            +
                  if (site == null) {
         | 
| 297 | 
            +
                    site = null;
         | 
| 298 | 
            +
                  }
         | 
| 299 | 
            +
                  name = wiki.asSlug(name);
         | 
| 300 | 
            +
                  if (page != null) {
         | 
| 301 | 
            +
                    $(page).nextAll().remove();
         | 
| 302 | 
            +
                  }
         | 
| 303 | 
            +
                  wiki.createPage(name, site).appendTo($('.main')).each(refresh);
         | 
| 304 | 
            +
                  return active.set($('.page').last());
         | 
| 305 | 
            +
                };
         | 
| 306 | 
            +
                LEFTARROW = 37;
         | 
| 307 | 
            +
                RIGHTARROW = 39;
         | 
| 308 | 
            +
                $(document).keydown(function(event) {
         | 
| 309 | 
            +
                  var direction, newIndex, pages;
         | 
| 310 | 
            +
                  direction = (function() {
         | 
| 311 | 
            +
                    switch (event.which) {
         | 
| 312 | 
            +
                      case LEFTARROW:
         | 
| 313 | 
            +
                        return -1;
         | 
| 314 | 
            +
                      case RIGHTARROW:
         | 
| 315 | 
            +
                        return +1;
         | 
| 316 | 
            +
                    }
         | 
| 317 | 
            +
                  })();
         | 
| 318 | 
            +
                  if (direction && !(event.target.tagName === "TEXTAREA")) {
         | 
| 319 | 
            +
                    pages = $('.page');
         | 
| 320 | 
            +
                    newIndex = pages.index($('.active')) + direction;
         | 
| 321 | 
            +
                    if ((0 <= newIndex && newIndex < pages.length)) {
         | 
| 322 | 
            +
                      return active.set(pages.eq(newIndex));
         | 
| 323 | 
            +
                    }
         | 
| 324 | 
            +
                  }
         | 
| 325 | 
            +
                });
         | 
| 326 | 
            +
                $(window).on('popstate', state.show);
         | 
| 327 | 
            +
                $(document).ajaxError(function(event, request, settings) {
         | 
| 328 | 
            +
                  if (request.status === 0 || request.status === 404) {
         | 
| 329 | 
            +
                    return;
         | 
| 330 | 
            +
                  }
         | 
| 331 | 
            +
                  wiki.log('ajax error', event, request, settings);
         | 
| 332 | 
            +
                  return $('.main').prepend("<li class='error'>\n  Error on " + settings.url + ": " + request.responseText + "\n</li>");
         | 
| 333 | 
            +
                });
         | 
| 334 | 
            +
                getTemplate = function(slug, done) {
         | 
| 335 | 
            +
                  if (!slug) {
         | 
| 336 | 
            +
                    return done(null);
         | 
| 337 | 
            +
                  }
         | 
| 338 | 
            +
                  wiki.log('getTemplate', slug);
         | 
| 339 | 
            +
                  return pageHandler.get({
         | 
| 340 | 
            +
                    whenGotten: function(data, siteFound) {
         | 
| 341 | 
            +
                      return done(data.story);
         | 
| 342 | 
            +
                    },
         | 
| 343 | 
            +
                    whenNotGotten: function() {
         | 
| 344 | 
            +
                      return done(null);
         | 
| 345 | 
            +
                    },
         | 
| 346 | 
            +
                    pageInformation: {
         | 
| 347 | 
            +
                      slug: slug
         | 
| 348 | 
            +
                    }
         | 
| 349 | 
            +
                  });
         | 
| 350 | 
            +
                };
         | 
| 351 | 
            +
                finishClick = function(e, name) {
         | 
| 352 | 
            +
                  var page;
         | 
| 353 | 
            +
                  e.preventDefault();
         | 
| 354 | 
            +
                  if (!e.shiftKey) {
         | 
| 355 | 
            +
                    page = $(e.target).parents('.page');
         | 
| 356 | 
            +
                  }
         | 
| 357 | 
            +
                  doInternalLink(name, page, $(e.target).data('site'));
         | 
| 358 | 
            +
                  return false;
         | 
| 359 | 
            +
                };
         | 
| 360 | 
            +
                $('.main').delegate('.show-page-source', 'click', function(e) {
         | 
| 361 | 
            +
                  var json, pageElement;
         | 
| 362 | 
            +
                  e.preventDefault();
         | 
| 363 | 
            +
                  pageElement = $(this).parent().parent();
         | 
| 364 | 
            +
                  json = pageElement.data('data');
         | 
| 365 | 
            +
                  return wiki.dialog("JSON for " + json.title, $('<pre/>').text(JSON.stringify(json, null, 2)));
         | 
| 366 | 
            +
                }).delegate('.page', 'click', function(e) {
         | 
| 367 | 
            +
                  if (!$(e.target).is("a")) {
         | 
| 368 | 
            +
                    return active.set(this);
         | 
| 369 | 
            +
                  }
         | 
| 370 | 
            +
                }).delegate('.internal', 'click', function(e) {
         | 
| 371 | 
            +
                  var name;
         | 
| 372 | 
            +
                  name = $(e.target).data('pageName');
         | 
| 373 | 
            +
                  pageHandler.context = $(e.target).attr('title').split(' => ');
         | 
| 374 | 
            +
                  return finishClick(e, name);
         | 
| 375 | 
            +
                }).delegate('img.remote', 'click', function(e) {
         | 
| 376 | 
            +
                  var name;
         | 
| 377 | 
            +
                  name = $(e.target).data('slug');
         | 
| 378 | 
            +
                  pageHandler.context = [$(e.target).data('site')];
         | 
| 379 | 
            +
                  return finishClick(e, name);
         | 
| 380 | 
            +
                }).delegate('.revision', 'dblclick', function(e) {
         | 
| 381 | 
            +
                  var $page, action, json, page, rev;
         | 
| 382 | 
            +
                  e.preventDefault();
         | 
| 383 | 
            +
                  $page = $(this).parents('.page');
         | 
| 384 | 
            +
                  page = $page.data('data');
         | 
| 385 | 
            +
                  rev = page.journal.length - 1;
         | 
| 386 | 
            +
                  action = page.journal[rev];
         | 
| 387 | 
            +
                  json = JSON.stringify(action, null, 2);
         | 
| 388 | 
            +
                  return wiki.dialog("Revision " + rev + ", " + action.type + " action", $('<pre/>').text(json));
         | 
| 389 | 
            +
                }).delegate('.action', 'click', function(e) {
         | 
| 390 | 
            +
                  var $action, $page, name, rev, slug;
         | 
| 391 | 
            +
                  e.preventDefault();
         | 
| 392 | 
            +
                  $action = $(e.target);
         | 
| 393 | 
            +
                  if ($action.is('.fork') && ((name = $action.data('slug')) != null)) {
         | 
| 394 | 
            +
                    pageHandler.context = [$action.data('site')];
         | 
| 395 | 
            +
                    return finishClick(e, (name.split('_'))[0]);
         | 
| 396 | 
            +
                  } else {
         | 
| 397 | 
            +
                    $page = $(this).parents('.page');
         | 
| 398 | 
            +
                    slug = wiki.asSlug($page.data('data').title);
         | 
| 399 | 
            +
                    rev = $(this).parent().children().index($action);
         | 
| 400 | 
            +
                    if (!e.shiftKey) {
         | 
| 401 | 
            +
                      $page.nextAll().remove();
         | 
| 402 | 
            +
                    }
         | 
| 403 | 
            +
                    wiki.createPage("" + slug + "_rev" + rev, $page.data('site')).appendTo($('.main')).each(refresh);
         | 
| 404 | 
            +
                    return active.set($('.page').last());
         | 
| 405 | 
            +
                  }
         | 
| 406 | 
            +
                }).delegate('.fork-page', 'click', function(e) {
         | 
| 407 | 
            +
                  var item, pageElement, remoteSite;
         | 
| 408 | 
            +
                  pageElement = $(e.target).parents('.page');
         | 
| 409 | 
            +
                  if (pageElement.hasClass('local')) {
         | 
| 410 | 
            +
                    if (!wiki.useLocalStorage()) {
         | 
| 411 | 
            +
                      item = pageElement.data('data');
         | 
| 412 | 
            +
                      pageElement.removeClass('local');
         | 
| 413 | 
            +
                      return pageHandler.put(pageElement, {
         | 
| 414 | 
            +
                        type: 'fork',
         | 
| 415 | 
            +
                        item: item
         | 
| 416 | 
            +
                      });
         | 
| 417 | 
            +
                    }
         | 
| 418 | 
            +
                  } else {
         | 
| 419 | 
            +
                    if ((remoteSite = pageElement.data('site')) != null) {
         | 
| 420 | 
            +
                      return pageHandler.put(pageElement, {
         | 
| 421 | 
            +
                        type: 'fork',
         | 
| 422 | 
            +
                        site: remoteSite
         | 
| 423 | 
            +
                      });
         | 
| 424 | 
            +
                    }
         | 
| 425 | 
            +
                  }
         | 
| 426 | 
            +
                }).delegate('.action', 'hover', function() {
         | 
| 427 | 
            +
                  var id;
         | 
| 428 | 
            +
                  id = $(this).attr('data-id');
         | 
| 429 | 
            +
                  $("[data-id=" + id + "]").toggleClass('target');
         | 
| 430 | 
            +
                  return $('.main').trigger('rev');
         | 
| 431 | 
            +
                }).delegate('.item', 'hover', function() {
         | 
| 432 | 
            +
                  var id;
         | 
| 433 | 
            +
                  id = $(this).attr('data-id');
         | 
| 434 | 
            +
                  return $(".action[data-id=" + id + "]").toggleClass('target');
         | 
| 435 | 
            +
                }).delegate('button.create', 'click', function(e) {
         | 
| 436 | 
            +
                  return getTemplate($(e.target).data('slug'), function(story) {
         | 
| 437 | 
            +
                    var $page, page, pageObject;
         | 
| 438 | 
            +
                    $page = $(e.target).parents('.page:first');
         | 
| 439 | 
            +
                    $page.removeClass('ghost');
         | 
| 440 | 
            +
                    page = $page.data('data');
         | 
| 441 | 
            +
                    page.story = story || [];
         | 
| 442 | 
            +
                    pageObject = newPage(page, null);
         | 
| 443 | 
            +
                    page = pageObject.getRawPage();
         | 
| 444 | 
            +
                    pageHandler.put($page, {
         | 
| 445 | 
            +
                      type: 'create',
         | 
| 446 | 
            +
                      id: page.id,
         | 
| 447 | 
            +
                      item: {
         | 
| 448 | 
            +
                        title: page.title,
         | 
| 449 | 
            +
                        story: page.story
         | 
| 450 | 
            +
                      }
         | 
| 451 | 
            +
                    });
         | 
| 452 | 
            +
                    return wiki.buildPage(pageObject, $page.empty());
         | 
| 453 | 
            +
                  });
         | 
| 454 | 
            +
                }).delegate('.ghost', 'rev', function(e) {
         | 
| 455 | 
            +
                  var $item, $page, position;
         | 
| 456 | 
            +
                  wiki.log('rev', e);
         | 
| 457 | 
            +
                  $page = $(e.target).parents('.page:first');
         | 
| 458 | 
            +
                  $item = $page.find('.target');
         | 
| 459 | 
            +
                  position = $item.offset().top + $page.scrollTop() - $page.height() / 2;
         | 
| 460 | 
            +
                  wiki.log('scroll', $page, $item, position);
         | 
| 461 | 
            +
                  return $page.stop().animate({
         | 
| 462 | 
            +
                    scrollTop: postion
         | 
| 463 | 
            +
                  }, 'slow');
         | 
| 464 | 
            +
                }).delegate('.score', 'hover', function(e) {
         | 
| 465 | 
            +
                  return $('.main').trigger('thumb', $(e.target).data('thumb'));
         | 
| 466 | 
            +
                });
         | 
| 467 | 
            +
                $(".provider input").click(function() {
         | 
| 468 | 
            +
                  $("footer input:first").val($(this).attr('data-provider'));
         | 
| 469 | 
            +
                  return $("footer form").submit();
         | 
| 470 | 
            +
                });
         | 
| 471 | 
            +
                $('body').on('new-neighbor-done', function(e, neighbor) {
         | 
| 472 | 
            +
                  return $('.page').each(function(index, element) {
         | 
| 473 | 
            +
                    return wiki.emitTwins($(element));
         | 
| 474 | 
            +
                  });
         | 
| 475 | 
            +
                });
         | 
| 476 | 
            +
                return $(function() {
         | 
| 477 | 
            +
                  state.first();
         | 
| 478 | 
            +
                  $('.page').each(refresh);
         | 
| 479 | 
            +
                  return active.set($('.page').last());
         | 
| 480 | 
            +
                });
         | 
| 481 | 
            +
              });
         | 
| 482 | 
            +
             | 
| 483 | 
            +
            }).call(this);
         | 
| 484 | 
            +
             | 
| 485 | 
            +
            },{"./active":10,"./page":12,"./pageHandler":7,"./plugin":8,"./refresh":11,"./state":9,"./util":6,"./wiki":2}],4:[function(require,module,exports){
         | 
| 486 | 
            +
            (function() {
         | 
| 487 | 
            +
              module.exports = function(page) {
         | 
| 488 | 
            +
                var p1, p2, synopsis;
         | 
| 489 | 
            +
                synopsis = page.synopsis;
         | 
| 490 | 
            +
                if ((page != null) && (page.story != null)) {
         | 
| 491 | 
            +
                  p1 = page.story[0];
         | 
| 492 | 
            +
                  p2 = page.story[1];
         | 
| 493 | 
            +
                  if (p1 && p1.type === 'paragraph') {
         | 
| 494 | 
            +
                    synopsis || (synopsis = p1.text);
         | 
| 495 | 
            +
                  }
         | 
| 496 | 
            +
                  if (p2 && p2.type === 'paragraph') {
         | 
| 497 | 
            +
                    synopsis || (synopsis = p2.text);
         | 
| 498 | 
            +
                  }
         | 
| 499 | 
            +
                  if (p1 && (p1.text != null)) {
         | 
| 500 | 
            +
                    synopsis || (synopsis = p1.text);
         | 
| 501 | 
            +
                  }
         | 
| 502 | 
            +
                  if (p2 && (p2.text != null)) {
         | 
| 503 | 
            +
                    synopsis || (synopsis = p2.text);
         | 
| 504 | 
            +
                  }
         | 
| 505 | 
            +
                  synopsis || (synopsis = (page.story != null) && ("A page with " + page.story.length + " items."));
         | 
| 506 | 
            +
                } else {
         | 
| 507 | 
            +
                  synopsis = 'A page with no story.';
         | 
| 508 | 
            +
                }
         | 
| 509 | 
            +
                return synopsis;
         | 
| 510 | 
            +
              };
         | 
| 511 | 
            +
             | 
| 512 | 
            +
            }).call(this);
         | 
| 513 | 
            +
             | 
| 514 | 
            +
            },{}],5:[function(require,module,exports){
         | 
| 515 | 
            +
            (function() {
         | 
| 516 | 
            +
              module.exports = function(owner) {
         | 
| 517 | 
            +
                $("#user-email").hide();
         | 
| 518 | 
            +
                $("#persona-login-btn").hide();
         | 
| 519 | 
            +
                $("#persona-logout-btn").hide();
         | 
| 520 | 
            +
                navigator.id.watch({
         | 
| 521 | 
            +
                  loggedInUser: owner,
         | 
| 522 | 
            +
                  onlogin: function(assertion) {
         | 
| 523 | 
            +
                    return $.post("/persona_login", {
         | 
| 524 | 
            +
                      assertion: assertion
         | 
| 525 | 
            +
                    }, function(verified) {
         | 
| 526 | 
            +
                      verified = JSON.parse(verified);
         | 
| 527 | 
            +
                      if ("okay" === verified.status) {
         | 
| 528 | 
            +
                        return window.location = "/";
         | 
| 529 | 
            +
                      } else {
         | 
| 530 | 
            +
                        navigator.id.logout();
         | 
| 531 | 
            +
                        if ("wrong-address" === verified.status) {
         | 
| 532 | 
            +
                          return window.location = "/oops";
         | 
| 533 | 
            +
                        }
         | 
| 534 | 
            +
                      }
         | 
| 535 | 
            +
                    });
         | 
| 536 | 
            +
                  },
         | 
| 537 | 
            +
                  onlogout: function() {
         | 
| 538 | 
            +
                    return $.post("/persona_logout", function() {
         | 
| 539 | 
            +
                      return window.location = "/";
         | 
| 540 | 
            +
                    });
         | 
| 541 | 
            +
                  },
         | 
| 542 | 
            +
                  onready: function() {
         | 
| 543 | 
            +
                    if (owner) {
         | 
| 544 | 
            +
                      $("#persona-login-btn").hide();
         | 
| 545 | 
            +
                      return $("#persona-logout-btn").show();
         | 
| 546 | 
            +
                    } else {
         | 
| 547 | 
            +
                      $("#persona-login-btn").show();
         | 
| 548 | 
            +
                      return $("#persona-logout-btn").hide();
         | 
| 549 | 
            +
                    }
         | 
| 550 | 
            +
                  }
         | 
| 551 | 
            +
                });
         | 
| 552 | 
            +
                $("#persona-login-btn").click(function(e) {
         | 
| 553 | 
            +
                  e.preventDefault();
         | 
| 554 | 
            +
                  return navigator.id.request({});
         | 
| 555 | 
            +
                });
         | 
| 556 | 
            +
                return $("#persona-logout-btn").click(function(e) {
         | 
| 557 | 
            +
                  e.preventDefault();
         | 
| 558 | 
            +
                  return navigator.id.logout();
         | 
| 559 | 
            +
                });
         | 
| 560 | 
            +
              };
         | 
| 561 | 
            +
             | 
| 562 | 
            +
            }).call(this);
         | 
| 563 | 
            +
             | 
| 564 | 
            +
            },{}],10:[function(require,module,exports){
         | 
| 565 | 
            +
            (function() {
         | 
| 566 | 
            +
              var active, findScrollContainer, scrollTo;
         | 
| 567 | 
            +
             | 
| 568 | 
            +
              module.exports = active = {};
         | 
| 569 | 
            +
             | 
| 570 | 
            +
              active.scrollContainer = void 0;
         | 
| 571 | 
            +
             | 
| 572 | 
            +
              findScrollContainer = function() {
         | 
| 573 | 
            +
                var scrolled;
         | 
| 574 | 
            +
                scrolled = $("body, html").filter(function() {
         | 
| 575 | 
            +
                  return $(this).scrollLeft() > 0;
         | 
| 576 | 
            +
                });
         | 
| 577 | 
            +
                if (scrolled.length > 0) {
         | 
| 578 | 
            +
                  return scrolled;
         | 
| 579 | 
            +
                } else {
         | 
| 580 | 
            +
                  return $("body, html").scrollLeft(12).filter(function() {
         | 
| 581 | 
            +
                    return $(this).scrollLeft() > 0;
         | 
| 582 | 
            +
                  }).scrollTop(0);
         | 
| 583 | 
            +
                }
         | 
| 584 | 
            +
              };
         | 
| 585 | 
            +
             | 
| 586 | 
            +
              scrollTo = function(el) {
         | 
| 587 | 
            +
                var bodyWidth, contentWidth, maxX, minX, target, width;
         | 
| 588 | 
            +
                if (active.scrollContainer == null) {
         | 
| 589 | 
            +
                  active.scrollContainer = findScrollContainer();
         | 
| 590 | 
            +
                }
         | 
| 591 | 
            +
                bodyWidth = $("body").width();
         | 
| 592 | 
            +
                minX = active.scrollContainer.scrollLeft();
         | 
| 593 | 
            +
                maxX = minX + bodyWidth;
         | 
| 594 | 
            +
                target = el.position().left;
         | 
| 595 | 
            +
                width = el.outerWidth(true);
         | 
| 596 | 
            +
                contentWidth = $(".page").outerWidth(true) * $(".page").size();
         | 
| 597 | 
            +
                if (target < minX) {
         | 
| 598 | 
            +
                  return active.scrollContainer.animate({
         | 
| 599 | 
            +
                    scrollLeft: target
         | 
| 600 | 
            +
                  });
         | 
| 601 | 
            +
                } else if (target + width > maxX) {
         | 
| 602 | 
            +
                  return active.scrollContainer.animate({
         | 
| 603 | 
            +
                    scrollLeft: target - (bodyWidth - width)
         | 
| 604 | 
            +
                  });
         | 
| 605 | 
            +
                } else if (maxX > $(".pages").outerWidth()) {
         | 
| 606 | 
            +
                  return active.scrollContainer.animate({
         | 
| 607 | 
            +
                    scrollLeft: Math.min(target, contentWidth - bodyWidth)
         | 
| 608 | 
            +
                  });
         | 
| 609 | 
            +
                }
         | 
| 610 | 
            +
              };
         | 
| 611 | 
            +
             | 
| 612 | 
            +
              active.set = function(el) {
         | 
| 613 | 
            +
                el = $(el);
         | 
| 614 | 
            +
                $(".active").removeClass("active");
         | 
| 615 | 
            +
                return scrollTo(el.addClass("active"));
         | 
| 616 | 
            +
              };
         | 
| 617 | 
            +
             | 
| 618 | 
            +
            }).call(this);
         | 
| 619 | 
            +
             | 
| 620 | 
            +
            },{}],6:[function(require,module,exports){
         | 
| 621 | 
            +
            (function() {
         | 
| 622 | 
            +
              var util, wiki;
         | 
| 623 | 
            +
             | 
| 624 | 
            +
              wiki = require('./wiki');
         | 
| 625 | 
            +
             | 
| 626 | 
            +
              module.exports = wiki.util = util = {};
         | 
| 627 | 
            +
             | 
| 628 | 
            +
              util.symbols = {
         | 
| 629 | 
            +
                create: '☼',
         | 
| 630 | 
            +
                add: '+',
         | 
| 631 | 
            +
                edit: '✎',
         | 
| 632 | 
            +
                fork: '⚑',
         | 
| 633 | 
            +
                move: '↕',
         | 
| 634 | 
            +
                remove: '✕'
         | 
| 635 | 
            +
              };
         | 
| 636 | 
            +
             | 
| 637 | 
            +
              util.randomByte = function() {
         | 
| 638 | 
            +
                return (((1 + Math.random()) * 0x100) | 0).toString(16).substring(1);
         | 
| 639 | 
            +
              };
         | 
| 640 | 
            +
             | 
| 641 | 
            +
              util.randomBytes = function(n) {
         | 
| 642 | 
            +
                return ((function() {
         | 
| 643 | 
            +
                  var _i, _results;
         | 
| 644 | 
            +
                  _results = [];
         | 
| 645 | 
            +
                  for (_i = 1; 1 <= n ? _i <= n : _i >= n; 1 <= n ? _i++ : _i--) {
         | 
| 646 | 
            +
                    _results.push(util.randomByte());
         | 
| 647 | 
            +
                  }
         | 
| 648 | 
            +
                  return _results;
         | 
| 649 | 
            +
                })()).join('');
         | 
| 650 | 
            +
              };
         | 
| 651 | 
            +
             | 
| 652 | 
            +
              util.formatTime = function(time) {
         | 
| 653 | 
            +
                var am, d, h, mi, mo;
         | 
| 654 | 
            +
                d = new Date((time > 10000000000 ? time : time * 1000));
         | 
| 655 | 
            +
                mo = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][d.getMonth()];
         | 
| 656 | 
            +
                h = d.getHours();
         | 
| 657 | 
            +
                am = h < 12 ? 'AM' : 'PM';
         | 
| 658 | 
            +
                h = h === 0 ? 12 : h > 12 ? h - 12 : h;
         | 
| 659 | 
            +
                mi = (d.getMinutes() < 10 ? "0" : "") + d.getMinutes();
         | 
| 660 | 
            +
                return "" + h + ":" + mi + " " + am + "<br>" + (d.getDate()) + " " + mo + " " + (d.getFullYear());
         | 
| 661 | 
            +
              };
         | 
| 662 | 
            +
             | 
| 663 | 
            +
              util.formatDate = function(msSinceEpoch) {
         | 
| 664 | 
            +
                var am, d, day, h, mi, mo, sec, wk, yr;
         | 
| 665 | 
            +
                d = new Date(msSinceEpoch);
         | 
| 666 | 
            +
                wk = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][d.getDay()];
         | 
| 667 | 
            +
                mo = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][d.getMonth()];
         | 
| 668 | 
            +
                day = d.getDate();
         | 
| 669 | 
            +
                yr = d.getFullYear();
         | 
| 670 | 
            +
                h = d.getHours();
         | 
| 671 | 
            +
                am = h < 12 ? 'AM' : 'PM';
         | 
| 672 | 
            +
                h = h === 0 ? 12 : h > 12 ? h - 12 : h;
         | 
| 673 | 
            +
                mi = (d.getMinutes() < 10 ? "0" : "") + d.getMinutes();
         | 
| 674 | 
            +
                sec = (d.getSeconds() < 10 ? "0" : "") + d.getSeconds();
         | 
| 675 | 
            +
                return "" + wk + " " + mo + " " + day + ", " + yr + "<br>" + h + ":" + mi + ":" + sec + " " + am;
         | 
| 676 | 
            +
              };
         | 
| 677 | 
            +
             | 
| 678 | 
            +
              util.formatElapsedTime = function(msSinceEpoch) {
         | 
| 679 | 
            +
                var days, hrs, mins, months, msecs, secs, weeks, years;
         | 
| 680 | 
            +
                msecs = new Date().getTime() - msSinceEpoch;
         | 
| 681 | 
            +
                if ((secs = msecs / 1000) < 2) {
         | 
| 682 | 
            +
                  return "" + (Math.floor(msecs)) + " milliseconds ago";
         | 
| 683 | 
            +
                }
         | 
| 684 | 
            +
                if ((mins = secs / 60) < 2) {
         | 
| 685 | 
            +
                  return "" + (Math.floor(secs)) + " seconds ago";
         | 
| 686 | 
            +
                }
         | 
| 687 | 
            +
                if ((hrs = mins / 60) < 2) {
         | 
| 688 | 
            +
                  return "" + (Math.floor(mins)) + " minutes ago";
         | 
| 689 | 
            +
                }
         | 
| 690 | 
            +
                if ((days = hrs / 24) < 2) {
         | 
| 691 | 
            +
                  return "" + (Math.floor(hrs)) + " hours ago";
         | 
| 692 | 
            +
                }
         | 
| 693 | 
            +
                if ((weeks = days / 7) < 2) {
         | 
| 694 | 
            +
                  return "" + (Math.floor(days)) + " days ago";
         | 
| 695 | 
            +
                }
         | 
| 696 | 
            +
                if ((months = days / 31) < 2) {
         | 
| 697 | 
            +
                  return "" + (Math.floor(weeks)) + " weeks ago";
         | 
| 698 | 
            +
                }
         | 
| 699 | 
            +
                if ((years = days / 365) < 2) {
         | 
| 700 | 
            +
                  return "" + (Math.floor(months)) + " months ago";
         | 
| 701 | 
            +
                }
         | 
| 702 | 
            +
                return "" + (Math.floor(years)) + " years ago";
         | 
| 703 | 
            +
              };
         | 
| 704 | 
            +
             | 
| 705 | 
            +
              util.emptyPage = function() {
         | 
| 706 | 
            +
                return {
         | 
| 707 | 
            +
                  title: 'empty',
         | 
| 708 | 
            +
                  story: [],
         | 
| 709 | 
            +
                  journal: []
         | 
| 710 | 
            +
                };
         | 
| 711 | 
            +
              };
         | 
| 712 | 
            +
             | 
| 713 | 
            +
              util.getSelectionPos = function(jQueryElement) {
         | 
| 714 | 
            +
                var el, iePos, sel;
         | 
| 715 | 
            +
                el = jQueryElement.get(0);
         | 
| 716 | 
            +
                if (document.selection) {
         | 
| 717 | 
            +
                  el.focus();
         | 
| 718 | 
            +
                  sel = document.selection.createRange();
         | 
| 719 | 
            +
                  sel.moveStart('character', -el.value.length);
         | 
| 720 | 
            +
                  iePos = sel.text.length;
         | 
| 721 | 
            +
                  return {
         | 
| 722 | 
            +
                    start: iePos,
         | 
| 723 | 
            +
                    end: iePos
         | 
| 724 | 
            +
                  };
         | 
| 725 | 
            +
                } else {
         | 
| 726 | 
            +
                  return {
         | 
| 727 | 
            +
                    start: el.selectionStart,
         | 
| 728 | 
            +
                    end: el.selectionEnd
         | 
| 729 | 
            +
                  };
         | 
| 730 | 
            +
                }
         | 
| 731 | 
            +
              };
         | 
| 732 | 
            +
             | 
| 733 | 
            +
              util.setCaretPosition = function(jQueryElement, caretPos) {
         | 
| 734 | 
            +
                var el, range;
         | 
| 735 | 
            +
                el = jQueryElement.get(0);
         | 
| 736 | 
            +
                if (el != null) {
         | 
| 737 | 
            +
                  if (el.createTextRange) {
         | 
| 738 | 
            +
                    range = el.createTextRange();
         | 
| 739 | 
            +
                    range.move("character", caretPos);
         | 
| 740 | 
            +
                    range.select();
         | 
| 741 | 
            +
                  } else {
         | 
| 742 | 
            +
                    el.setSelectionRange(caretPos, caretPos);
         | 
| 743 | 
            +
                  }
         | 
| 744 | 
            +
                  return el.focus();
         | 
| 745 | 
            +
                }
         | 
| 746 | 
            +
              };
         | 
| 747 | 
            +
             | 
| 748 | 
            +
            }).call(this);
         | 
| 749 | 
            +
             | 
| 750 | 
            +
            },{"./wiki":2}],8:[function(require,module,exports){
         | 
| 751 | 
            +
            (function() {
         | 
| 752 | 
            +
              var getScript, plugin, scripts, util, wiki;
         | 
| 753 | 
            +
             | 
| 754 | 
            +
              util = require('./util');
         | 
| 755 | 
            +
             | 
| 756 | 
            +
              wiki = require('./wiki');
         | 
| 757 | 
            +
             | 
| 758 | 
            +
              module.exports = plugin = {};
         | 
| 759 | 
            +
             | 
| 760 | 
            +
              scripts = {};
         | 
| 761 | 
            +
             | 
| 762 | 
            +
              getScript = wiki.getScript = function(url, callback) {
         | 
| 763 | 
            +
                if (callback == null) {
         | 
| 764 | 
            +
                  callback = function() {};
         | 
| 765 | 
            +
                }
         | 
| 766 | 
            +
                if (scripts[url] != null) {
         | 
| 767 | 
            +
                  return callback();
         | 
| 768 | 
            +
                } else {
         | 
| 769 | 
            +
                  return $.getScript(url).done(function() {
         | 
| 770 | 
            +
                    scripts[url] = true;
         | 
| 771 | 
            +
                    return callback();
         | 
| 772 | 
            +
                  }).fail(function() {
         | 
| 773 | 
            +
                    return callback();
         | 
| 774 | 
            +
                  });
         | 
| 775 | 
            +
                }
         | 
| 776 | 
            +
              };
         | 
| 777 | 
            +
             | 
| 778 | 
            +
              plugin.get = wiki.getPlugin = function(name, callback) {
         | 
| 779 | 
            +
                if (window.plugins[name]) {
         | 
| 780 | 
            +
                  return callback(window.plugins[name]);
         | 
| 781 | 
            +
                }
         | 
| 782 | 
            +
                return getScript("/plugins/" + name + "/" + name + ".js", function() {
         | 
| 783 | 
            +
                  if (window.plugins[name]) {
         | 
| 784 | 
            +
                    return callback(window.plugins[name]);
         | 
| 785 | 
            +
                  }
         | 
| 786 | 
            +
                  return getScript("/plugins/" + name + ".js", function() {
         | 
| 787 | 
            +
                    return callback(window.plugins[name]);
         | 
| 788 | 
            +
                  });
         | 
| 789 | 
            +
                });
         | 
| 790 | 
            +
              };
         | 
| 791 | 
            +
             | 
| 792 | 
            +
              plugin["do"] = wiki.doPlugin = function(div, item, done) {
         | 
| 793 | 
            +
                var error;
         | 
| 794 | 
            +
                if (done == null) {
         | 
| 795 | 
            +
                  done = function() {};
         | 
| 796 | 
            +
                }
         | 
| 797 | 
            +
                error = function(ex) {
         | 
| 798 | 
            +
                  var errorElement;
         | 
| 799 | 
            +
                  errorElement = $("<div />").addClass('error');
         | 
| 800 | 
            +
                  errorElement.text(ex.toString());
         | 
| 801 | 
            +
                  return div.append(errorElement);
         | 
| 802 | 
            +
                };
         | 
| 803 | 
            +
                div.data('pageElement', div.parents(".page"));
         | 
| 804 | 
            +
                div.data('item', item);
         | 
| 805 | 
            +
                return plugin.get(item.type, function(script) {
         | 
| 806 | 
            +
                  var err;
         | 
| 807 | 
            +
                  try {
         | 
| 808 | 
            +
                    if (script == null) {
         | 
| 809 | 
            +
                      throw TypeError("Can't find plugin for '" + item.type + "'");
         | 
| 810 | 
            +
                    }
         | 
| 811 | 
            +
                    if (script.emit.length > 2) {
         | 
| 812 | 
            +
                      return script.emit(div, item, function() {
         | 
| 813 | 
            +
                        script.bind(div, item);
         | 
| 814 | 
            +
                        return done();
         | 
| 815 | 
            +
                      });
         | 
| 816 | 
            +
                    } else {
         | 
| 817 | 
            +
                      script.emit(div, item);
         | 
| 818 | 
            +
                      script.bind(div, item);
         | 
| 819 | 
            +
                      return done();
         | 
| 820 | 
            +
                    }
         | 
| 821 | 
            +
                  } catch (_error) {
         | 
| 822 | 
            +
                    err = _error;
         | 
| 823 | 
            +
                    wiki.log('plugin error', err);
         | 
| 824 | 
            +
                    error(err);
         | 
| 825 | 
            +
                    return done();
         | 
| 826 | 
            +
                  }
         | 
| 827 | 
            +
                });
         | 
| 828 | 
            +
              };
         | 
| 829 | 
            +
             | 
| 830 | 
            +
              wiki.registerPlugin = function(pluginName, pluginFn) {
         | 
| 831 | 
            +
                return window.plugins[pluginName] = pluginFn($);
         | 
| 832 | 
            +
              };
         | 
| 833 | 
            +
             | 
| 834 | 
            +
              window.plugins = {
         | 
| 835 | 
            +
                reference: require('./reference'),
         | 
| 836 | 
            +
                factory: require('./factory'),
         | 
| 837 | 
            +
                paragraph: {
         | 
| 838 | 
            +
                  emit: function(div, item) {
         | 
| 839 | 
            +
                    var text, _i, _len, _ref, _results;
         | 
| 840 | 
            +
                    _ref = item.text.split(/\n\n+/);
         | 
| 841 | 
            +
                    _results = [];
         | 
| 842 | 
            +
                    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         | 
| 843 | 
            +
                      text = _ref[_i];
         | 
| 844 | 
            +
                      if (text.match(/\S/)) {
         | 
| 845 | 
            +
                        _results.push(div.append("<p>" + (wiki.resolveLinks(text)) + "</p>"));
         | 
| 846 | 
            +
                      } else {
         | 
| 847 | 
            +
                        _results.push(void 0);
         | 
| 848 | 
            +
                      }
         | 
| 849 | 
            +
                    }
         | 
| 850 | 
            +
                    return _results;
         | 
| 851 | 
            +
                  },
         | 
| 852 | 
            +
                  bind: function(div, item) {
         | 
| 853 | 
            +
                    return div.dblclick(function() {
         | 
| 854 | 
            +
                      return wiki.textEditor(div, item, null, true);
         | 
| 855 | 
            +
                    });
         | 
| 856 | 
            +
                  }
         | 
| 857 | 
            +
                },
         | 
| 858 | 
            +
                image: {
         | 
| 859 | 
            +
                  emit: function(div, item) {
         | 
| 860 | 
            +
                    item.text || (item.text = item.caption);
         | 
| 861 | 
            +
                    return div.append("<img class=thumbnail src=\"" + item.url + "\"> <p>" + (wiki.resolveLinks(item.text)) + "</p>");
         | 
| 862 | 
            +
                  },
         | 
| 863 | 
            +
                  bind: function(div, item) {
         | 
| 864 | 
            +
                    div.dblclick(function() {
         | 
| 865 | 
            +
                      return wiki.textEditor(div, item);
         | 
| 866 | 
            +
                    });
         | 
| 867 | 
            +
                    return div.find('img').dblclick(function() {
         | 
| 868 | 
            +
                      return wiki.dialog(item.text, this);
         | 
| 869 | 
            +
                    });
         | 
| 870 | 
            +
                  }
         | 
| 871 | 
            +
                },
         | 
| 872 | 
            +
                future: {
         | 
| 873 | 
            +
                  emit: function(div, item) {
         | 
| 874 | 
            +
                    var info, _i, _len, _ref, _results;
         | 
| 875 | 
            +
                    div.append("" + item.text + "<br><br><button class=\"create\">create</button> new blank page");
         | 
| 876 | 
            +
                    if (((info = wiki.neighborhood[location.host]) != null) && (info.sitemap != null)) {
         | 
| 877 | 
            +
                      _ref = info.sitemap;
         | 
| 878 | 
            +
                      _results = [];
         | 
| 879 | 
            +
                      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         | 
| 880 | 
            +
                        item = _ref[_i];
         | 
| 881 | 
            +
                        if (item.slug.match(/-template$/)) {
         | 
| 882 | 
            +
                          _results.push(div.append("<br><button class=\"create\" data-slug=" + item.slug + ">create</button> from " + (wiki.resolveLinks("[[" + item.title + "]]"))));
         | 
| 883 | 
            +
                        } else {
         | 
| 884 | 
            +
                          _results.push(void 0);
         | 
| 885 | 
            +
                        }
         | 
| 886 | 
            +
                      }
         | 
| 887 | 
            +
                      return _results;
         | 
| 888 | 
            +
                    }
         | 
| 889 | 
            +
                  },
         | 
| 890 | 
            +
                  bind: function(div, item) {}
         | 
| 891 | 
            +
                }
         | 
| 892 | 
            +
              };
         | 
| 893 | 
            +
             | 
| 894 | 
            +
            }).call(this);
         | 
| 895 | 
            +
             | 
| 896 | 
            +
            },{"./factory":14,"./reference":13,"./util":6,"./wiki":2}],9:[function(require,module,exports){
         | 
| 897 | 
            +
            (function() {
         | 
| 898 | 
            +
              var active, state, wiki,
         | 
| 899 | 
            +
                __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
         | 
| 900 | 
            +
             | 
| 901 | 
            +
              wiki = require('./wiki');
         | 
| 902 | 
            +
             | 
| 903 | 
            +
              active = require('./active');
         | 
| 904 | 
            +
             | 
| 905 | 
            +
              module.exports = state = {};
         | 
| 906 | 
            +
             | 
| 907 | 
            +
              state.pagesInDom = function() {
         | 
| 908 | 
            +
                return $.makeArray($(".page").map(function(_, el) {
         | 
| 909 | 
            +
                  return el.id;
         | 
| 910 | 
            +
                }));
         | 
| 911 | 
            +
              };
         | 
| 912 | 
            +
             | 
| 913 | 
            +
              state.urlPages = function() {
         | 
| 914 | 
            +
                var i;
         | 
| 915 | 
            +
                return ((function() {
         | 
| 916 | 
            +
                  var _i, _len, _ref, _results;
         | 
| 917 | 
            +
                  _ref = $(location).attr('pathname').split('/');
         | 
| 918 | 
            +
                  _results = [];
         | 
| 919 | 
            +
                  for (_i = 0, _len = _ref.length; _i < _len; _i += 2) {
         | 
| 920 | 
            +
                    i = _ref[_i];
         | 
| 921 | 
            +
                    _results.push(i);
         | 
| 922 | 
            +
                  }
         | 
| 923 | 
            +
                  return _results;
         | 
| 924 | 
            +
                })()).slice(1);
         | 
| 925 | 
            +
              };
         | 
| 926 | 
            +
             | 
| 927 | 
            +
              state.locsInDom = function() {
         | 
| 928 | 
            +
                return $.makeArray($(".page").map(function(_, el) {
         | 
| 929 | 
            +
                  return $(el).data('site') || 'view';
         | 
| 930 | 
            +
                }));
         | 
| 931 | 
            +
              };
         | 
| 932 | 
            +
             | 
| 933 | 
            +
              state.urlLocs = function() {
         | 
| 934 | 
            +
                var j, _i, _len, _ref, _results;
         | 
| 935 | 
            +
                _ref = $(location).attr('pathname').split('/').slice(1);
         | 
| 936 | 
            +
                _results = [];
         | 
| 937 | 
            +
                for (_i = 0, _len = _ref.length; _i < _len; _i += 2) {
         | 
| 938 | 
            +
                  j = _ref[_i];
         | 
| 939 | 
            +
                  _results.push(j);
         | 
| 940 | 
            +
                }
         | 
| 941 | 
            +
                return _results;
         | 
| 942 | 
            +
              };
         | 
| 943 | 
            +
             | 
| 944 | 
            +
              state.setUrl = function() {
         | 
| 945 | 
            +
                var idx, locs, page, pages, url, _ref;
         | 
| 946 | 
            +
                document.title = (_ref = $('.page:last').data('data')) != null ? _ref.title : void 0;
         | 
| 947 | 
            +
                if (history && history.pushState) {
         | 
| 948 | 
            +
                  locs = state.locsInDom();
         | 
| 949 | 
            +
                  pages = state.pagesInDom();
         | 
| 950 | 
            +
                  url = ((function() {
         | 
| 951 | 
            +
                    var _i, _len, _results;
         | 
| 952 | 
            +
                    _results = [];
         | 
| 953 | 
            +
                    for (idx = _i = 0, _len = pages.length; _i < _len; idx = ++_i) {
         | 
| 954 | 
            +
                      page = pages[idx];
         | 
| 955 | 
            +
                      _results.push("/" + ((locs != null ? locs[idx] : void 0) || 'view') + "/" + page);
         | 
| 956 | 
            +
                    }
         | 
| 957 | 
            +
                    return _results;
         | 
| 958 | 
            +
                  })()).join('');
         | 
| 959 | 
            +
                  if (url !== $(location).attr('pathname')) {
         | 
| 960 | 
            +
                    return history.pushState(null, null, url);
         | 
| 961 | 
            +
                  }
         | 
| 962 | 
            +
                }
         | 
| 963 | 
            +
              };
         | 
| 964 | 
            +
             | 
| 965 | 
            +
              state.show = function(e) {
         | 
| 966 | 
            +
                var idx, name, newLocs, newPages, old, oldLocs, oldPages, previous, _i, _len, _ref;
         | 
| 967 | 
            +
                oldPages = state.pagesInDom();
         | 
| 968 | 
            +
                newPages = state.urlPages();
         | 
| 969 | 
            +
                oldLocs = state.locsInDom();
         | 
| 970 | 
            +
                newLocs = state.urlLocs();
         | 
| 971 | 
            +
                if (!location.pathname || location.pathname === '/') {
         | 
| 972 | 
            +
                  return;
         | 
| 973 | 
            +
                }
         | 
| 974 | 
            +
                previous = $('.page').eq(0);
         | 
| 975 | 
            +
                for (idx = _i = 0, _len = newPages.length; _i < _len; idx = ++_i) {
         | 
| 976 | 
            +
                  name = newPages[idx];
         | 
| 977 | 
            +
                  if (name !== oldPages[idx]) {
         | 
| 978 | 
            +
                    old = $('.page').eq(idx);
         | 
| 979 | 
            +
                    if (old) {
         | 
| 980 | 
            +
                      old.remove();
         | 
| 981 | 
            +
                    }
         | 
| 982 | 
            +
                    wiki.createPage(name, newLocs[idx]).insertAfter(previous).each(wiki.refresh);
         | 
| 983 | 
            +
                  }
         | 
| 984 | 
            +
                  previous = $('.page').eq(idx);
         | 
| 985 | 
            +
                }
         | 
| 986 | 
            +
                previous.nextAll().remove();
         | 
| 987 | 
            +
                active.set($('.page').last());
         | 
| 988 | 
            +
                return document.title = (_ref = $('.page:last').data('data')) != null ? _ref.title : void 0;
         | 
| 989 | 
            +
              };
         | 
| 990 | 
            +
             | 
| 991 | 
            +
              state.first = function() {
         | 
| 992 | 
            +
                var firstUrlLocs, firstUrlPages, idx, oldPages, urlPage, _i, _len, _results;
         | 
| 993 | 
            +
                state.setUrl();
         | 
| 994 | 
            +
                firstUrlPages = state.urlPages();
         | 
| 995 | 
            +
                firstUrlLocs = state.urlLocs();
         | 
| 996 | 
            +
                oldPages = state.pagesInDom();
         | 
| 997 | 
            +
                _results = [];
         | 
| 998 | 
            +
                for (idx = _i = 0, _len = firstUrlPages.length; _i < _len; idx = ++_i) {
         | 
| 999 | 
            +
                  urlPage = firstUrlPages[idx];
         | 
| 1000 | 
            +
                  if (__indexOf.call(oldPages, urlPage) < 0) {
         | 
| 1001 | 
            +
                    if (urlPage !== '') {
         | 
| 1002 | 
            +
                      _results.push(wiki.createPage(urlPage, firstUrlLocs[idx]).appendTo('.main'));
         | 
| 1003 | 
            +
                    } else {
         | 
| 1004 | 
            +
                      _results.push(void 0);
         | 
| 1005 | 
            +
                    }
         | 
| 1006 | 
            +
                  }
         | 
| 1007 | 
            +
                }
         | 
| 1008 | 
            +
                return _results;
         | 
| 1009 | 
            +
              };
         | 
| 1010 | 
            +
             | 
| 1011 | 
            +
            }).call(this);
         | 
| 1012 | 
            +
             | 
| 1013 | 
            +
            },{"./active":10,"./wiki":2}],15:[function(require,module,exports){
         | 
| 1014 | 
            +
            (function() {
         | 
| 1015 | 
            +
              var create;
         | 
| 1016 | 
            +
             | 
| 1017 | 
            +
              create = function(revIndex, data) {
         | 
| 1018 | 
            +
                var afterIndex, editIndex, itemId, items, journal, journalEntry, removeIndex, revJournal, revStory, revStoryIds, revTitle, storyItem, _i, _j, _k, _len, _len1, _len2, _ref;
         | 
| 1019 | 
            +
                journal = data.journal;
         | 
| 1020 | 
            +
                revTitle = data.title;
         | 
| 1021 | 
            +
                revStory = [];
         | 
| 1022 | 
            +
                revJournal = journal.slice(0, +(+revIndex) + 1 || 9e9);
         | 
| 1023 | 
            +
                for (_i = 0, _len = revJournal.length; _i < _len; _i++) {
         | 
| 1024 | 
            +
                  journalEntry = revJournal[_i];
         | 
| 1025 | 
            +
                  revStoryIds = revStory.map(function(storyItem) {
         | 
| 1026 | 
            +
                    return storyItem.id;
         | 
| 1027 | 
            +
                  });
         | 
| 1028 | 
            +
                  switch (journalEntry.type) {
         | 
| 1029 | 
            +
                    case 'create':
         | 
| 1030 | 
            +
                      if (journalEntry.item.title != null) {
         | 
| 1031 | 
            +
                        revTitle = journalEntry.item.title;
         | 
| 1032 | 
            +
                        revStory = journalEntry.item.story || [];
         | 
| 1033 | 
            +
                      }
         | 
| 1034 | 
            +
                      break;
         | 
| 1035 | 
            +
                    case 'add':
         | 
| 1036 | 
            +
                      if ((afterIndex = revStoryIds.indexOf(journalEntry.after)) !== -1) {
         | 
| 1037 | 
            +
                        revStory.splice(afterIndex + 1, 0, journalEntry.item);
         | 
| 1038 | 
            +
                      } else {
         | 
| 1039 | 
            +
                        revStory.push(journalEntry.item);
         | 
| 1040 | 
            +
                      }
         | 
| 1041 | 
            +
                      break;
         | 
| 1042 | 
            +
                    case 'edit':
         | 
| 1043 | 
            +
                      if ((editIndex = revStoryIds.indexOf(journalEntry.id)) !== -1) {
         | 
| 1044 | 
            +
                        revStory.splice(editIndex, 1, journalEntry.item);
         | 
| 1045 | 
            +
                      } else {
         | 
| 1046 | 
            +
                        revStory.push(journalEntry.item);
         | 
| 1047 | 
            +
                      }
         | 
| 1048 | 
            +
                      break;
         | 
| 1049 | 
            +
                    case 'move':
         | 
| 1050 | 
            +
                      items = {};
         | 
| 1051 | 
            +
                      for (_j = 0, _len1 = revStory.length; _j < _len1; _j++) {
         | 
| 1052 | 
            +
                        storyItem = revStory[_j];
         | 
| 1053 | 
            +
                        items[storyItem.id] = storyItem;
         | 
| 1054 | 
            +
                      }
         | 
| 1055 | 
            +
                      revStory = [];
         | 
| 1056 | 
            +
                      _ref = journalEntry.order;
         | 
| 1057 | 
            +
                      for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) {
         | 
| 1058 | 
            +
                        itemId = _ref[_k];
         | 
| 1059 | 
            +
                        if (items[itemId] != null) {
         | 
| 1060 | 
            +
                          revStory.push(items[itemId]);
         | 
| 1061 | 
            +
                        }
         | 
| 1062 | 
            +
                      }
         | 
| 1063 | 
            +
                      break;
         | 
| 1064 | 
            +
                    case 'remove':
         | 
| 1065 | 
            +
                      if ((removeIndex = revStoryIds.indexOf(journalEntry.id)) !== -1) {
         | 
| 1066 | 
            +
                        revStory.splice(removeIndex, 1);
         | 
| 1067 | 
            +
                      }
         | 
| 1068 | 
            +
                  }
         | 
| 1069 | 
            +
                }
         | 
| 1070 | 
            +
                return {
         | 
| 1071 | 
            +
                  story: revStory,
         | 
| 1072 | 
            +
                  journal: revJournal,
         | 
| 1073 | 
            +
                  title: revTitle
         | 
| 1074 | 
            +
                };
         | 
| 1075 | 
            +
              };
         | 
| 1076 | 
            +
             | 
| 1077 | 
            +
              exports.create = create;
         | 
| 1078 | 
            +
             | 
| 1079 | 
            +
            }).call(this);
         | 
| 1080 | 
            +
             | 
| 1081 | 
            +
            },{}],13:[function(require,module,exports){
         | 
| 1082 | 
            +
            (function() {
         | 
| 1083 | 
            +
              var bind, emit;
         | 
| 1084 | 
            +
             | 
| 1085 | 
            +
              emit = function($item, item) {
         | 
| 1086 | 
            +
                var site, slug;
         | 
| 1087 | 
            +
                slug = item.slug || 'welcome-visitors';
         | 
| 1088 | 
            +
                site = item.site;
         | 
| 1089 | 
            +
                return wiki.resolveFrom(site, function() {
         | 
| 1090 | 
            +
                  return $item.append("<p style='margin-bottom:3px;'>\n  <img class='remote'\n    src='//" + site + "/favicon.png'\n    title='" + site + "'\n    data-site=\"" + site + "\"\n    data-slug=\"" + slug + "\"\n  >\n  " + (wiki.resolveLinks("[[" + (item.title || slug) + "]]")) + "\n</p>\n<div>\n  " + (wiki.resolveLinks(item.text)) + "\n</div>");
         | 
| 1091 | 
            +
                });
         | 
| 1092 | 
            +
              };
         | 
| 1093 | 
            +
             | 
| 1094 | 
            +
              bind = function($item, item) {
         | 
| 1095 | 
            +
                return $item.dblclick(function() {
         | 
| 1096 | 
            +
                  return wiki.textEditor($item, item);
         | 
| 1097 | 
            +
                });
         | 
| 1098 | 
            +
              };
         | 
| 1099 | 
            +
             | 
| 1100 | 
            +
              module.exports = {
         | 
| 1101 | 
            +
                emit: emit,
         | 
| 1102 | 
            +
                bind: bind
         | 
| 1103 | 
            +
              };
         | 
| 1104 | 
            +
             | 
| 1105 | 
            +
            }).call(this);
         | 
| 1106 | 
            +
             | 
| 1107 | 
            +
            },{}],14:[function(require,module,exports){
         | 
| 1108 | 
            +
            (function() {
         | 
| 1109 | 
            +
              var arrayToJson, bind, csvToArray, emit,
         | 
| 1110 | 
            +
                __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
         | 
| 1111 | 
            +
             | 
| 1112 | 
            +
              emit = function(div, item) {
         | 
| 1113 | 
            +
                var showMenu, showPrompt;
         | 
| 1114 | 
            +
                div.append('<p>Double-Click to Edit<br>Drop Text or Image to Insert</p>');
         | 
| 1115 | 
            +
                showMenu = function() {
         | 
| 1116 | 
            +
                  var info, menu, menuItem, name, _i, _len, _ref, _ref1;
         | 
| 1117 | 
            +
                  menu = div.find('p').append("<br>Or Choose a Plugin");
         | 
| 1118 | 
            +
                  menuItem = function(title, name) {
         | 
| 1119 | 
            +
                    return menu.append("<li><a class=\"menu\" href=\"#\" title=\"" + title + "\">" + name + "</a></li>");
         | 
| 1120 | 
            +
                  };
         | 
| 1121 | 
            +
                  if (Array.isArray(window.catalog)) {
         | 
| 1122 | 
            +
                    _ref = window.catalog;
         | 
| 1123 | 
            +
                    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         | 
| 1124 | 
            +
                      info = _ref[_i];
         | 
| 1125 | 
            +
                      menuItem(info.title, info.name);
         | 
| 1126 | 
            +
                    }
         | 
| 1127 | 
            +
                  } else {
         | 
| 1128 | 
            +
                    _ref1 = window.catalog;
         | 
| 1129 | 
            +
                    for (name in _ref1) {
         | 
| 1130 | 
            +
                      info = _ref1[name];
         | 
| 1131 | 
            +
                      menuItem(info.menu, name);
         | 
| 1132 | 
            +
                    }
         | 
| 1133 | 
            +
                  }
         | 
| 1134 | 
            +
                  return menu.find('a.menu').click(function(evt) {
         | 
| 1135 | 
            +
                    div.removeClass('factory').addClass(item.type = evt.target.text.toLowerCase());
         | 
| 1136 | 
            +
                    div.unbind();
         | 
| 1137 | 
            +
                    return wiki.textEditor(div, item);
         | 
| 1138 | 
            +
                  });
         | 
| 1139 | 
            +
                };
         | 
| 1140 | 
            +
                showPrompt = function() {
         | 
| 1141 | 
            +
                  return div.append("<p>" + (wiki.resolveLinks(item.prompt)) + "</b>");
         | 
| 1142 | 
            +
                };
         | 
| 1143 | 
            +
                if (item.prompt) {
         | 
| 1144 | 
            +
                  return showPrompt();
         | 
| 1145 | 
            +
                } else if (window.catalog != null) {
         | 
| 1146 | 
            +
                  return showMenu();
         | 
| 1147 | 
            +
                } else {
         | 
| 1148 | 
            +
                  return $.getJSON('/system/factories.json', function(data) {
         | 
| 1149 | 
            +
                    window.catalog = data;
         | 
| 1150 | 
            +
                    return showMenu();
         | 
| 1151 | 
            +
                  });
         | 
| 1152 | 
            +
                }
         | 
| 1153 | 
            +
              };
         | 
| 1154 | 
            +
             | 
| 1155 | 
            +
              bind = function(div, item) {
         | 
| 1156 | 
            +
                var syncEditAction;
         | 
| 1157 | 
            +
                syncEditAction = function() {
         | 
| 1158 | 
            +
                  var err, pageElement;
         | 
| 1159 | 
            +
                  wiki.log('factory item', item);
         | 
| 1160 | 
            +
                  div.empty().unbind();
         | 
| 1161 | 
            +
                  div.removeClass("factory").addClass(item.type);
         | 
| 1162 | 
            +
                  pageElement = div.parents('.page:first');
         | 
| 1163 | 
            +
                  try {
         | 
| 1164 | 
            +
                    div.data('pageElement', pageElement);
         | 
| 1165 | 
            +
                    div.data('item', item);
         | 
| 1166 | 
            +
                    wiki.getPlugin(item.type, function(plugin) {
         | 
| 1167 | 
            +
                      plugin.emit(div, item);
         | 
| 1168 | 
            +
                      return plugin.bind(div, item);
         | 
| 1169 | 
            +
                    });
         | 
| 1170 | 
            +
                  } catch (_error) {
         | 
| 1171 | 
            +
                    err = _error;
         | 
| 1172 | 
            +
                    div.append("<p class='error'>" + err + "</p>");
         | 
| 1173 | 
            +
                  }
         | 
| 1174 | 
            +
                  return wiki.pageHandler.put(pageElement, {
         | 
| 1175 | 
            +
                    type: 'edit',
         | 
| 1176 | 
            +
                    id: item.id,
         | 
| 1177 | 
            +
                    item: item
         | 
| 1178 | 
            +
                  });
         | 
| 1179 | 
            +
                };
         | 
| 1180 | 
            +
                div.dblclick(function() {
         | 
| 1181 | 
            +
                  div.removeClass('factory').addClass(item.type = 'paragraph');
         | 
| 1182 | 
            +
                  div.unbind();
         | 
| 1183 | 
            +
                  return wiki.textEditor(div, item);
         | 
| 1184 | 
            +
                });
         | 
| 1185 | 
            +
                div.bind('dragenter', function(evt) {
         | 
| 1186 | 
            +
                  return evt.preventDefault();
         | 
| 1187 | 
            +
                });
         | 
| 1188 | 
            +
                div.bind('dragover', function(evt) {
         | 
| 1189 | 
            +
                  return evt.preventDefault();
         | 
| 1190 | 
            +
                });
         | 
| 1191 | 
            +
                return div.bind("drop", function(dropEvent) {
         | 
| 1192 | 
            +
                  var dt, found, ignore, origin, punt, readFile, url;
         | 
| 1193 | 
            +
                  punt = function(data) {
         | 
| 1194 | 
            +
                    item.prompt = "<b>Unexpected Item</b><br>We can't make sense of the drop.<br>" + (JSON.stringify(data)) + "<br>Try something else or see [[About Factory Plugin]].";
         | 
| 1195 | 
            +
                    data.userAgent = navigator.userAgent;
         | 
| 1196 | 
            +
                    item.punt = data;
         | 
| 1197 | 
            +
                    wiki.log('factory punt', dropEvent);
         | 
| 1198 | 
            +
                    return syncEditAction();
         | 
| 1199 | 
            +
                  };
         | 
| 1200 | 
            +
                  readFile = function(file) {
         | 
| 1201 | 
            +
                    var majorType, minorType, reader, _ref;
         | 
| 1202 | 
            +
                    if (file != null) {
         | 
| 1203 | 
            +
                      _ref = file.type.split("/"), majorType = _ref[0], minorType = _ref[1];
         | 
| 1204 | 
            +
                      reader = new FileReader();
         | 
| 1205 | 
            +
                      if (majorType === "image") {
         | 
| 1206 | 
            +
                        reader.onload = function(loadEvent) {
         | 
| 1207 | 
            +
                          item.type = 'image';
         | 
| 1208 | 
            +
                          item.url = loadEvent.target.result;
         | 
| 1209 | 
            +
                          item.caption || (item.caption = "Uploaded image");
         | 
| 1210 | 
            +
                          return syncEditAction();
         | 
| 1211 | 
            +
                        };
         | 
| 1212 | 
            +
                        return reader.readAsDataURL(file);
         | 
| 1213 | 
            +
                      } else if (majorType === "text") {
         | 
| 1214 | 
            +
                        reader.onload = function(loadEvent) {
         | 
| 1215 | 
            +
                          var array, result;
         | 
| 1216 | 
            +
                          result = loadEvent.target.result;
         | 
| 1217 | 
            +
                          if (minorType === 'csv') {
         | 
| 1218 | 
            +
                            item.type = 'data';
         | 
| 1219 | 
            +
                            item.columns = (array = csvToArray(result))[0];
         | 
| 1220 | 
            +
                            item.data = arrayToJson(array);
         | 
| 1221 | 
            +
                            item.text = file.fileName;
         | 
| 1222 | 
            +
                          } else {
         | 
| 1223 | 
            +
                            item.type = 'paragraph';
         | 
| 1224 | 
            +
                            item.text = result;
         | 
| 1225 | 
            +
                          }
         | 
| 1226 | 
            +
                          return syncEditAction();
         | 
| 1227 | 
            +
                        };
         | 
| 1228 | 
            +
                        return reader.readAsText(file);
         | 
| 1229 | 
            +
                      } else {
         | 
| 1230 | 
            +
                        return punt({
         | 
| 1231 | 
            +
                          number: 1,
         | 
| 1232 | 
            +
                          name: file.fileName,
         | 
| 1233 | 
            +
                          type: file.type
         | 
| 1234 | 
            +
                        });
         | 
| 1235 | 
            +
                      }
         | 
| 1236 | 
            +
                    } else {
         | 
| 1237 | 
            +
                      return punt({
         | 
| 1238 | 
            +
                        number: 2,
         | 
| 1239 | 
            +
                        types: dropEvent.originalEvent.dataTransfer.types
         | 
| 1240 | 
            +
                      });
         | 
| 1241 | 
            +
                    }
         | 
| 1242 | 
            +
                  };
         | 
| 1243 | 
            +
                  dropEvent.preventDefault();
         | 
| 1244 | 
            +
                  if ((dt = dropEvent.originalEvent.dataTransfer) != null) {
         | 
| 1245 | 
            +
                    if ((dt.types != null) && (__indexOf.call(dt.types, 'text/uri-list') >= 0 || __indexOf.call(dt.types, 'text/x-moz-url') >= 0) && !(__indexOf.call(dt.types, 'Files') >= 0)) {
         | 
| 1246 | 
            +
                      url = dt.getData('URL');
         | 
| 1247 | 
            +
                      if (found = url.match(/^http:\/\/([a-zA-Z0-9:.-]+)(\/([a-zA-Z0-9:.-]+)\/([a-z0-9-]+(_rev\d+)?))+$/)) {
         | 
| 1248 | 
            +
                        wiki.log('factory drop url', found);
         | 
| 1249 | 
            +
                        ignore = found[0], origin = found[1], ignore = found[2], item.site = found[3], item.slug = found[4], ignore = found[5];
         | 
| 1250 | 
            +
                        if ($.inArray(item.site, ['view', 'local', 'origin']) >= 0) {
         | 
| 1251 | 
            +
                          item.site = origin;
         | 
| 1252 | 
            +
                        }
         | 
| 1253 | 
            +
                        return $.getJSON("http://" + item.site + "/" + item.slug + ".json", function(remote) {
         | 
| 1254 | 
            +
                          wiki.log('factory remote', remote);
         | 
| 1255 | 
            +
                          item.type = 'reference';
         | 
| 1256 | 
            +
                          item.title = remote.title || item.slug;
         | 
| 1257 | 
            +
                          item.text = wiki.createSynopsis(remote);
         | 
| 1258 | 
            +
                          syncEditAction();
         | 
| 1259 | 
            +
                          if (item.site != null) {
         | 
| 1260 | 
            +
                            return wiki.registerNeighbor(item.site);
         | 
| 1261 | 
            +
                          }
         | 
| 1262 | 
            +
                        });
         | 
| 1263 | 
            +
                      } else {
         | 
| 1264 | 
            +
                        return punt({
         | 
| 1265 | 
            +
                          number: 4,
         | 
| 1266 | 
            +
                          url: url,
         | 
| 1267 | 
            +
                          types: dt.types
         | 
| 1268 | 
            +
                        });
         | 
| 1269 | 
            +
                      }
         | 
| 1270 | 
            +
                    } else if (__indexOf.call(dt.types, 'Files') >= 0) {
         | 
| 1271 | 
            +
                      return readFile(dt.files[0]);
         | 
| 1272 | 
            +
                    } else {
         | 
| 1273 | 
            +
                      return punt({
         | 
| 1274 | 
            +
                        number: 5,
         | 
| 1275 | 
            +
                        types: dt.types
         | 
| 1276 | 
            +
                      });
         | 
| 1277 | 
            +
                    }
         | 
| 1278 | 
            +
                  } else {
         | 
| 1279 | 
            +
                    return punt({
         | 
| 1280 | 
            +
                      number: 6,
         | 
| 1281 | 
            +
                      trouble: "no data transfer object"
         | 
| 1282 | 
            +
                    });
         | 
| 1283 | 
            +
                  }
         | 
| 1284 | 
            +
                });
         | 
| 1285 | 
            +
              };
         | 
| 1286 | 
            +
             | 
| 1287 | 
            +
              csvToArray = function(strData, strDelimiter) {
         | 
| 1288 | 
            +
                var arrData, arrMatches, objPattern, strMatchedDelimiter, strMatchedValue;
         | 
| 1289 | 
            +
                strDelimiter = strDelimiter || ",";
         | 
| 1290 | 
            +
                objPattern = new RegExp("(\\" + strDelimiter + "|\\r?\\n|\\r|^)" + "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" + "([^\"\\" + strDelimiter + "\\r\\n]*))", "gi");
         | 
| 1291 | 
            +
                arrData = [[]];
         | 
| 1292 | 
            +
                arrMatches = null;
         | 
| 1293 | 
            +
                while (arrMatches = objPattern.exec(strData)) {
         | 
| 1294 | 
            +
                  strMatchedDelimiter = arrMatches[1];
         | 
| 1295 | 
            +
                  if (strMatchedDelimiter.length && (strMatchedDelimiter !== strDelimiter)) {
         | 
| 1296 | 
            +
                    arrData.push([]);
         | 
| 1297 | 
            +
                  }
         | 
| 1298 | 
            +
                  if (arrMatches[2]) {
         | 
| 1299 | 
            +
                    strMatchedValue = arrMatches[2].replace(new RegExp("\"\"", "g"), "\"");
         | 
| 1300 | 
            +
                  } else {
         | 
| 1301 | 
            +
                    strMatchedValue = arrMatches[3];
         | 
| 1302 | 
            +
                  }
         | 
| 1303 | 
            +
                  arrData[arrData.length - 1].push(strMatchedValue);
         | 
| 1304 | 
            +
                }
         | 
| 1305 | 
            +
                return arrData;
         | 
| 1306 | 
            +
              };
         | 
| 1307 | 
            +
             | 
| 1308 | 
            +
              arrayToJson = function(array) {
         | 
| 1309 | 
            +
                var cols, row, rowToObject, _i, _len, _results;
         | 
| 1310 | 
            +
                cols = array.shift();
         | 
| 1311 | 
            +
                rowToObject = function(row) {
         | 
| 1312 | 
            +
                  var k, obj, v, _i, _len, _ref, _ref1;
         | 
| 1313 | 
            +
                  obj = {};
         | 
| 1314 | 
            +
                  _ref = _.zip(cols, row);
         | 
| 1315 | 
            +
                  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         | 
| 1316 | 
            +
                    _ref1 = _ref[_i], k = _ref1[0], v = _ref1[1];
         | 
| 1317 | 
            +
                    if ((v != null) && (v.match(/\S/)) && v !== 'NULL') {
         | 
| 1318 | 
            +
                      obj[k] = v;
         | 
| 1319 | 
            +
                    }
         | 
| 1320 | 
            +
                  }
         | 
| 1321 | 
            +
                  return obj;
         | 
| 1322 | 
            +
                };
         | 
| 1323 | 
            +
                _results = [];
         | 
| 1324 | 
            +
                for (_i = 0, _len = array.length; _i < _len; _i++) {
         | 
| 1325 | 
            +
                  row = array[_i];
         | 
| 1326 | 
            +
                  _results.push(rowToObject(row));
         | 
| 1327 | 
            +
                }
         | 
| 1328 | 
            +
                return _results;
         | 
| 1329 | 
            +
              };
         | 
| 1330 | 
            +
             | 
| 1331 | 
            +
              module.exports = {
         | 
| 1332 | 
            +
                emit: emit,
         | 
| 1333 | 
            +
                bind: bind
         | 
| 1334 | 
            +
              };
         | 
| 1335 | 
            +
             | 
| 1336 | 
            +
            }).call(this);
         | 
| 1337 | 
            +
             | 
| 1338 | 
            +
            },{}],16:[function(require,module,exports){
         | 
| 1339 | 
            +
            (function() {
         | 
| 1340 | 
            +
              var util;
         | 
| 1341 | 
            +
             | 
| 1342 | 
            +
              util = require('./util');
         | 
| 1343 | 
            +
             | 
| 1344 | 
            +
              module.exports = function(journalElement, action) {
         | 
| 1345 | 
            +
                var actionElement, actionTitle, controls, pageElement;
         | 
| 1346 | 
            +
                pageElement = journalElement.parents('.page:first');
         | 
| 1347 | 
            +
                actionTitle = action.type || 'separator';
         | 
| 1348 | 
            +
                if (action.date != null) {
         | 
| 1349 | 
            +
                  actionTitle += " " + (util.formatElapsedTime(action.date));
         | 
| 1350 | 
            +
                }
         | 
| 1351 | 
            +
                actionElement = $("<a href=\"#\" /> ").addClass("action").addClass(action.type || 'separator').text(action.symbol || util.symbols[action.type]).attr('title', actionTitle).attr('data-id', action.id || "0").data('action', action);
         | 
| 1352 | 
            +
                controls = journalElement.children('.control-buttons');
         | 
| 1353 | 
            +
                if (controls.length > 0) {
         | 
| 1354 | 
            +
                  actionElement.insertBefore(controls);
         | 
| 1355 | 
            +
                } else {
         | 
| 1356 | 
            +
                  actionElement.appendTo(journalElement);
         | 
| 1357 | 
            +
                }
         | 
| 1358 | 
            +
                if (action.type === 'fork' && (action.site != null)) {
         | 
| 1359 | 
            +
                  return actionElement.css("background-image", "url(//" + action.site + "/favicon.png)").attr("href", "//" + action.site + "/" + (pageElement.attr('id')) + ".html").data("site", action.site).data("slug", pageElement.attr('id'));
         | 
| 1360 | 
            +
                }
         | 
| 1361 | 
            +
              };
         | 
| 1362 | 
            +
             | 
| 1363 | 
            +
            }).call(this);
         | 
| 1364 | 
            +
             | 
| 1365 | 
            +
            },{"./util":6}],7:[function(require,module,exports){
         | 
| 1366 | 
            +
            (function() {
         | 
| 1367 | 
            +
              var addToJournal, newPage, pageFromLocalStorage, pageHandler, pushToLocal, pushToServer, recursiveGet, revision, state, util, wiki, _;
         | 
| 1368 | 
            +
             | 
| 1369 | 
            +
              _ = require('underscore');
         | 
| 1370 | 
            +
             | 
| 1371 | 
            +
              wiki = require('./wiki');
         | 
| 1372 | 
            +
             | 
| 1373 | 
            +
              util = require('./util');
         | 
| 1374 | 
            +
             | 
| 1375 | 
            +
              state = require('./state');
         | 
| 1376 | 
            +
             | 
| 1377 | 
            +
              revision = require('./revision');
         | 
| 1378 | 
            +
             | 
| 1379 | 
            +
              addToJournal = require('./addToJournal');
         | 
| 1380 | 
            +
             | 
| 1381 | 
            +
              newPage = require('./page').newPage;
         | 
| 1382 | 
            +
             | 
| 1383 | 
            +
              module.exports = pageHandler = {};
         | 
| 1384 | 
            +
             | 
| 1385 | 
            +
              pageFromLocalStorage = function(slug) {
         | 
| 1386 | 
            +
                var json;
         | 
| 1387 | 
            +
                if (json = localStorage[slug]) {
         | 
| 1388 | 
            +
                  return JSON.parse(json);
         | 
| 1389 | 
            +
                } else {
         | 
| 1390 | 
            +
                  return void 0;
         | 
| 1391 | 
            +
                }
         | 
| 1392 | 
            +
              };
         | 
| 1393 | 
            +
             | 
| 1394 | 
            +
              recursiveGet = function(_arg) {
         | 
| 1395 | 
            +
                var localContext, localPage, pageInformation, rev, site, slug, url, whenGotten, whenNotGotten;
         | 
| 1396 | 
            +
                pageInformation = _arg.pageInformation, whenGotten = _arg.whenGotten, whenNotGotten = _arg.whenNotGotten, localContext = _arg.localContext;
         | 
| 1397 | 
            +
                slug = pageInformation.slug, rev = pageInformation.rev, site = pageInformation.site;
         | 
| 1398 | 
            +
                if (site) {
         | 
| 1399 | 
            +
                  localContext = [];
         | 
| 1400 | 
            +
                } else {
         | 
| 1401 | 
            +
                  site = localContext.shift();
         | 
| 1402 | 
            +
                }
         | 
| 1403 | 
            +
                if (site === window.location.host) {
         | 
| 1404 | 
            +
                  site = 'origin';
         | 
| 1405 | 
            +
                }
         | 
| 1406 | 
            +
                if (site === 'view') {
         | 
| 1407 | 
            +
                  site = null;
         | 
| 1408 | 
            +
                }
         | 
| 1409 | 
            +
                if (site != null) {
         | 
| 1410 | 
            +
                  if (site === 'local') {
         | 
| 1411 | 
            +
                    if (localPage = pageFromLocalStorage(pageInformation.slug)) {
         | 
| 1412 | 
            +
                      return whenGotten(newPage(localPage, 'local'));
         | 
| 1413 | 
            +
                    } else {
         | 
| 1414 | 
            +
                      return whenNotGotten();
         | 
| 1415 | 
            +
                    }
         | 
| 1416 | 
            +
                  } else {
         | 
| 1417 | 
            +
                    if (site === 'origin') {
         | 
| 1418 | 
            +
                      url = "/" + slug + ".json";
         | 
| 1419 | 
            +
                    } else {
         | 
| 1420 | 
            +
                      url = "http://" + site + "/" + slug + ".json";
         | 
| 1421 | 
            +
                    }
         | 
| 1422 | 
            +
                  }
         | 
| 1423 | 
            +
                } else {
         | 
| 1424 | 
            +
                  url = "/" + slug + ".json";
         | 
| 1425 | 
            +
                }
         | 
| 1426 | 
            +
                return $.ajax({
         | 
| 1427 | 
            +
                  type: 'GET',
         | 
| 1428 | 
            +
                  dataType: 'json',
         | 
| 1429 | 
            +
                  url: url + ("?random=" + (util.randomBytes(4))),
         | 
| 1430 | 
            +
                  success: function(page) {
         | 
| 1431 | 
            +
                    if (rev) {
         | 
| 1432 | 
            +
                      page = revision.create(rev, page);
         | 
| 1433 | 
            +
                    }
         | 
| 1434 | 
            +
                    return whenGotten(newPage(page, site));
         | 
| 1435 | 
            +
                  },
         | 
| 1436 | 
            +
                  error: function(xhr, type, msg) {
         | 
| 1437 | 
            +
                    var report;
         | 
| 1438 | 
            +
                    if ((xhr.status !== 404) && (xhr.status !== 0)) {
         | 
| 1439 | 
            +
                      wiki.log('pageHandler.get error', xhr, xhr.status, type, msg);
         | 
| 1440 | 
            +
                      report = {
         | 
| 1441 | 
            +
                        'title': "" + xhr.status + " " + msg,
         | 
| 1442 | 
            +
                        'story': [
         | 
| 1443 | 
            +
                          {
         | 
| 1444 | 
            +
                            'type': 'paragraph',
         | 
| 1445 | 
            +
                            'id': '928739187243',
         | 
| 1446 | 
            +
                            'text': "<pre>" + xhr.responseText
         | 
| 1447 | 
            +
                          }
         | 
| 1448 | 
            +
                        ]
         | 
| 1449 | 
            +
                      };
         | 
| 1450 | 
            +
                      return whenGotten(report, 'local');
         | 
| 1451 | 
            +
                    }
         | 
| 1452 | 
            +
                    if (localContext.length > 0) {
         | 
| 1453 | 
            +
                      return recursiveGet({
         | 
| 1454 | 
            +
                        pageInformation: pageInformation,
         | 
| 1455 | 
            +
                        whenGotten: whenGotten,
         | 
| 1456 | 
            +
                        whenNotGotten: whenNotGotten,
         | 
| 1457 | 
            +
                        localContext: localContext
         | 
| 1458 | 
            +
                      });
         | 
| 1459 | 
            +
                    } else {
         | 
| 1460 | 
            +
                      return whenNotGotten();
         | 
| 1461 | 
            +
                    }
         | 
| 1462 | 
            +
                  }
         | 
| 1463 | 
            +
                });
         | 
| 1464 | 
            +
              };
         | 
| 1465 | 
            +
             | 
| 1466 | 
            +
              pageHandler.get = function(_arg) {
         | 
| 1467 | 
            +
                var localPage, pageInformation, whenGotten, whenNotGotten;
         | 
| 1468 | 
            +
                whenGotten = _arg.whenGotten, whenNotGotten = _arg.whenNotGotten, pageInformation = _arg.pageInformation;
         | 
| 1469 | 
            +
                if (!pageInformation.site) {
         | 
| 1470 | 
            +
                  if (localPage = pageFromLocalStorage(pageInformation.slug)) {
         | 
| 1471 | 
            +
                    if (pageInformation.rev) {
         | 
| 1472 | 
            +
                      localPage = revision.create(pageInformation.rev, localPage);
         | 
| 1473 | 
            +
                    }
         | 
| 1474 | 
            +
                    return whenGotten(newPage(localPage, 'local'));
         | 
| 1475 | 
            +
                  }
         | 
| 1476 | 
            +
                }
         | 
| 1477 | 
            +
                if (!pageHandler.context.length) {
         | 
| 1478 | 
            +
                  pageHandler.context = ['view'];
         | 
| 1479 | 
            +
                }
         | 
| 1480 | 
            +
                return recursiveGet({
         | 
| 1481 | 
            +
                  pageInformation: pageInformation,
         | 
| 1482 | 
            +
                  whenGotten: whenGotten,
         | 
| 1483 | 
            +
                  whenNotGotten: whenNotGotten,
         | 
| 1484 | 
            +
                  localContext: _.clone(pageHandler.context)
         | 
| 1485 | 
            +
                });
         | 
| 1486 | 
            +
              };
         | 
| 1487 | 
            +
             | 
| 1488 | 
            +
              pageHandler.context = [];
         | 
| 1489 | 
            +
             | 
| 1490 | 
            +
              pushToLocal = function(pageElement, pagePutInfo, action) {
         | 
| 1491 | 
            +
                var page, site;
         | 
| 1492 | 
            +
                if (action.type === 'create') {
         | 
| 1493 | 
            +
                  page = {
         | 
| 1494 | 
            +
                    title: action.item.title,
         | 
| 1495 | 
            +
                    story: [],
         | 
| 1496 | 
            +
                    journal: []
         | 
| 1497 | 
            +
                  };
         | 
| 1498 | 
            +
                } else {
         | 
| 1499 | 
            +
                  page = pageFromLocalStorage(pagePutInfo.slug);
         | 
| 1500 | 
            +
                  page || (page = pageElement.data("data"));
         | 
| 1501 | 
            +
                  if (page.journal == null) {
         | 
| 1502 | 
            +
                    page.journal = [];
         | 
| 1503 | 
            +
                  }
         | 
| 1504 | 
            +
                  if ((site = action['fork']) != null) {
         | 
| 1505 | 
            +
                    page.journal = page.journal.concat({
         | 
| 1506 | 
            +
                      'type': 'fork',
         | 
| 1507 | 
            +
                      'site': site
         | 
| 1508 | 
            +
                    });
         | 
| 1509 | 
            +
                    delete action['fork'];
         | 
| 1510 | 
            +
                  }
         | 
| 1511 | 
            +
                  page.story = $(pageElement).find(".item").map(function() {
         | 
| 1512 | 
            +
                    return $(this).data("item");
         | 
| 1513 | 
            +
                  }).get();
         | 
| 1514 | 
            +
                }
         | 
| 1515 | 
            +
                page.journal = page.journal.concat(action);
         | 
| 1516 | 
            +
                localStorage[pagePutInfo.slug] = JSON.stringify(page);
         | 
| 1517 | 
            +
                return addToJournal(pageElement.find('.journal'), action);
         | 
| 1518 | 
            +
              };
         | 
| 1519 | 
            +
             | 
| 1520 | 
            +
              pushToServer = function(pageElement, pagePutInfo, action) {
         | 
| 1521 | 
            +
                return $.ajax({
         | 
| 1522 | 
            +
                  type: 'PUT',
         | 
| 1523 | 
            +
                  url: "/page/" + pagePutInfo.slug + "/action",
         | 
| 1524 | 
            +
                  data: {
         | 
| 1525 | 
            +
                    'action': JSON.stringify(action)
         | 
| 1526 | 
            +
                  },
         | 
| 1527 | 
            +
                  success: function() {
         | 
| 1528 | 
            +
                    addToJournal(pageElement.find('.journal'), action);
         | 
| 1529 | 
            +
                    if (action.type === 'fork') {
         | 
| 1530 | 
            +
                      localStorage.removeItem(pageElement.attr('id'));
         | 
| 1531 | 
            +
                      return state.setUrl;
         | 
| 1532 | 
            +
                    }
         | 
| 1533 | 
            +
                  },
         | 
| 1534 | 
            +
                  error: function(xhr, type, msg) {
         | 
| 1535 | 
            +
                    return wiki.log("pageHandler.put ajax error callback", type, msg);
         | 
| 1536 | 
            +
                  }
         | 
| 1537 | 
            +
                });
         | 
| 1538 | 
            +
              };
         | 
| 1539 | 
            +
             | 
| 1540 | 
            +
              pageHandler.put = function(pageElement, action) {
         | 
| 1541 | 
            +
                var checkedSite, forkFrom, pagePutInfo;
         | 
| 1542 | 
            +
                checkedSite = function() {
         | 
| 1543 | 
            +
                  var site;
         | 
| 1544 | 
            +
                  switch (site = pageElement.data('site')) {
         | 
| 1545 | 
            +
                    case 'origin':
         | 
| 1546 | 
            +
                    case 'local':
         | 
| 1547 | 
            +
                    case 'view':
         | 
| 1548 | 
            +
                      return null;
         | 
| 1549 | 
            +
                    case location.host:
         | 
| 1550 | 
            +
                      return null;
         | 
| 1551 | 
            +
                    default:
         | 
| 1552 | 
            +
                      return site;
         | 
| 1553 | 
            +
                  }
         | 
| 1554 | 
            +
                };
         | 
| 1555 | 
            +
                pagePutInfo = {
         | 
| 1556 | 
            +
                  slug: pageElement.attr('id').split('_rev')[0],
         | 
| 1557 | 
            +
                  rev: pageElement.attr('id').split('_rev')[1],
         | 
| 1558 | 
            +
                  site: checkedSite(),
         | 
| 1559 | 
            +
                  local: pageElement.hasClass('local')
         | 
| 1560 | 
            +
                };
         | 
| 1561 | 
            +
                forkFrom = pagePutInfo.site;
         | 
| 1562 | 
            +
                wiki.log('pageHandler.put', action, pagePutInfo);
         | 
| 1563 | 
            +
                if (wiki.useLocalStorage()) {
         | 
| 1564 | 
            +
                  if (pagePutInfo.site != null) {
         | 
| 1565 | 
            +
                    wiki.log('remote => local');
         | 
| 1566 | 
            +
                  } else if (!pagePutInfo.local) {
         | 
| 1567 | 
            +
                    wiki.log('origin => local');
         | 
| 1568 | 
            +
                    action.site = forkFrom = location.host;
         | 
| 1569 | 
            +
                  }
         | 
| 1570 | 
            +
                }
         | 
| 1571 | 
            +
                action.date = (new Date()).getTime();
         | 
| 1572 | 
            +
                if (action.site === 'origin') {
         | 
| 1573 | 
            +
                  delete action.site;
         | 
| 1574 | 
            +
                }
         | 
| 1575 | 
            +
                if (forkFrom) {
         | 
| 1576 | 
            +
                  pageElement.find('h1 img').attr('src', '/favicon.png');
         | 
| 1577 | 
            +
                  pageElement.find('h1 a').attr('href', '/');
         | 
| 1578 | 
            +
                  pageElement.data('site', null);
         | 
| 1579 | 
            +
                  pageElement.removeClass('remote');
         | 
| 1580 | 
            +
                  state.setUrl();
         | 
| 1581 | 
            +
                  if (action.type !== 'fork') {
         | 
| 1582 | 
            +
                    action.fork = forkFrom;
         | 
| 1583 | 
            +
                    addToJournal(pageElement.find('.journal'), {
         | 
| 1584 | 
            +
                      type: 'fork',
         | 
| 1585 | 
            +
                      site: forkFrom,
         | 
| 1586 | 
            +
                      date: action.date
         | 
| 1587 | 
            +
                    });
         | 
| 1588 | 
            +
                  }
         | 
| 1589 | 
            +
                }
         | 
| 1590 | 
            +
                if (wiki.useLocalStorage() || pagePutInfo.site === 'local') {
         | 
| 1591 | 
            +
                  pushToLocal(pageElement, pagePutInfo, action);
         | 
| 1592 | 
            +
                  return pageElement.addClass("local");
         | 
| 1593 | 
            +
                } else {
         | 
| 1594 | 
            +
                  return pushToServer(pageElement, pagePutInfo, action);
         | 
| 1595 | 
            +
                }
         | 
| 1596 | 
            +
              };
         | 
| 1597 | 
            +
             | 
| 1598 | 
            +
            }).call(this);
         | 
| 1599 | 
            +
             | 
| 1600 | 
            +
            },{"./addToJournal":16,"./page":12,"./revision":15,"./state":9,"./util":6,"./wiki":2,"underscore":17}],11:[function(require,module,exports){
         | 
| 1601 | 
            +
            (function() {
         | 
| 1602 | 
            +
              var addToJournal, buildPageHeader, createFactory, emitHeader, emitTwins, handleDragging, initAddButton, initDragging, neighborhood, pageHandler, plugin, refresh, renderPageIntoPageElement, state, util, wiki, _;
         | 
| 1603 | 
            +
             | 
| 1604 | 
            +
              _ = require('underscore');
         | 
| 1605 | 
            +
             | 
| 1606 | 
            +
              util = require('./util');
         | 
| 1607 | 
            +
             | 
| 1608 | 
            +
              pageHandler = require('./pageHandler');
         | 
| 1609 | 
            +
             | 
| 1610 | 
            +
              plugin = require('./plugin');
         | 
| 1611 | 
            +
             | 
| 1612 | 
            +
              state = require('./state');
         | 
| 1613 | 
            +
             | 
| 1614 | 
            +
              neighborhood = require('./neighborhood');
         | 
| 1615 | 
            +
             | 
| 1616 | 
            +
              addToJournal = require('./addToJournal');
         | 
| 1617 | 
            +
             | 
| 1618 | 
            +
              wiki = require('./wiki');
         | 
| 1619 | 
            +
             | 
| 1620 | 
            +
              handleDragging = function(evt, ui) {
         | 
| 1621 | 
            +
                var action, before, beforeElement, destinationPageElement, equals, item, itemElement, moveFromPage, moveToPage, moveWithinPage, order, sourcePageElement, sourceSite, thisPageElement;
         | 
| 1622 | 
            +
                itemElement = ui.item;
         | 
| 1623 | 
            +
                item = wiki.getItem(itemElement);
         | 
| 1624 | 
            +
                thisPageElement = $(this).parents('.page:first');
         | 
| 1625 | 
            +
                sourcePageElement = itemElement.data('pageElement');
         | 
| 1626 | 
            +
                sourceSite = sourcePageElement.data('site');
         | 
| 1627 | 
            +
                destinationPageElement = itemElement.parents('.page:first');
         | 
| 1628 | 
            +
                equals = function(a, b) {
         | 
| 1629 | 
            +
                  return a && b && a.get(0) === b.get(0);
         | 
| 1630 | 
            +
                };
         | 
| 1631 | 
            +
                moveWithinPage = !sourcePageElement || equals(sourcePageElement, destinationPageElement);
         | 
| 1632 | 
            +
                moveFromPage = !moveWithinPage && equals(thisPageElement, sourcePageElement);
         | 
| 1633 | 
            +
                moveToPage = !moveWithinPage && equals(thisPageElement, destinationPageElement);
         | 
| 1634 | 
            +
                if (moveFromPage) {
         | 
| 1635 | 
            +
                  if (sourcePageElement.hasClass('ghost') || sourcePageElement.attr('id') === destinationPageElement.attr('id')) {
         | 
| 1636 | 
            +
                    return;
         | 
| 1637 | 
            +
                  }
         | 
| 1638 | 
            +
                }
         | 
| 1639 | 
            +
                action = moveWithinPage ? (order = $(this).children().map(function(_, value) {
         | 
| 1640 | 
            +
                  return $(value).attr('data-id');
         | 
| 1641 | 
            +
                }).get(), {
         | 
| 1642 | 
            +
                  type: 'move',
         | 
| 1643 | 
            +
                  order: order
         | 
| 1644 | 
            +
                }) : moveFromPage ? (wiki.log('drag from', sourcePageElement.find('h1').text()), {
         | 
| 1645 | 
            +
                  type: 'remove'
         | 
| 1646 | 
            +
                }) : moveToPage ? (itemElement.data('pageElement', thisPageElement), beforeElement = itemElement.prev('.item'), before = wiki.getItem(beforeElement), {
         | 
| 1647 | 
            +
                  type: 'add',
         | 
| 1648 | 
            +
                  item: item,
         | 
| 1649 | 
            +
                  after: before != null ? before.id : void 0
         | 
| 1650 | 
            +
                }) : void 0;
         | 
| 1651 | 
            +
                action.id = item.id;
         | 
| 1652 | 
            +
                return pageHandler.put(thisPageElement, action);
         | 
| 1653 | 
            +
              };
         | 
| 1654 | 
            +
             | 
| 1655 | 
            +
              initDragging = function($page) {
         | 
| 1656 | 
            +
                var $story;
         | 
| 1657 | 
            +
                $story = $page.find('.story');
         | 
| 1658 | 
            +
                return $story.sortable({
         | 
| 1659 | 
            +
                  connectWith: '.page .story'
         | 
| 1660 | 
            +
                }).on("sortupdate", handleDragging);
         | 
| 1661 | 
            +
              };
         | 
| 1662 | 
            +
             | 
| 1663 | 
            +
              initAddButton = function($page) {
         | 
| 1664 | 
            +
                return $page.find(".add-factory").live("click", function(evt) {
         | 
| 1665 | 
            +
                  if ($page.hasClass('ghost')) {
         | 
| 1666 | 
            +
                    return;
         | 
| 1667 | 
            +
                  }
         | 
| 1668 | 
            +
                  evt.preventDefault();
         | 
| 1669 | 
            +
                  return createFactory($page);
         | 
| 1670 | 
            +
                });
         | 
| 1671 | 
            +
              };
         | 
| 1672 | 
            +
             | 
| 1673 | 
            +
              createFactory = function($page) {
         | 
| 1674 | 
            +
                var before, beforeElement, item, itemElement;
         | 
| 1675 | 
            +
                item = {
         | 
| 1676 | 
            +
                  type: "factory",
         | 
| 1677 | 
            +
                  id: util.randomBytes(8)
         | 
| 1678 | 
            +
                };
         | 
| 1679 | 
            +
                itemElement = $("<div />", {
         | 
| 1680 | 
            +
                  "class": "item factory"
         | 
| 1681 | 
            +
                }).data('item', item).attr('data-id', item.id);
         | 
| 1682 | 
            +
                itemElement.data('pageElement', $page);
         | 
| 1683 | 
            +
                $page.find(".story").append(itemElement);
         | 
| 1684 | 
            +
                plugin["do"](itemElement, item);
         | 
| 1685 | 
            +
                beforeElement = itemElement.prev('.item');
         | 
| 1686 | 
            +
                before = wiki.getItem(beforeElement);
         | 
| 1687 | 
            +
                return pageHandler.put($page, {
         | 
| 1688 | 
            +
                  item: item,
         | 
| 1689 | 
            +
                  id: item.id,
         | 
| 1690 | 
            +
                  type: "add",
         | 
| 1691 | 
            +
                  after: before != null ? before.id : void 0
         | 
| 1692 | 
            +
                });
         | 
| 1693 | 
            +
              };
         | 
| 1694 | 
            +
             | 
| 1695 | 
            +
              buildPageHeader = function(_arg) {
         | 
| 1696 | 
            +
                var favicon_src, header_href, page, tooltip;
         | 
| 1697 | 
            +
                page = _arg.page, tooltip = _arg.tooltip, header_href = _arg.header_href, favicon_src = _arg.favicon_src;
         | 
| 1698 | 
            +
                if (page.plugin) {
         | 
| 1699 | 
            +
                  tooltip += "\n" + page.plugin + " plugin";
         | 
| 1700 | 
            +
                }
         | 
| 1701 | 
            +
                return "<h1 title=\"" + tooltip + "\"><a href=\"" + header_href + "\"><img src=\"" + favicon_src + "\" height=\"32px\" class=\"favicon\"></a> " + page.title + "</h1>";
         | 
| 1702 | 
            +
              };
         | 
| 1703 | 
            +
             | 
| 1704 | 
            +
              emitHeader = function($header, $page, pageObject) {
         | 
| 1705 | 
            +
                var date, header, isRemotePage, page, pageHeader, rev, viewHere;
         | 
| 1706 | 
            +
                page = pageObject.getRawPage();
         | 
| 1707 | 
            +
                isRemotePage = pageObject.isRemote();
         | 
| 1708 | 
            +
                header = '';
         | 
| 1709 | 
            +
                viewHere = wiki.asSlug(page.title) === 'welcome-visitors' ? "" : "/view/" + (pageObject.getSlug());
         | 
| 1710 | 
            +
                pageHeader = isRemotePage ? buildPageHeader({
         | 
| 1711 | 
            +
                  tooltip: pageObject.getRemoteSite(),
         | 
| 1712 | 
            +
                  header_href: "//" + (pageObject.getRemoteSite()) + "/view/welcome-visitors" + viewHere,
         | 
| 1713 | 
            +
                  favicon_src: "http://" + (pageObject.getRemoteSite()) + "/favicon.png",
         | 
| 1714 | 
            +
                  page: page
         | 
| 1715 | 
            +
                }) : buildPageHeader({
         | 
| 1716 | 
            +
                  tooltip: location.host,
         | 
| 1717 | 
            +
                  header_href: "/view/welcome-visitors" + viewHere,
         | 
| 1718 | 
            +
                  favicon_src: "/favicon.png",
         | 
| 1719 | 
            +
                  page: page
         | 
| 1720 | 
            +
                });
         | 
| 1721 | 
            +
                $header.append(pageHeader);
         | 
| 1722 | 
            +
                if (!isRemotePage) {
         | 
| 1723 | 
            +
                  $('img.favicon', $page).error(function(e) {
         | 
| 1724 | 
            +
                    return plugin.get('favicon', function(favicon) {
         | 
| 1725 | 
            +
                      return favicon.create();
         | 
| 1726 | 
            +
                    });
         | 
| 1727 | 
            +
                  });
         | 
| 1728 | 
            +
                }
         | 
| 1729 | 
            +
                if ($page.attr('id').match(/_rev/)) {
         | 
| 1730 | 
            +
                  rev = page.journal.length - 1;
         | 
| 1731 | 
            +
                  date = page.journal[rev].date;
         | 
| 1732 | 
            +
                  $page.addClass('ghost').data('rev', rev);
         | 
| 1733 | 
            +
                  return $header.append($("<h2 class=\"revision\">\n  <span>\n    " + (date != null ? util.formatDate(date) : "Revision " + rev) + "\n  </span>\n</h2>"));
         | 
| 1734 | 
            +
                }
         | 
| 1735 | 
            +
              };
         | 
| 1736 | 
            +
             | 
| 1737 | 
            +
              emitTwins = wiki.emitTwins = function($page) {
         | 
| 1738 | 
            +
                var actions, bin, bins, flags, i, info, item, legend, page, remoteSite, site, slug, twins, viewing, _i, _len, _ref, _ref1, _ref2, _ref3;
         | 
| 1739 | 
            +
                page = $page.data('data');
         | 
| 1740 | 
            +
                site = $page.data('site') || window.location.host;
         | 
| 1741 | 
            +
                if (site === 'view' || site === 'origin') {
         | 
| 1742 | 
            +
                  site = window.location.host;
         | 
| 1743 | 
            +
                }
         | 
| 1744 | 
            +
                slug = wiki.asSlug(page.title);
         | 
| 1745 | 
            +
                if (((actions = (_ref = page.journal) != null ? _ref.length : void 0) != null) && ((viewing = (_ref1 = page.journal[actions - 1]) != null ? _ref1.date : void 0) != null)) {
         | 
| 1746 | 
            +
                  viewing = Math.floor(viewing / 1000) * 1000;
         | 
| 1747 | 
            +
                  bins = {
         | 
| 1748 | 
            +
                    newer: [],
         | 
| 1749 | 
            +
                    same: [],
         | 
| 1750 | 
            +
                    older: []
         | 
| 1751 | 
            +
                  };
         | 
| 1752 | 
            +
                  _ref2 = wiki.neighborhood;
         | 
| 1753 | 
            +
                  for (remoteSite in _ref2) {
         | 
| 1754 | 
            +
                    info = _ref2[remoteSite];
         | 
| 1755 | 
            +
                    if (remoteSite !== site && (info.sitemap != null)) {
         | 
| 1756 | 
            +
                      _ref3 = info.sitemap;
         | 
| 1757 | 
            +
                      for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
         | 
| 1758 | 
            +
                        item = _ref3[_i];
         | 
| 1759 | 
            +
                        if (item.slug === slug) {
         | 
| 1760 | 
            +
                          bin = item.date > viewing ? bins.newer : item.date < viewing ? bins.older : bins.same;
         | 
| 1761 | 
            +
                          bin.push({
         | 
| 1762 | 
            +
                            remoteSite: remoteSite,
         | 
| 1763 | 
            +
                            item: item
         | 
| 1764 | 
            +
                          });
         | 
| 1765 | 
            +
                        }
         | 
| 1766 | 
            +
                      }
         | 
| 1767 | 
            +
                    }
         | 
| 1768 | 
            +
                  }
         | 
| 1769 | 
            +
                  twins = [];
         | 
| 1770 | 
            +
                  for (legend in bins) {
         | 
| 1771 | 
            +
                    bin = bins[legend];
         | 
| 1772 | 
            +
                    if (!bin.length) {
         | 
| 1773 | 
            +
                      continue;
         | 
| 1774 | 
            +
                    }
         | 
| 1775 | 
            +
                    bin.sort(function(a, b) {
         | 
| 1776 | 
            +
                      return a.item.date < b.item.date;
         | 
| 1777 | 
            +
                    });
         | 
| 1778 | 
            +
                    flags = (function() {
         | 
| 1779 | 
            +
                      var _j, _len1, _ref4, _results;
         | 
| 1780 | 
            +
                      _results = [];
         | 
| 1781 | 
            +
                      for (i = _j = 0, _len1 = bin.length; _j < _len1; i = ++_j) {
         | 
| 1782 | 
            +
                        _ref4 = bin[i], remoteSite = _ref4.remoteSite, item = _ref4.item;
         | 
| 1783 | 
            +
                        if (i >= 8) {
         | 
| 1784 | 
            +
                          break;
         | 
| 1785 | 
            +
                        }
         | 
| 1786 | 
            +
                        _results.push("<img class=\"remote\"\nsrc=\"http://" + remoteSite + "/favicon.png\"\ndata-slug=\"" + slug + "\"\ndata-site=\"" + remoteSite + "\"\ntitle=\"" + remoteSite + "\">");
         | 
| 1787 | 
            +
                      }
         | 
| 1788 | 
            +
                      return _results;
         | 
| 1789 | 
            +
                    })();
         | 
| 1790 | 
            +
                    twins.push("" + (flags.join(' ')) + " " + legend);
         | 
| 1791 | 
            +
                  }
         | 
| 1792 | 
            +
                  if (twins) {
         | 
| 1793 | 
            +
                    return $page.find('.twins').html("<p>" + (twins.join(", ")) + "</p>");
         | 
| 1794 | 
            +
                  }
         | 
| 1795 | 
            +
                }
         | 
| 1796 | 
            +
              };
         | 
| 1797 | 
            +
             | 
| 1798 | 
            +
              renderPageIntoPageElement = function(pageObject, $page) {
         | 
| 1799 | 
            +
                var $footer, $header, $journal, $story, $twins, host, slug, _ref;
         | 
| 1800 | 
            +
                $page.data("data", pageObject.getRawPage());
         | 
| 1801 | 
            +
                if (pageObject.isRemote()) {
         | 
| 1802 | 
            +
                  $page.data("site", pageObject.getRemoteSite());
         | 
| 1803 | 
            +
                }
         | 
| 1804 | 
            +
                slug = $page.attr('id');
         | 
| 1805 | 
            +
                wiki.resolutionContext = pageObject.getContext();
         | 
| 1806 | 
            +
                $page.empty();
         | 
| 1807 | 
            +
                _ref = ['twins', 'header', 'story', 'journal', 'footer'].map(function(className) {
         | 
| 1808 | 
            +
                  return $("<div />").addClass(className).appendTo($page);
         | 
| 1809 | 
            +
                }), $twins = _ref[0], $header = _ref[1], $story = _ref[2], $journal = _ref[3], $footer = _ref[4];
         | 
| 1810 | 
            +
                emitHeader($header, $page, pageObject);
         | 
| 1811 | 
            +
                pageObject.seqItems(function(item, done) {
         | 
| 1812 | 
            +
                  var $item;
         | 
| 1813 | 
            +
                  if ((item != null ? item.type : void 0) && (item != null ? item.id : void 0)) {
         | 
| 1814 | 
            +
                    $item = $("<div class=\"item " + item.type + "\" data-id=\"" + item.id + "\">");
         | 
| 1815 | 
            +
                    $story.append($item);
         | 
| 1816 | 
            +
                    return plugin["do"]($item, item, done);
         | 
| 1817 | 
            +
                  } else {
         | 
| 1818 | 
            +
                    $story.append($("<div><p class=\"error\">Can't make sense of story[" + i + "]</p></div>"));
         | 
| 1819 | 
            +
                    return done();
         | 
| 1820 | 
            +
                  }
         | 
| 1821 | 
            +
                });
         | 
| 1822 | 
            +
                pageObject.seqActions(function(each, done) {
         | 
| 1823 | 
            +
                  if (each.separator) {
         | 
| 1824 | 
            +
                    addToJournal($journal, each.separator);
         | 
| 1825 | 
            +
                  }
         | 
| 1826 | 
            +
                  addToJournal($journal, each.action);
         | 
| 1827 | 
            +
                  return done();
         | 
| 1828 | 
            +
                });
         | 
| 1829 | 
            +
                emitTwins($page);
         | 
| 1830 | 
            +
                $journal.append("<div class=\"control-buttons\">\n  <a href=\"#\" class=\"button fork-page\" title=\"fork this page\">" + util.symbols['fork'] + "</a>\n  <a href=\"#\" class=\"button add-factory\" title=\"add paragraph\">" + util.symbols['add'] + "</a>\n</div>");
         | 
| 1831 | 
            +
                host = pageObject.getRemoteSite() || location.host;
         | 
| 1832 | 
            +
                return $footer.append("<a id=\"license\" href=\"http://creativecommons.org/licenses/by-sa/3.0/\">CC BY-SA 3.0</a> .\n<a class=\"show-page-source\" href=\"/" + slug + ".json?random=" + (util.randomBytes(4)) + "\" title=\"source\">JSON</a> .\n<a href= \"//" + host + "/" + slug + ".html\">" + host + "</a>");
         | 
| 1833 | 
            +
              };
         | 
| 1834 | 
            +
             | 
| 1835 | 
            +
              wiki.buildPage = function(pageObject, $page) {
         | 
| 1836 | 
            +
                if (pageObject.isLocal()) {
         | 
| 1837 | 
            +
                  $page.addClass('local');
         | 
| 1838 | 
            +
                }
         | 
| 1839 | 
            +
                if (pageObject.isRemote()) {
         | 
| 1840 | 
            +
                  $page.addClass('remote');
         | 
| 1841 | 
            +
                }
         | 
| 1842 | 
            +
                if (pageObject.isPlugin()) {
         | 
| 1843 | 
            +
                  $page.addClass('plugin');
         | 
| 1844 | 
            +
                }
         | 
| 1845 | 
            +
                renderPageIntoPageElement(pageObject, $page);
         | 
| 1846 | 
            +
                state.setUrl();
         | 
| 1847 | 
            +
                initDragging($page);
         | 
| 1848 | 
            +
                initAddButton($page);
         | 
| 1849 | 
            +
                return $page;
         | 
| 1850 | 
            +
              };
         | 
| 1851 | 
            +
             | 
| 1852 | 
            +
              module.exports = refresh = wiki.refresh = function() {
         | 
| 1853 | 
            +
                var $page, createGhostPage, emptyPage, pageInformation, rev, slug, whenGotten, _ref;
         | 
| 1854 | 
            +
                $page = $(this);
         | 
| 1855 | 
            +
                _ref = $page.attr('id').split('_rev'), slug = _ref[0], rev = _ref[1];
         | 
| 1856 | 
            +
                pageInformation = {
         | 
| 1857 | 
            +
                  slug: slug,
         | 
| 1858 | 
            +
                  rev: rev,
         | 
| 1859 | 
            +
                  site: $page.data('site')
         | 
| 1860 | 
            +
                };
         | 
| 1861 | 
            +
                emptyPage = require('./page').emptyPage;
         | 
| 1862 | 
            +
                createGhostPage = function() {
         | 
| 1863 | 
            +
                  var hit, hits, info, pageObject, result, site, title, _i, _len, _ref1;
         | 
| 1864 | 
            +
                  title = $("a[href=\"/" + slug + ".html\"]:last").text() || slug;
         | 
| 1865 | 
            +
                  pageObject = emptyPage();
         | 
| 1866 | 
            +
                  pageObject.setTitle(title);
         | 
| 1867 | 
            +
                  hits = [];
         | 
| 1868 | 
            +
                  _ref1 = wiki.neighborhood;
         | 
| 1869 | 
            +
                  for (site in _ref1) {
         | 
| 1870 | 
            +
                    info = _ref1[site];
         | 
| 1871 | 
            +
                    if (info.sitemap != null) {
         | 
| 1872 | 
            +
                      result = _.find(info.sitemap, function(each) {
         | 
| 1873 | 
            +
                        return each.slug === slug;
         | 
| 1874 | 
            +
                      });
         | 
| 1875 | 
            +
                      if (result != null) {
         | 
| 1876 | 
            +
                        hits.push({
         | 
| 1877 | 
            +
                          "type": "reference",
         | 
| 1878 | 
            +
                          "site": site,
         | 
| 1879 | 
            +
                          "slug": slug,
         | 
| 1880 | 
            +
                          "title": result.title || slug,
         | 
| 1881 | 
            +
                          "text": result.synopsis || ''
         | 
| 1882 | 
            +
                        });
         | 
| 1883 | 
            +
                      }
         | 
| 1884 | 
            +
                    }
         | 
| 1885 | 
            +
                  }
         | 
| 1886 | 
            +
                  if (hits.length > 0) {
         | 
| 1887 | 
            +
                    pageObject.addItem({
         | 
| 1888 | 
            +
                      'type': 'future',
         | 
| 1889 | 
            +
                      'text': 'We could not find this page in the expected context.',
         | 
| 1890 | 
            +
                      'title': title
         | 
| 1891 | 
            +
                    });
         | 
| 1892 | 
            +
                    pageObject.addItem({
         | 
| 1893 | 
            +
                      'type': 'paragraph',
         | 
| 1894 | 
            +
                      'text': "We did find the page in your current neighborhood."
         | 
| 1895 | 
            +
                    });
         | 
| 1896 | 
            +
                    for (_i = 0, _len = hits.length; _i < _len; _i++) {
         | 
| 1897 | 
            +
                      hit = hits[_i];
         | 
| 1898 | 
            +
                      pageObject.addItem(hit);
         | 
| 1899 | 
            +
                    }
         | 
| 1900 | 
            +
                  } else {
         | 
| 1901 | 
            +
                    pageObject.addItem({
         | 
| 1902 | 
            +
                      'type': 'future',
         | 
| 1903 | 
            +
                      'text': 'We could not find this page.',
         | 
| 1904 | 
            +
                      'title': title
         | 
| 1905 | 
            +
                    });
         | 
| 1906 | 
            +
                  }
         | 
| 1907 | 
            +
                  return wiki.buildPage(pageObject, $page).addClass('ghost');
         | 
| 1908 | 
            +
                };
         | 
| 1909 | 
            +
                whenGotten = function(pageObject) {
         | 
| 1910 | 
            +
                  var site, _i, _len, _ref1, _results;
         | 
| 1911 | 
            +
                  wiki.buildPage(pageObject, $page);
         | 
| 1912 | 
            +
                  _ref1 = pageObject.getNeighbors(location.host);
         | 
| 1913 | 
            +
                  _results = [];
         | 
| 1914 | 
            +
                  for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
         | 
| 1915 | 
            +
                    site = _ref1[_i];
         | 
| 1916 | 
            +
                    _results.push(neighborhood.registerNeighbor(site));
         | 
| 1917 | 
            +
                  }
         | 
| 1918 | 
            +
                  return _results;
         | 
| 1919 | 
            +
                };
         | 
| 1920 | 
            +
                return pageHandler.get({
         | 
| 1921 | 
            +
                  whenGotten: whenGotten,
         | 
| 1922 | 
            +
                  whenNotGotten: createGhostPage,
         | 
| 1923 | 
            +
                  pageInformation: pageInformation
         | 
| 1924 | 
            +
                });
         | 
| 1925 | 
            +
              };
         | 
| 1926 | 
            +
             | 
| 1927 | 
            +
            }).call(this);
         | 
| 1928 | 
            +
             | 
| 1929 | 
            +
            },{"./addToJournal":16,"./neighborhood":18,"./page":12,"./pageHandler":7,"./plugin":8,"./state":9,"./util":6,"./wiki":2,"underscore":17}],12:[function(require,module,exports){
         | 
| 1930 | 
            +
            (function() {
         | 
| 1931 | 
            +
              var asSlug, emptyPage, newPage, nowSections, util, _;
         | 
| 1932 | 
            +
             | 
| 1933 | 
            +
              util = require('./util');
         | 
| 1934 | 
            +
             | 
| 1935 | 
            +
              _ = require('underscore');
         | 
| 1936 | 
            +
             | 
| 1937 | 
            +
              asSlug = function(name) {
         | 
| 1938 | 
            +
                return name.replace(/\s/g, '-').replace(/[^A-Za-z0-9-]/g, '').toLowerCase();
         | 
| 1939 | 
            +
              };
         | 
| 1940 | 
            +
             | 
| 1941 | 
            +
              emptyPage = function() {
         | 
| 1942 | 
            +
                return newPage({}, null);
         | 
| 1943 | 
            +
              };
         | 
| 1944 | 
            +
             | 
| 1945 | 
            +
              nowSections = function(now) {
         | 
| 1946 | 
            +
                return [
         | 
| 1947 | 
            +
                  {
         | 
| 1948 | 
            +
                    symbol: '❄',
         | 
| 1949 | 
            +
                    date: now - 1000 * 60 * 60 * 24 * 366,
         | 
| 1950 | 
            +
                    period: 'a Year'
         | 
| 1951 | 
            +
                  }, {
         | 
| 1952 | 
            +
                    symbol: '⚘',
         | 
| 1953 | 
            +
                    date: now - 1000 * 60 * 60 * 24 * 31 * 3,
         | 
| 1954 | 
            +
                    period: 'a Season'
         | 
| 1955 | 
            +
                  }, {
         | 
| 1956 | 
            +
                    symbol: '⚪',
         | 
| 1957 | 
            +
                    date: now - 1000 * 60 * 60 * 24 * 31,
         | 
| 1958 | 
            +
                    period: 'a Month'
         | 
| 1959 | 
            +
                  }, {
         | 
| 1960 | 
            +
                    symbol: '☽',
         | 
| 1961 | 
            +
                    date: now - 1000 * 60 * 60 * 24 * 7,
         | 
| 1962 | 
            +
                    period: 'a Week'
         | 
| 1963 | 
            +
                  }, {
         | 
| 1964 | 
            +
                    symbol: '☀',
         | 
| 1965 | 
            +
                    date: now - 1000 * 60 * 60 * 24,
         | 
| 1966 | 
            +
                    period: 'a Day'
         | 
| 1967 | 
            +
                  }, {
         | 
| 1968 | 
            +
                    symbol: '⌚',
         | 
| 1969 | 
            +
                    date: now - 1000 * 60 * 60,
         | 
| 1970 | 
            +
                    period: 'an Hour'
         | 
| 1971 | 
            +
                  }
         | 
| 1972 | 
            +
                ];
         | 
| 1973 | 
            +
              };
         | 
| 1974 | 
            +
             | 
| 1975 | 
            +
              newPage = function(json, site) {
         | 
| 1976 | 
            +
                var addItem, addParagraph, getContext, getNeighbors, getRawPage, getRemoteSite, getSlug, isLocal, isPlugin, isRemote, page, seqActions, seqItems, setTitle;
         | 
| 1977 | 
            +
                page = _.extend({}, util.emptyPage(), json);
         | 
| 1978 | 
            +
                page.story || (page.story = []);
         | 
| 1979 | 
            +
                page.journal || (page.journal = []);
         | 
| 1980 | 
            +
                getRawPage = function() {
         | 
| 1981 | 
            +
                  return page;
         | 
| 1982 | 
            +
                };
         | 
| 1983 | 
            +
                getContext = function() {
         | 
| 1984 | 
            +
                  var action, addContext, context, _i, _len, _ref;
         | 
| 1985 | 
            +
                  context = ['view'];
         | 
| 1986 | 
            +
                  if (isRemote()) {
         | 
| 1987 | 
            +
                    context.push(site);
         | 
| 1988 | 
            +
                  }
         | 
| 1989 | 
            +
                  addContext = function(site) {
         | 
| 1990 | 
            +
                    if ((site != null) && !_.include(context, site)) {
         | 
| 1991 | 
            +
                      return context.push(site);
         | 
| 1992 | 
            +
                    }
         | 
| 1993 | 
            +
                  };
         | 
| 1994 | 
            +
                  _ref = page.journal.slice(0).reverse();
         | 
| 1995 | 
            +
                  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         | 
| 1996 | 
            +
                    action = _ref[_i];
         | 
| 1997 | 
            +
                    addContext(action.site);
         | 
| 1998 | 
            +
                  }
         | 
| 1999 | 
            +
                  return context;
         | 
| 2000 | 
            +
                };
         | 
| 2001 | 
            +
                isPlugin = function() {
         | 
| 2002 | 
            +
                  return page.plugin != null;
         | 
| 2003 | 
            +
                };
         | 
| 2004 | 
            +
                isRemote = function() {
         | 
| 2005 | 
            +
                  return !(site === (void 0) || site === null || site === 'view' || site === 'origin' || site === 'local');
         | 
| 2006 | 
            +
                };
         | 
| 2007 | 
            +
                isLocal = function() {
         | 
| 2008 | 
            +
                  return site === 'local';
         | 
| 2009 | 
            +
                };
         | 
| 2010 | 
            +
                getRemoteSite = function() {
         | 
| 2011 | 
            +
                  if (isRemote()) {
         | 
| 2012 | 
            +
                    return site;
         | 
| 2013 | 
            +
                  }
         | 
| 2014 | 
            +
                  return null;
         | 
| 2015 | 
            +
                };
         | 
| 2016 | 
            +
                getSlug = function() {
         | 
| 2017 | 
            +
                  return asSlug(page.title);
         | 
| 2018 | 
            +
                };
         | 
| 2019 | 
            +
                getNeighbors = function(host) {
         | 
| 2020 | 
            +
                  var action, item, neighbors, _i, _j, _len, _len1, _ref, _ref1;
         | 
| 2021 | 
            +
                  neighbors = [];
         | 
| 2022 | 
            +
                  if (isRemote()) {
         | 
| 2023 | 
            +
                    neighbors.push(site);
         | 
| 2024 | 
            +
                  } else {
         | 
| 2025 | 
            +
                    if (host != null) {
         | 
| 2026 | 
            +
                      neighbors.push(host);
         | 
| 2027 | 
            +
                    }
         | 
| 2028 | 
            +
                  }
         | 
| 2029 | 
            +
                  _ref = page.story;
         | 
| 2030 | 
            +
                  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         | 
| 2031 | 
            +
                    item = _ref[_i];
         | 
| 2032 | 
            +
                    if (item.site != null) {
         | 
| 2033 | 
            +
                      neighbors.push(item.site);
         | 
| 2034 | 
            +
                    }
         | 
| 2035 | 
            +
                  }
         | 
| 2036 | 
            +
                  _ref1 = page.journal;
         | 
| 2037 | 
            +
                  for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
         | 
| 2038 | 
            +
                    action = _ref1[_j];
         | 
| 2039 | 
            +
                    if (action.site != null) {
         | 
| 2040 | 
            +
                      neighbors.push(action.site);
         | 
| 2041 | 
            +
                    }
         | 
| 2042 | 
            +
                  }
         | 
| 2043 | 
            +
                  return _.uniq(neighbors);
         | 
| 2044 | 
            +
                };
         | 
| 2045 | 
            +
                setTitle = function(title) {
         | 
| 2046 | 
            +
                  return page.title = title;
         | 
| 2047 | 
            +
                };
         | 
| 2048 | 
            +
                addItem = function(item) {
         | 
| 2049 | 
            +
                  item = _.extend({}, {
         | 
| 2050 | 
            +
                    id: util.randomBytes(8)
         | 
| 2051 | 
            +
                  }, item);
         | 
| 2052 | 
            +
                  return page.story.push(item);
         | 
| 2053 | 
            +
                };
         | 
| 2054 | 
            +
                seqItems = function(each) {
         | 
| 2055 | 
            +
                  var emitItem;
         | 
| 2056 | 
            +
                  emitItem = function(i) {
         | 
| 2057 | 
            +
                    if (i >= page.story.length) {
         | 
| 2058 | 
            +
                      return;
         | 
| 2059 | 
            +
                    }
         | 
| 2060 | 
            +
                    return each(page.story[i], function() {
         | 
| 2061 | 
            +
                      return emitItem(i + 1);
         | 
| 2062 | 
            +
                    });
         | 
| 2063 | 
            +
                  };
         | 
| 2064 | 
            +
                  return emitItem(0);
         | 
| 2065 | 
            +
                };
         | 
| 2066 | 
            +
                addParagraph = function(text) {
         | 
| 2067 | 
            +
                  var type;
         | 
| 2068 | 
            +
                  type = "paragraph";
         | 
| 2069 | 
            +
                  return addItem({
         | 
| 2070 | 
            +
                    type: type,
         | 
| 2071 | 
            +
                    text: text
         | 
| 2072 | 
            +
                  });
         | 
| 2073 | 
            +
                };
         | 
| 2074 | 
            +
                seqActions = function(each) {
         | 
| 2075 | 
            +
                  var emitAction, sections, smaller;
         | 
| 2076 | 
            +
                  smaller = 0;
         | 
| 2077 | 
            +
                  sections = nowSections((new Date).getTime());
         | 
| 2078 | 
            +
                  emitAction = function(i) {
         | 
| 2079 | 
            +
                    var action, bigger, section, separator, _i, _len;
         | 
| 2080 | 
            +
                    if (i >= page.journal.length) {
         | 
| 2081 | 
            +
                      return;
         | 
| 2082 | 
            +
                    }
         | 
| 2083 | 
            +
                    action = page.journal[i];
         | 
| 2084 | 
            +
                    bigger = action.date || 0;
         | 
| 2085 | 
            +
                    separator = null;
         | 
| 2086 | 
            +
                    for (_i = 0, _len = sections.length; _i < _len; _i++) {
         | 
| 2087 | 
            +
                      section = sections[_i];
         | 
| 2088 | 
            +
                      if (section.date > smaller && section.date < bigger) {
         | 
| 2089 | 
            +
                        separator = section;
         | 
| 2090 | 
            +
                      }
         | 
| 2091 | 
            +
                    }
         | 
| 2092 | 
            +
                    smaller = bigger;
         | 
| 2093 | 
            +
                    return each({
         | 
| 2094 | 
            +
                      action: action,
         | 
| 2095 | 
            +
                      separator: separator
         | 
| 2096 | 
            +
                    }, function() {
         | 
| 2097 | 
            +
                      return emitAction(i + 1);
         | 
| 2098 | 
            +
                    });
         | 
| 2099 | 
            +
                  };
         | 
| 2100 | 
            +
                  return emitAction(0);
         | 
| 2101 | 
            +
                };
         | 
| 2102 | 
            +
                return {
         | 
| 2103 | 
            +
                  getRawPage: getRawPage,
         | 
| 2104 | 
            +
                  getContext: getContext,
         | 
| 2105 | 
            +
                  isPlugin: isPlugin,
         | 
| 2106 | 
            +
                  isRemote: isRemote,
         | 
| 2107 | 
            +
                  isLocal: isLocal,
         | 
| 2108 | 
            +
                  getRemoteSite: getRemoteSite,
         | 
| 2109 | 
            +
                  getSlug: getSlug,
         | 
| 2110 | 
            +
                  getNeighbors: getNeighbors,
         | 
| 2111 | 
            +
                  setTitle: setTitle,
         | 
| 2112 | 
            +
                  addItem: addItem,
         | 
| 2113 | 
            +
                  addParagraph: addParagraph,
         | 
| 2114 | 
            +
                  seqItems: seqItems,
         | 
| 2115 | 
            +
                  seqActions: seqActions
         | 
| 2116 | 
            +
                };
         | 
| 2117 | 
            +
              };
         | 
| 2118 | 
            +
             | 
| 2119 | 
            +
              module.exports = {
         | 
| 2120 | 
            +
                newPage: newPage,
         | 
| 2121 | 
            +
                emptyPage: emptyPage
         | 
| 2122 | 
            +
              };
         | 
| 2123 | 
            +
             | 
| 2124 | 
            +
            }).call(this);
         | 
| 2125 | 
            +
             | 
| 2126 | 
            +
            },{"./util":6,"underscore":17}],17:[function(require,module,exports){
         | 
| 2127 | 
            +
            (function(){//     Underscore.js 1.5.2
         | 
| 2128 | 
            +
            //     http://underscorejs.org
         | 
| 2129 | 
            +
            //     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
         | 
| 2130 | 
            +
            //     Underscore may be freely distributed under the MIT license.
         | 
| 2131 | 
            +
             | 
| 2132 | 
            +
            (function() {
         | 
| 2133 | 
            +
             | 
| 2134 | 
            +
              // Baseline setup
         | 
| 2135 | 
            +
              // --------------
         | 
| 2136 | 
            +
             | 
| 2137 | 
            +
              // Establish the root object, `window` in the browser, or `exports` on the server.
         | 
| 2138 | 
            +
              var root = this;
         | 
| 2139 | 
            +
             | 
| 2140 | 
            +
              // Save the previous value of the `_` variable.
         | 
| 2141 | 
            +
              var previousUnderscore = root._;
         | 
| 2142 | 
            +
             | 
| 2143 | 
            +
              // Establish the object that gets returned to break out of a loop iteration.
         | 
| 2144 | 
            +
              var breaker = {};
         | 
| 2145 | 
            +
             | 
| 2146 | 
            +
              // Save bytes in the minified (but not gzipped) version:
         | 
| 2147 | 
            +
              var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
         | 
| 2148 | 
            +
             | 
| 2149 | 
            +
              // Create quick reference variables for speed access to core prototypes.
         | 
| 2150 | 
            +
              var
         | 
| 2151 | 
            +
                push             = ArrayProto.push,
         | 
| 2152 | 
            +
                slice            = ArrayProto.slice,
         | 
| 2153 | 
            +
                concat           = ArrayProto.concat,
         | 
| 2154 | 
            +
                toString         = ObjProto.toString,
         | 
| 2155 | 
            +
                hasOwnProperty   = ObjProto.hasOwnProperty;
         | 
| 2156 | 
            +
             | 
| 2157 | 
            +
              // All **ECMAScript 5** native function implementations that we hope to use
         | 
| 2158 | 
            +
              // are declared here.
         | 
| 2159 | 
            +
              var
         | 
| 2160 | 
            +
                nativeForEach      = ArrayProto.forEach,
         | 
| 2161 | 
            +
                nativeMap          = ArrayProto.map,
         | 
| 2162 | 
            +
                nativeReduce       = ArrayProto.reduce,
         | 
| 2163 | 
            +
                nativeReduceRight  = ArrayProto.reduceRight,
         | 
| 2164 | 
            +
                nativeFilter       = ArrayProto.filter,
         | 
| 2165 | 
            +
                nativeEvery        = ArrayProto.every,
         | 
| 2166 | 
            +
                nativeSome         = ArrayProto.some,
         | 
| 2167 | 
            +
                nativeIndexOf      = ArrayProto.indexOf,
         | 
| 2168 | 
            +
                nativeLastIndexOf  = ArrayProto.lastIndexOf,
         | 
| 2169 | 
            +
                nativeIsArray      = Array.isArray,
         | 
| 2170 | 
            +
                nativeKeys         = Object.keys,
         | 
| 2171 | 
            +
                nativeBind         = FuncProto.bind;
         | 
| 2172 | 
            +
             | 
| 2173 | 
            +
              // Create a safe reference to the Underscore object for use below.
         | 
| 2174 | 
            +
              var _ = function(obj) {
         | 
| 2175 | 
            +
                if (obj instanceof _) return obj;
         | 
| 2176 | 
            +
                if (!(this instanceof _)) return new _(obj);
         | 
| 2177 | 
            +
                this._wrapped = obj;
         | 
| 2178 | 
            +
              };
         | 
| 2179 | 
            +
             | 
| 2180 | 
            +
              // Export the Underscore object for **Node.js**, with
         | 
| 2181 | 
            +
              // backwards-compatibility for the old `require()` API. If we're in
         | 
| 2182 | 
            +
              // the browser, add `_` as a global object via a string identifier,
         | 
| 2183 | 
            +
              // for Closure Compiler "advanced" mode.
         | 
| 2184 | 
            +
              if (typeof exports !== 'undefined') {
         | 
| 2185 | 
            +
                if (typeof module !== 'undefined' && module.exports) {
         | 
| 2186 | 
            +
                  exports = module.exports = _;
         | 
| 2187 | 
            +
                }
         | 
| 2188 | 
            +
                exports._ = _;
         | 
| 2189 | 
            +
              } else {
         | 
| 2190 | 
            +
                root._ = _;
         | 
| 2191 | 
            +
              }
         | 
| 2192 | 
            +
             | 
| 2193 | 
            +
              // Current version.
         | 
| 2194 | 
            +
              _.VERSION = '1.5.2';
         | 
| 2195 | 
            +
             | 
| 2196 | 
            +
              // Collection Functions
         | 
| 2197 | 
            +
              // --------------------
         | 
| 2198 | 
            +
             | 
| 2199 | 
            +
              // The cornerstone, an `each` implementation, aka `forEach`.
         | 
| 2200 | 
            +
              // Handles objects with the built-in `forEach`, arrays, and raw objects.
         | 
| 2201 | 
            +
              // Delegates to **ECMAScript 5**'s native `forEach` if available.
         | 
| 2202 | 
            +
              var each = _.each = _.forEach = function(obj, iterator, context) {
         | 
| 2203 | 
            +
                if (obj == null) return;
         | 
| 2204 | 
            +
                if (nativeForEach && obj.forEach === nativeForEach) {
         | 
| 2205 | 
            +
                  obj.forEach(iterator, context);
         | 
| 2206 | 
            +
                } else if (obj.length === +obj.length) {
         | 
| 2207 | 
            +
                  for (var i = 0, length = obj.length; i < length; i++) {
         | 
| 2208 | 
            +
                    if (iterator.call(context, obj[i], i, obj) === breaker) return;
         | 
| 2209 | 
            +
                  }
         | 
| 2210 | 
            +
                } else {
         | 
| 2211 | 
            +
                  var keys = _.keys(obj);
         | 
| 2212 | 
            +
                  for (var i = 0, length = keys.length; i < length; i++) {
         | 
| 2213 | 
            +
                    if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
         | 
| 2214 | 
            +
                  }
         | 
| 2215 | 
            +
                }
         | 
| 2216 | 
            +
              };
         | 
| 2217 | 
            +
             | 
| 2218 | 
            +
              // Return the results of applying the iterator to each element.
         | 
| 2219 | 
            +
              // Delegates to **ECMAScript 5**'s native `map` if available.
         | 
| 2220 | 
            +
              _.map = _.collect = function(obj, iterator, context) {
         | 
| 2221 | 
            +
                var results = [];
         | 
| 2222 | 
            +
                if (obj == null) return results;
         | 
| 2223 | 
            +
                if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
         | 
| 2224 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2225 | 
            +
                  results.push(iterator.call(context, value, index, list));
         | 
| 2226 | 
            +
                });
         | 
| 2227 | 
            +
                return results;
         | 
| 2228 | 
            +
              };
         | 
| 2229 | 
            +
             | 
| 2230 | 
            +
              var reduceError = 'Reduce of empty array with no initial value';
         | 
| 2231 | 
            +
             | 
| 2232 | 
            +
              // **Reduce** builds up a single result from a list of values, aka `inject`,
         | 
| 2233 | 
            +
              // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
         | 
| 2234 | 
            +
              _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
         | 
| 2235 | 
            +
                var initial = arguments.length > 2;
         | 
| 2236 | 
            +
                if (obj == null) obj = [];
         | 
| 2237 | 
            +
                if (nativeReduce && obj.reduce === nativeReduce) {
         | 
| 2238 | 
            +
                  if (context) iterator = _.bind(iterator, context);
         | 
| 2239 | 
            +
                  return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
         | 
| 2240 | 
            +
                }
         | 
| 2241 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2242 | 
            +
                  if (!initial) {
         | 
| 2243 | 
            +
                    memo = value;
         | 
| 2244 | 
            +
                    initial = true;
         | 
| 2245 | 
            +
                  } else {
         | 
| 2246 | 
            +
                    memo = iterator.call(context, memo, value, index, list);
         | 
| 2247 | 
            +
                  }
         | 
| 2248 | 
            +
                });
         | 
| 2249 | 
            +
                if (!initial) throw new TypeError(reduceError);
         | 
| 2250 | 
            +
                return memo;
         | 
| 2251 | 
            +
              };
         | 
| 2252 | 
            +
             | 
| 2253 | 
            +
              // The right-associative version of reduce, also known as `foldr`.
         | 
| 2254 | 
            +
              // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
         | 
| 2255 | 
            +
              _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
         | 
| 2256 | 
            +
                var initial = arguments.length > 2;
         | 
| 2257 | 
            +
                if (obj == null) obj = [];
         | 
| 2258 | 
            +
                if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
         | 
| 2259 | 
            +
                  if (context) iterator = _.bind(iterator, context);
         | 
| 2260 | 
            +
                  return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
         | 
| 2261 | 
            +
                }
         | 
| 2262 | 
            +
                var length = obj.length;
         | 
| 2263 | 
            +
                if (length !== +length) {
         | 
| 2264 | 
            +
                  var keys = _.keys(obj);
         | 
| 2265 | 
            +
                  length = keys.length;
         | 
| 2266 | 
            +
                }
         | 
| 2267 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2268 | 
            +
                  index = keys ? keys[--length] : --length;
         | 
| 2269 | 
            +
                  if (!initial) {
         | 
| 2270 | 
            +
                    memo = obj[index];
         | 
| 2271 | 
            +
                    initial = true;
         | 
| 2272 | 
            +
                  } else {
         | 
| 2273 | 
            +
                    memo = iterator.call(context, memo, obj[index], index, list);
         | 
| 2274 | 
            +
                  }
         | 
| 2275 | 
            +
                });
         | 
| 2276 | 
            +
                if (!initial) throw new TypeError(reduceError);
         | 
| 2277 | 
            +
                return memo;
         | 
| 2278 | 
            +
              };
         | 
| 2279 | 
            +
             | 
| 2280 | 
            +
              // Return the first value which passes a truth test. Aliased as `detect`.
         | 
| 2281 | 
            +
              _.find = _.detect = function(obj, iterator, context) {
         | 
| 2282 | 
            +
                var result;
         | 
| 2283 | 
            +
                any(obj, function(value, index, list) {
         | 
| 2284 | 
            +
                  if (iterator.call(context, value, index, list)) {
         | 
| 2285 | 
            +
                    result = value;
         | 
| 2286 | 
            +
                    return true;
         | 
| 2287 | 
            +
                  }
         | 
| 2288 | 
            +
                });
         | 
| 2289 | 
            +
                return result;
         | 
| 2290 | 
            +
              };
         | 
| 2291 | 
            +
             | 
| 2292 | 
            +
              // Return all the elements that pass a truth test.
         | 
| 2293 | 
            +
              // Delegates to **ECMAScript 5**'s native `filter` if available.
         | 
| 2294 | 
            +
              // Aliased as `select`.
         | 
| 2295 | 
            +
              _.filter = _.select = function(obj, iterator, context) {
         | 
| 2296 | 
            +
                var results = [];
         | 
| 2297 | 
            +
                if (obj == null) return results;
         | 
| 2298 | 
            +
                if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
         | 
| 2299 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2300 | 
            +
                  if (iterator.call(context, value, index, list)) results.push(value);
         | 
| 2301 | 
            +
                });
         | 
| 2302 | 
            +
                return results;
         | 
| 2303 | 
            +
              };
         | 
| 2304 | 
            +
             | 
| 2305 | 
            +
              // Return all the elements for which a truth test fails.
         | 
| 2306 | 
            +
              _.reject = function(obj, iterator, context) {
         | 
| 2307 | 
            +
                return _.filter(obj, function(value, index, list) {
         | 
| 2308 | 
            +
                  return !iterator.call(context, value, index, list);
         | 
| 2309 | 
            +
                }, context);
         | 
| 2310 | 
            +
              };
         | 
| 2311 | 
            +
             | 
| 2312 | 
            +
              // Determine whether all of the elements match a truth test.
         | 
| 2313 | 
            +
              // Delegates to **ECMAScript 5**'s native `every` if available.
         | 
| 2314 | 
            +
              // Aliased as `all`.
         | 
| 2315 | 
            +
              _.every = _.all = function(obj, iterator, context) {
         | 
| 2316 | 
            +
                iterator || (iterator = _.identity);
         | 
| 2317 | 
            +
                var result = true;
         | 
| 2318 | 
            +
                if (obj == null) return result;
         | 
| 2319 | 
            +
                if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
         | 
| 2320 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2321 | 
            +
                  if (!(result = result && iterator.call(context, value, index, list))) return breaker;
         | 
| 2322 | 
            +
                });
         | 
| 2323 | 
            +
                return !!result;
         | 
| 2324 | 
            +
              };
         | 
| 2325 | 
            +
             | 
| 2326 | 
            +
              // Determine if at least one element in the object matches a truth test.
         | 
| 2327 | 
            +
              // Delegates to **ECMAScript 5**'s native `some` if available.
         | 
| 2328 | 
            +
              // Aliased as `any`.
         | 
| 2329 | 
            +
              var any = _.some = _.any = function(obj, iterator, context) {
         | 
| 2330 | 
            +
                iterator || (iterator = _.identity);
         | 
| 2331 | 
            +
                var result = false;
         | 
| 2332 | 
            +
                if (obj == null) return result;
         | 
| 2333 | 
            +
                if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
         | 
| 2334 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2335 | 
            +
                  if (result || (result = iterator.call(context, value, index, list))) return breaker;
         | 
| 2336 | 
            +
                });
         | 
| 2337 | 
            +
                return !!result;
         | 
| 2338 | 
            +
              };
         | 
| 2339 | 
            +
             | 
| 2340 | 
            +
              // Determine if the array or object contains a given value (using `===`).
         | 
| 2341 | 
            +
              // Aliased as `include`.
         | 
| 2342 | 
            +
              _.contains = _.include = function(obj, target) {
         | 
| 2343 | 
            +
                if (obj == null) return false;
         | 
| 2344 | 
            +
                if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
         | 
| 2345 | 
            +
                return any(obj, function(value) {
         | 
| 2346 | 
            +
                  return value === target;
         | 
| 2347 | 
            +
                });
         | 
| 2348 | 
            +
              };
         | 
| 2349 | 
            +
             | 
| 2350 | 
            +
              // Invoke a method (with arguments) on every item in a collection.
         | 
| 2351 | 
            +
              _.invoke = function(obj, method) {
         | 
| 2352 | 
            +
                var args = slice.call(arguments, 2);
         | 
| 2353 | 
            +
                var isFunc = _.isFunction(method);
         | 
| 2354 | 
            +
                return _.map(obj, function(value) {
         | 
| 2355 | 
            +
                  return (isFunc ? method : value[method]).apply(value, args);
         | 
| 2356 | 
            +
                });
         | 
| 2357 | 
            +
              };
         | 
| 2358 | 
            +
             | 
| 2359 | 
            +
              // Convenience version of a common use case of `map`: fetching a property.
         | 
| 2360 | 
            +
              _.pluck = function(obj, key) {
         | 
| 2361 | 
            +
                return _.map(obj, function(value){ return value[key]; });
         | 
| 2362 | 
            +
              };
         | 
| 2363 | 
            +
             | 
| 2364 | 
            +
              // Convenience version of a common use case of `filter`: selecting only objects
         | 
| 2365 | 
            +
              // containing specific `key:value` pairs.
         | 
| 2366 | 
            +
              _.where = function(obj, attrs, first) {
         | 
| 2367 | 
            +
                if (_.isEmpty(attrs)) return first ? void 0 : [];
         | 
| 2368 | 
            +
                return _[first ? 'find' : 'filter'](obj, function(value) {
         | 
| 2369 | 
            +
                  for (var key in attrs) {
         | 
| 2370 | 
            +
                    if (attrs[key] !== value[key]) return false;
         | 
| 2371 | 
            +
                  }
         | 
| 2372 | 
            +
                  return true;
         | 
| 2373 | 
            +
                });
         | 
| 2374 | 
            +
              };
         | 
| 2375 | 
            +
             | 
| 2376 | 
            +
              // Convenience version of a common use case of `find`: getting the first object
         | 
| 2377 | 
            +
              // containing specific `key:value` pairs.
         | 
| 2378 | 
            +
              _.findWhere = function(obj, attrs) {
         | 
| 2379 | 
            +
                return _.where(obj, attrs, true);
         | 
| 2380 | 
            +
              };
         | 
| 2381 | 
            +
             | 
| 2382 | 
            +
              // Return the maximum element or (element-based computation).
         | 
| 2383 | 
            +
              // Can't optimize arrays of integers longer than 65,535 elements.
         | 
| 2384 | 
            +
              // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
         | 
| 2385 | 
            +
              _.max = function(obj, iterator, context) {
         | 
| 2386 | 
            +
                if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
         | 
| 2387 | 
            +
                  return Math.max.apply(Math, obj);
         | 
| 2388 | 
            +
                }
         | 
| 2389 | 
            +
                if (!iterator && _.isEmpty(obj)) return -Infinity;
         | 
| 2390 | 
            +
                var result = {computed : -Infinity, value: -Infinity};
         | 
| 2391 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2392 | 
            +
                  var computed = iterator ? iterator.call(context, value, index, list) : value;
         | 
| 2393 | 
            +
                  computed > result.computed && (result = {value : value, computed : computed});
         | 
| 2394 | 
            +
                });
         | 
| 2395 | 
            +
                return result.value;
         | 
| 2396 | 
            +
              };
         | 
| 2397 | 
            +
             | 
| 2398 | 
            +
              // Return the minimum element (or element-based computation).
         | 
| 2399 | 
            +
              _.min = function(obj, iterator, context) {
         | 
| 2400 | 
            +
                if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
         | 
| 2401 | 
            +
                  return Math.min.apply(Math, obj);
         | 
| 2402 | 
            +
                }
         | 
| 2403 | 
            +
                if (!iterator && _.isEmpty(obj)) return Infinity;
         | 
| 2404 | 
            +
                var result = {computed : Infinity, value: Infinity};
         | 
| 2405 | 
            +
                each(obj, function(value, index, list) {
         | 
| 2406 | 
            +
                  var computed = iterator ? iterator.call(context, value, index, list) : value;
         | 
| 2407 | 
            +
                  computed < result.computed && (result = {value : value, computed : computed});
         | 
| 2408 | 
            +
                });
         | 
| 2409 | 
            +
                return result.value;
         | 
| 2410 | 
            +
              };
         | 
| 2411 | 
            +
             | 
| 2412 | 
            +
              // Shuffle an array, using the modern version of the 
         | 
| 2413 | 
            +
              // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
         | 
| 2414 | 
            +
              _.shuffle = function(obj) {
         | 
| 2415 | 
            +
                var rand;
         | 
| 2416 | 
            +
                var index = 0;
         | 
| 2417 | 
            +
                var shuffled = [];
         | 
| 2418 | 
            +
                each(obj, function(value) {
         | 
| 2419 | 
            +
                  rand = _.random(index++);
         | 
| 2420 | 
            +
                  shuffled[index - 1] = shuffled[rand];
         | 
| 2421 | 
            +
                  shuffled[rand] = value;
         | 
| 2422 | 
            +
                });
         | 
| 2423 | 
            +
                return shuffled;
         | 
| 2424 | 
            +
              };
         | 
| 2425 | 
            +
             | 
| 2426 | 
            +
              // Sample **n** random values from an array.
         | 
| 2427 | 
            +
              // If **n** is not specified, returns a single random element from the array.
         | 
| 2428 | 
            +
              // The internal `guard` argument allows it to work with `map`.
         | 
| 2429 | 
            +
              _.sample = function(obj, n, guard) {
         | 
| 2430 | 
            +
                if (arguments.length < 2 || guard) {
         | 
| 2431 | 
            +
                  return obj[_.random(obj.length - 1)];
         | 
| 2432 | 
            +
                }
         | 
| 2433 | 
            +
                return _.shuffle(obj).slice(0, Math.max(0, n));
         | 
| 2434 | 
            +
              };
         | 
| 2435 | 
            +
             | 
| 2436 | 
            +
              // An internal function to generate lookup iterators.
         | 
| 2437 | 
            +
              var lookupIterator = function(value) {
         | 
| 2438 | 
            +
                return _.isFunction(value) ? value : function(obj){ return obj[value]; };
         | 
| 2439 | 
            +
              };
         | 
| 2440 | 
            +
             | 
| 2441 | 
            +
              // Sort the object's values by a criterion produced by an iterator.
         | 
| 2442 | 
            +
              _.sortBy = function(obj, value, context) {
         | 
| 2443 | 
            +
                var iterator = lookupIterator(value);
         | 
| 2444 | 
            +
                return _.pluck(_.map(obj, function(value, index, list) {
         | 
| 2445 | 
            +
                  return {
         | 
| 2446 | 
            +
                    value: value,
         | 
| 2447 | 
            +
                    index: index,
         | 
| 2448 | 
            +
                    criteria: iterator.call(context, value, index, list)
         | 
| 2449 | 
            +
                  };
         | 
| 2450 | 
            +
                }).sort(function(left, right) {
         | 
| 2451 | 
            +
                  var a = left.criteria;
         | 
| 2452 | 
            +
                  var b = right.criteria;
         | 
| 2453 | 
            +
                  if (a !== b) {
         | 
| 2454 | 
            +
                    if (a > b || a === void 0) return 1;
         | 
| 2455 | 
            +
                    if (a < b || b === void 0) return -1;
         | 
| 2456 | 
            +
                  }
         | 
| 2457 | 
            +
                  return left.index - right.index;
         | 
| 2458 | 
            +
                }), 'value');
         | 
| 2459 | 
            +
              };
         | 
| 2460 | 
            +
             | 
| 2461 | 
            +
              // An internal function used for aggregate "group by" operations.
         | 
| 2462 | 
            +
              var group = function(behavior) {
         | 
| 2463 | 
            +
                return function(obj, value, context) {
         | 
| 2464 | 
            +
                  var result = {};
         | 
| 2465 | 
            +
                  var iterator = value == null ? _.identity : lookupIterator(value);
         | 
| 2466 | 
            +
                  each(obj, function(value, index) {
         | 
| 2467 | 
            +
                    var key = iterator.call(context, value, index, obj);
         | 
| 2468 | 
            +
                    behavior(result, key, value);
         | 
| 2469 | 
            +
                  });
         | 
| 2470 | 
            +
                  return result;
         | 
| 2471 | 
            +
                };
         | 
| 2472 | 
            +
              };
         | 
| 2473 | 
            +
             | 
| 2474 | 
            +
              // Groups the object's values by a criterion. Pass either a string attribute
         | 
| 2475 | 
            +
              // to group by, or a function that returns the criterion.
         | 
| 2476 | 
            +
              _.groupBy = group(function(result, key, value) {
         | 
| 2477 | 
            +
                (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
         | 
| 2478 | 
            +
              });
         | 
| 2479 | 
            +
             | 
| 2480 | 
            +
              // Indexes the object's values by a criterion, similar to `groupBy`, but for
         | 
| 2481 | 
            +
              // when you know that your index values will be unique.
         | 
| 2482 | 
            +
              _.indexBy = group(function(result, key, value) {
         | 
| 2483 | 
            +
                result[key] = value;
         | 
| 2484 | 
            +
              });
         | 
| 2485 | 
            +
             | 
| 2486 | 
            +
              // Counts instances of an object that group by a certain criterion. Pass
         | 
| 2487 | 
            +
              // either a string attribute to count by, or a function that returns the
         | 
| 2488 | 
            +
              // criterion.
         | 
| 2489 | 
            +
              _.countBy = group(function(result, key) {
         | 
| 2490 | 
            +
                _.has(result, key) ? result[key]++ : result[key] = 1;
         | 
| 2491 | 
            +
              });
         | 
| 2492 | 
            +
             | 
| 2493 | 
            +
              // Use a comparator function to figure out the smallest index at which
         | 
| 2494 | 
            +
              // an object should be inserted so as to maintain order. Uses binary search.
         | 
| 2495 | 
            +
              _.sortedIndex = function(array, obj, iterator, context) {
         | 
| 2496 | 
            +
                iterator = iterator == null ? _.identity : lookupIterator(iterator);
         | 
| 2497 | 
            +
                var value = iterator.call(context, obj);
         | 
| 2498 | 
            +
                var low = 0, high = array.length;
         | 
| 2499 | 
            +
                while (low < high) {
         | 
| 2500 | 
            +
                  var mid = (low + high) >>> 1;
         | 
| 2501 | 
            +
                  iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
         | 
| 2502 | 
            +
                }
         | 
| 2503 | 
            +
                return low;
         | 
| 2504 | 
            +
              };
         | 
| 2505 | 
            +
             | 
| 2506 | 
            +
              // Safely create a real, live array from anything iterable.
         | 
| 2507 | 
            +
              _.toArray = function(obj) {
         | 
| 2508 | 
            +
                if (!obj) return [];
         | 
| 2509 | 
            +
                if (_.isArray(obj)) return slice.call(obj);
         | 
| 2510 | 
            +
                if (obj.length === +obj.length) return _.map(obj, _.identity);
         | 
| 2511 | 
            +
                return _.values(obj);
         | 
| 2512 | 
            +
              };
         | 
| 2513 | 
            +
             | 
| 2514 | 
            +
              // Return the number of elements in an object.
         | 
| 2515 | 
            +
              _.size = function(obj) {
         | 
| 2516 | 
            +
                if (obj == null) return 0;
         | 
| 2517 | 
            +
                return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
         | 
| 2518 | 
            +
              };
         | 
| 2519 | 
            +
             | 
| 2520 | 
            +
              // Array Functions
         | 
| 2521 | 
            +
              // ---------------
         | 
| 2522 | 
            +
             | 
| 2523 | 
            +
              // Get the first element of an array. Passing **n** will return the first N
         | 
| 2524 | 
            +
              // values in the array. Aliased as `head` and `take`. The **guard** check
         | 
| 2525 | 
            +
              // allows it to work with `_.map`.
         | 
| 2526 | 
            +
              _.first = _.head = _.take = function(array, n, guard) {
         | 
| 2527 | 
            +
                if (array == null) return void 0;
         | 
| 2528 | 
            +
                return (n == null) || guard ? array[0] : slice.call(array, 0, n);
         | 
| 2529 | 
            +
              };
         | 
| 2530 | 
            +
             | 
| 2531 | 
            +
              // Returns everything but the last entry of the array. Especially useful on
         | 
| 2532 | 
            +
              // the arguments object. Passing **n** will return all the values in
         | 
| 2533 | 
            +
              // the array, excluding the last N. The **guard** check allows it to work with
         | 
| 2534 | 
            +
              // `_.map`.
         | 
| 2535 | 
            +
              _.initial = function(array, n, guard) {
         | 
| 2536 | 
            +
                return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
         | 
| 2537 | 
            +
              };
         | 
| 2538 | 
            +
             | 
| 2539 | 
            +
              // Get the last element of an array. Passing **n** will return the last N
         | 
| 2540 | 
            +
              // values in the array. The **guard** check allows it to work with `_.map`.
         | 
| 2541 | 
            +
              _.last = function(array, n, guard) {
         | 
| 2542 | 
            +
                if (array == null) return void 0;
         | 
| 2543 | 
            +
                if ((n == null) || guard) {
         | 
| 2544 | 
            +
                  return array[array.length - 1];
         | 
| 2545 | 
            +
                } else {
         | 
| 2546 | 
            +
                  return slice.call(array, Math.max(array.length - n, 0));
         | 
| 2547 | 
            +
                }
         | 
| 2548 | 
            +
              };
         | 
| 2549 | 
            +
             | 
| 2550 | 
            +
              // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
         | 
| 2551 | 
            +
              // Especially useful on the arguments object. Passing an **n** will return
         | 
| 2552 | 
            +
              // the rest N values in the array. The **guard**
         | 
| 2553 | 
            +
              // check allows it to work with `_.map`.
         | 
| 2554 | 
            +
              _.rest = _.tail = _.drop = function(array, n, guard) {
         | 
| 2555 | 
            +
                return slice.call(array, (n == null) || guard ? 1 : n);
         | 
| 2556 | 
            +
              };
         | 
| 2557 | 
            +
             | 
| 2558 | 
            +
              // Trim out all falsy values from an array.
         | 
| 2559 | 
            +
              _.compact = function(array) {
         | 
| 2560 | 
            +
                return _.filter(array, _.identity);
         | 
| 2561 | 
            +
              };
         | 
| 2562 | 
            +
             | 
| 2563 | 
            +
              // Internal implementation of a recursive `flatten` function.
         | 
| 2564 | 
            +
              var flatten = function(input, shallow, output) {
         | 
| 2565 | 
            +
                if (shallow && _.every(input, _.isArray)) {
         | 
| 2566 | 
            +
                  return concat.apply(output, input);
         | 
| 2567 | 
            +
                }
         | 
| 2568 | 
            +
                each(input, function(value) {
         | 
| 2569 | 
            +
                  if (_.isArray(value) || _.isArguments(value)) {
         | 
| 2570 | 
            +
                    shallow ? push.apply(output, value) : flatten(value, shallow, output);
         | 
| 2571 | 
            +
                  } else {
         | 
| 2572 | 
            +
                    output.push(value);
         | 
| 2573 | 
            +
                  }
         | 
| 2574 | 
            +
                });
         | 
| 2575 | 
            +
                return output;
         | 
| 2576 | 
            +
              };
         | 
| 2577 | 
            +
             | 
| 2578 | 
            +
              // Flatten out an array, either recursively (by default), or just one level.
         | 
| 2579 | 
            +
              _.flatten = function(array, shallow) {
         | 
| 2580 | 
            +
                return flatten(array, shallow, []);
         | 
| 2581 | 
            +
              };
         | 
| 2582 | 
            +
             | 
| 2583 | 
            +
              // Return a version of the array that does not contain the specified value(s).
         | 
| 2584 | 
            +
              _.without = function(array) {
         | 
| 2585 | 
            +
                return _.difference(array, slice.call(arguments, 1));
         | 
| 2586 | 
            +
              };
         | 
| 2587 | 
            +
             | 
| 2588 | 
            +
              // Produce a duplicate-free version of the array. If the array has already
         | 
| 2589 | 
            +
              // been sorted, you have the option of using a faster algorithm.
         | 
| 2590 | 
            +
              // Aliased as `unique`.
         | 
| 2591 | 
            +
              _.uniq = _.unique = function(array, isSorted, iterator, context) {
         | 
| 2592 | 
            +
                if (_.isFunction(isSorted)) {
         | 
| 2593 | 
            +
                  context = iterator;
         | 
| 2594 | 
            +
                  iterator = isSorted;
         | 
| 2595 | 
            +
                  isSorted = false;
         | 
| 2596 | 
            +
                }
         | 
| 2597 | 
            +
                var initial = iterator ? _.map(array, iterator, context) : array;
         | 
| 2598 | 
            +
                var results = [];
         | 
| 2599 | 
            +
                var seen = [];
         | 
| 2600 | 
            +
                each(initial, function(value, index) {
         | 
| 2601 | 
            +
                  if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
         | 
| 2602 | 
            +
                    seen.push(value);
         | 
| 2603 | 
            +
                    results.push(array[index]);
         | 
| 2604 | 
            +
                  }
         | 
| 2605 | 
            +
                });
         | 
| 2606 | 
            +
                return results;
         | 
| 2607 | 
            +
              };
         | 
| 2608 | 
            +
             | 
| 2609 | 
            +
              // Produce an array that contains the union: each distinct element from all of
         | 
| 2610 | 
            +
              // the passed-in arrays.
         | 
| 2611 | 
            +
              _.union = function() {
         | 
| 2612 | 
            +
                return _.uniq(_.flatten(arguments, true));
         | 
| 2613 | 
            +
              };
         | 
| 2614 | 
            +
             | 
| 2615 | 
            +
              // Produce an array that contains every item shared between all the
         | 
| 2616 | 
            +
              // passed-in arrays.
         | 
| 2617 | 
            +
              _.intersection = function(array) {
         | 
| 2618 | 
            +
                var rest = slice.call(arguments, 1);
         | 
| 2619 | 
            +
                return _.filter(_.uniq(array), function(item) {
         | 
| 2620 | 
            +
                  return _.every(rest, function(other) {
         | 
| 2621 | 
            +
                    return _.indexOf(other, item) >= 0;
         | 
| 2622 | 
            +
                  });
         | 
| 2623 | 
            +
                });
         | 
| 2624 | 
            +
              };
         | 
| 2625 | 
            +
             | 
| 2626 | 
            +
              // Take the difference between one array and a number of other arrays.
         | 
| 2627 | 
            +
              // Only the elements present in just the first array will remain.
         | 
| 2628 | 
            +
              _.difference = function(array) {
         | 
| 2629 | 
            +
                var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
         | 
| 2630 | 
            +
                return _.filter(array, function(value){ return !_.contains(rest, value); });
         | 
| 2631 | 
            +
              };
         | 
| 2632 | 
            +
             | 
| 2633 | 
            +
              // Zip together multiple lists into a single array -- elements that share
         | 
| 2634 | 
            +
              // an index go together.
         | 
| 2635 | 
            +
              _.zip = function() {
         | 
| 2636 | 
            +
                var length = _.max(_.pluck(arguments, "length").concat(0));
         | 
| 2637 | 
            +
                var results = new Array(length);
         | 
| 2638 | 
            +
                for (var i = 0; i < length; i++) {
         | 
| 2639 | 
            +
                  results[i] = _.pluck(arguments, '' + i);
         | 
| 2640 | 
            +
                }
         | 
| 2641 | 
            +
                return results;
         | 
| 2642 | 
            +
              };
         | 
| 2643 | 
            +
             | 
| 2644 | 
            +
              // Converts lists into objects. Pass either a single array of `[key, value]`
         | 
| 2645 | 
            +
              // pairs, or two parallel arrays of the same length -- one of keys, and one of
         | 
| 2646 | 
            +
              // the corresponding values.
         | 
| 2647 | 
            +
              _.object = function(list, values) {
         | 
| 2648 | 
            +
                if (list == null) return {};
         | 
| 2649 | 
            +
                var result = {};
         | 
| 2650 | 
            +
                for (var i = 0, length = list.length; i < length; i++) {
         | 
| 2651 | 
            +
                  if (values) {
         | 
| 2652 | 
            +
                    result[list[i]] = values[i];
         | 
| 2653 | 
            +
                  } else {
         | 
| 2654 | 
            +
                    result[list[i][0]] = list[i][1];
         | 
| 2655 | 
            +
                  }
         | 
| 2656 | 
            +
                }
         | 
| 2657 | 
            +
                return result;
         | 
| 2658 | 
            +
              };
         | 
| 2659 | 
            +
             | 
| 2660 | 
            +
              // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
         | 
| 2661 | 
            +
              // we need this function. Return the position of the first occurrence of an
         | 
| 2662 | 
            +
              // item in an array, or -1 if the item is not included in the array.
         | 
| 2663 | 
            +
              // Delegates to **ECMAScript 5**'s native `indexOf` if available.
         | 
| 2664 | 
            +
              // If the array is large and already in sort order, pass `true`
         | 
| 2665 | 
            +
              // for **isSorted** to use binary search.
         | 
| 2666 | 
            +
              _.indexOf = function(array, item, isSorted) {
         | 
| 2667 | 
            +
                if (array == null) return -1;
         | 
| 2668 | 
            +
                var i = 0, length = array.length;
         | 
| 2669 | 
            +
                if (isSorted) {
         | 
| 2670 | 
            +
                  if (typeof isSorted == 'number') {
         | 
| 2671 | 
            +
                    i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
         | 
| 2672 | 
            +
                  } else {
         | 
| 2673 | 
            +
                    i = _.sortedIndex(array, item);
         | 
| 2674 | 
            +
                    return array[i] === item ? i : -1;
         | 
| 2675 | 
            +
                  }
         | 
| 2676 | 
            +
                }
         | 
| 2677 | 
            +
                if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
         | 
| 2678 | 
            +
                for (; i < length; i++) if (array[i] === item) return i;
         | 
| 2679 | 
            +
                return -1;
         | 
| 2680 | 
            +
              };
         | 
| 2681 | 
            +
             | 
| 2682 | 
            +
              // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
         | 
| 2683 | 
            +
              _.lastIndexOf = function(array, item, from) {
         | 
| 2684 | 
            +
                if (array == null) return -1;
         | 
| 2685 | 
            +
                var hasIndex = from != null;
         | 
| 2686 | 
            +
                if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
         | 
| 2687 | 
            +
                  return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
         | 
| 2688 | 
            +
                }
         | 
| 2689 | 
            +
                var i = (hasIndex ? from : array.length);
         | 
| 2690 | 
            +
                while (i--) if (array[i] === item) return i;
         | 
| 2691 | 
            +
                return -1;
         | 
| 2692 | 
            +
              };
         | 
| 2693 | 
            +
             | 
| 2694 | 
            +
              // Generate an integer Array containing an arithmetic progression. A port of
         | 
| 2695 | 
            +
              // the native Python `range()` function. See
         | 
| 2696 | 
            +
              // [the Python documentation](http://docs.python.org/library/functions.html#range).
         | 
| 2697 | 
            +
              _.range = function(start, stop, step) {
         | 
| 2698 | 
            +
                if (arguments.length <= 1) {
         | 
| 2699 | 
            +
                  stop = start || 0;
         | 
| 2700 | 
            +
                  start = 0;
         | 
| 2701 | 
            +
                }
         | 
| 2702 | 
            +
                step = arguments[2] || 1;
         | 
| 2703 | 
            +
             | 
| 2704 | 
            +
                var length = Math.max(Math.ceil((stop - start) / step), 0);
         | 
| 2705 | 
            +
                var idx = 0;
         | 
| 2706 | 
            +
                var range = new Array(length);
         | 
| 2707 | 
            +
             | 
| 2708 | 
            +
                while(idx < length) {
         | 
| 2709 | 
            +
                  range[idx++] = start;
         | 
| 2710 | 
            +
                  start += step;
         | 
| 2711 | 
            +
                }
         | 
| 2712 | 
            +
             | 
| 2713 | 
            +
                return range;
         | 
| 2714 | 
            +
              };
         | 
| 2715 | 
            +
             | 
| 2716 | 
            +
              // Function (ahem) Functions
         | 
| 2717 | 
            +
              // ------------------
         | 
| 2718 | 
            +
             | 
| 2719 | 
            +
              // Reusable constructor function for prototype setting.
         | 
| 2720 | 
            +
              var ctor = function(){};
         | 
| 2721 | 
            +
             | 
| 2722 | 
            +
              // Create a function bound to a given object (assigning `this`, and arguments,
         | 
| 2723 | 
            +
              // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
         | 
| 2724 | 
            +
              // available.
         | 
| 2725 | 
            +
              _.bind = function(func, context) {
         | 
| 2726 | 
            +
                var args, bound;
         | 
| 2727 | 
            +
                if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
         | 
| 2728 | 
            +
                if (!_.isFunction(func)) throw new TypeError;
         | 
| 2729 | 
            +
                args = slice.call(arguments, 2);
         | 
| 2730 | 
            +
                return bound = function() {
         | 
| 2731 | 
            +
                  if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
         | 
| 2732 | 
            +
                  ctor.prototype = func.prototype;
         | 
| 2733 | 
            +
                  var self = new ctor;
         | 
| 2734 | 
            +
                  ctor.prototype = null;
         | 
| 2735 | 
            +
                  var result = func.apply(self, args.concat(slice.call(arguments)));
         | 
| 2736 | 
            +
                  if (Object(result) === result) return result;
         | 
| 2737 | 
            +
                  return self;
         | 
| 2738 | 
            +
                };
         | 
| 2739 | 
            +
              };
         | 
| 2740 | 
            +
             | 
| 2741 | 
            +
              // Partially apply a function by creating a version that has had some of its
         | 
| 2742 | 
            +
              // arguments pre-filled, without changing its dynamic `this` context.
         | 
| 2743 | 
            +
              _.partial = function(func) {
         | 
| 2744 | 
            +
                var args = slice.call(arguments, 1);
         | 
| 2745 | 
            +
                return function() {
         | 
| 2746 | 
            +
                  return func.apply(this, args.concat(slice.call(arguments)));
         | 
| 2747 | 
            +
                };
         | 
| 2748 | 
            +
              };
         | 
| 2749 | 
            +
             | 
| 2750 | 
            +
              // Bind all of an object's methods to that object. Useful for ensuring that
         | 
| 2751 | 
            +
              // all callbacks defined on an object belong to it.
         | 
| 2752 | 
            +
              _.bindAll = function(obj) {
         | 
| 2753 | 
            +
                var funcs = slice.call(arguments, 1);
         | 
| 2754 | 
            +
                if (funcs.length === 0) throw new Error("bindAll must be passed function names");
         | 
| 2755 | 
            +
                each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
         | 
| 2756 | 
            +
                return obj;
         | 
| 2757 | 
            +
              };
         | 
| 2758 | 
            +
             | 
| 2759 | 
            +
              // Memoize an expensive function by storing its results.
         | 
| 2760 | 
            +
              _.memoize = function(func, hasher) {
         | 
| 2761 | 
            +
                var memo = {};
         | 
| 2762 | 
            +
                hasher || (hasher = _.identity);
         | 
| 2763 | 
            +
                return function() {
         | 
| 2764 | 
            +
                  var key = hasher.apply(this, arguments);
         | 
| 2765 | 
            +
                  return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
         | 
| 2766 | 
            +
                };
         | 
| 2767 | 
            +
              };
         | 
| 2768 | 
            +
             | 
| 2769 | 
            +
              // Delays a function for the given number of milliseconds, and then calls
         | 
| 2770 | 
            +
              // it with the arguments supplied.
         | 
| 2771 | 
            +
              _.delay = function(func, wait) {
         | 
| 2772 | 
            +
                var args = slice.call(arguments, 2);
         | 
| 2773 | 
            +
                return setTimeout(function(){ return func.apply(null, args); }, wait);
         | 
| 2774 | 
            +
              };
         | 
| 2775 | 
            +
             | 
| 2776 | 
            +
              // Defers a function, scheduling it to run after the current call stack has
         | 
| 2777 | 
            +
              // cleared.
         | 
| 2778 | 
            +
              _.defer = function(func) {
         | 
| 2779 | 
            +
                return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
         | 
| 2780 | 
            +
              };
         | 
| 2781 | 
            +
             | 
| 2782 | 
            +
              // Returns a function, that, when invoked, will only be triggered at most once
         | 
| 2783 | 
            +
              // during a given window of time. Normally, the throttled function will run
         | 
| 2784 | 
            +
              // as much as it can, without ever going more than once per `wait` duration;
         | 
| 2785 | 
            +
              // but if you'd like to disable the execution on the leading edge, pass
         | 
| 2786 | 
            +
              // `{leading: false}`. To disable execution on the trailing edge, ditto.
         | 
| 2787 | 
            +
              _.throttle = function(func, wait, options) {
         | 
| 2788 | 
            +
                var context, args, result;
         | 
| 2789 | 
            +
                var timeout = null;
         | 
| 2790 | 
            +
                var previous = 0;
         | 
| 2791 | 
            +
                options || (options = {});
         | 
| 2792 | 
            +
                var later = function() {
         | 
| 2793 | 
            +
                  previous = options.leading === false ? 0 : new Date;
         | 
| 2794 | 
            +
                  timeout = null;
         | 
| 2795 | 
            +
                  result = func.apply(context, args);
         | 
| 2796 | 
            +
                };
         | 
| 2797 | 
            +
                return function() {
         | 
| 2798 | 
            +
                  var now = new Date;
         | 
| 2799 | 
            +
                  if (!previous && options.leading === false) previous = now;
         | 
| 2800 | 
            +
                  var remaining = wait - (now - previous);
         | 
| 2801 | 
            +
                  context = this;
         | 
| 2802 | 
            +
                  args = arguments;
         | 
| 2803 | 
            +
                  if (remaining <= 0) {
         | 
| 2804 | 
            +
                    clearTimeout(timeout);
         | 
| 2805 | 
            +
                    timeout = null;
         | 
| 2806 | 
            +
                    previous = now;
         | 
| 2807 | 
            +
                    result = func.apply(context, args);
         | 
| 2808 | 
            +
                  } else if (!timeout && options.trailing !== false) {
         | 
| 2809 | 
            +
                    timeout = setTimeout(later, remaining);
         | 
| 2810 | 
            +
                  }
         | 
| 2811 | 
            +
                  return result;
         | 
| 2812 | 
            +
                };
         | 
| 2813 | 
            +
              };
         | 
| 2814 | 
            +
             | 
| 2815 | 
            +
              // Returns a function, that, as long as it continues to be invoked, will not
         | 
| 2816 | 
            +
              // be triggered. The function will be called after it stops being called for
         | 
| 2817 | 
            +
              // N milliseconds. If `immediate` is passed, trigger the function on the
         | 
| 2818 | 
            +
              // leading edge, instead of the trailing.
         | 
| 2819 | 
            +
              _.debounce = function(func, wait, immediate) {
         | 
| 2820 | 
            +
                var timeout, args, context, timestamp, result;
         | 
| 2821 | 
            +
                return function() {
         | 
| 2822 | 
            +
                  context = this;
         | 
| 2823 | 
            +
                  args = arguments;
         | 
| 2824 | 
            +
                  timestamp = new Date();
         | 
| 2825 | 
            +
                  var later = function() {
         | 
| 2826 | 
            +
                    var last = (new Date()) - timestamp;
         | 
| 2827 | 
            +
                    if (last < wait) {
         | 
| 2828 | 
            +
                      timeout = setTimeout(later, wait - last);
         | 
| 2829 | 
            +
                    } else {
         | 
| 2830 | 
            +
                      timeout = null;
         | 
| 2831 | 
            +
                      if (!immediate) result = func.apply(context, args);
         | 
| 2832 | 
            +
                    }
         | 
| 2833 | 
            +
                  };
         | 
| 2834 | 
            +
                  var callNow = immediate && !timeout;
         | 
| 2835 | 
            +
                  if (!timeout) {
         | 
| 2836 | 
            +
                    timeout = setTimeout(later, wait);
         | 
| 2837 | 
            +
                  }
         | 
| 2838 | 
            +
                  if (callNow) result = func.apply(context, args);
         | 
| 2839 | 
            +
                  return result;
         | 
| 2840 | 
            +
                };
         | 
| 2841 | 
            +
              };
         | 
| 2842 | 
            +
             | 
| 2843 | 
            +
              // Returns a function that will be executed at most one time, no matter how
         | 
| 2844 | 
            +
              // often you call it. Useful for lazy initialization.
         | 
| 2845 | 
            +
              _.once = function(func) {
         | 
| 2846 | 
            +
                var ran = false, memo;
         | 
| 2847 | 
            +
                return function() {
         | 
| 2848 | 
            +
                  if (ran) return memo;
         | 
| 2849 | 
            +
                  ran = true;
         | 
| 2850 | 
            +
                  memo = func.apply(this, arguments);
         | 
| 2851 | 
            +
                  func = null;
         | 
| 2852 | 
            +
                  return memo;
         | 
| 2853 | 
            +
                };
         | 
| 2854 | 
            +
              };
         | 
| 2855 | 
            +
             | 
| 2856 | 
            +
              // Returns the first function passed as an argument to the second,
         | 
| 2857 | 
            +
              // allowing you to adjust arguments, run code before and after, and
         | 
| 2858 | 
            +
              // conditionally execute the original function.
         | 
| 2859 | 
            +
              _.wrap = function(func, wrapper) {
         | 
| 2860 | 
            +
                return function() {
         | 
| 2861 | 
            +
                  var args = [func];
         | 
| 2862 | 
            +
                  push.apply(args, arguments);
         | 
| 2863 | 
            +
                  return wrapper.apply(this, args);
         | 
| 2864 | 
            +
                };
         | 
| 2865 | 
            +
              };
         | 
| 2866 | 
            +
             | 
| 2867 | 
            +
              // Returns a function that is the composition of a list of functions, each
         | 
| 2868 | 
            +
              // consuming the return value of the function that follows.
         | 
| 2869 | 
            +
              _.compose = function() {
         | 
| 2870 | 
            +
                var funcs = arguments;
         | 
| 2871 | 
            +
                return function() {
         | 
| 2872 | 
            +
                  var args = arguments;
         | 
| 2873 | 
            +
                  for (var i = funcs.length - 1; i >= 0; i--) {
         | 
| 2874 | 
            +
                    args = [funcs[i].apply(this, args)];
         | 
| 2875 | 
            +
                  }
         | 
| 2876 | 
            +
                  return args[0];
         | 
| 2877 | 
            +
                };
         | 
| 2878 | 
            +
              };
         | 
| 2879 | 
            +
             | 
| 2880 | 
            +
              // Returns a function that will only be executed after being called N times.
         | 
| 2881 | 
            +
              _.after = function(times, func) {
         | 
| 2882 | 
            +
                return function() {
         | 
| 2883 | 
            +
                  if (--times < 1) {
         | 
| 2884 | 
            +
                    return func.apply(this, arguments);
         | 
| 2885 | 
            +
                  }
         | 
| 2886 | 
            +
                };
         | 
| 2887 | 
            +
              };
         | 
| 2888 | 
            +
             | 
| 2889 | 
            +
              // Object Functions
         | 
| 2890 | 
            +
              // ----------------
         | 
| 2891 | 
            +
             | 
| 2892 | 
            +
              // Retrieve the names of an object's properties.
         | 
| 2893 | 
            +
              // Delegates to **ECMAScript 5**'s native `Object.keys`
         | 
| 2894 | 
            +
              _.keys = nativeKeys || function(obj) {
         | 
| 2895 | 
            +
                if (obj !== Object(obj)) throw new TypeError('Invalid object');
         | 
| 2896 | 
            +
                var keys = [];
         | 
| 2897 | 
            +
                for (var key in obj) if (_.has(obj, key)) keys.push(key);
         | 
| 2898 | 
            +
                return keys;
         | 
| 2899 | 
            +
              };
         | 
| 2900 | 
            +
             | 
| 2901 | 
            +
              // Retrieve the values of an object's properties.
         | 
| 2902 | 
            +
              _.values = function(obj) {
         | 
| 2903 | 
            +
                var keys = _.keys(obj);
         | 
| 2904 | 
            +
                var length = keys.length;
         | 
| 2905 | 
            +
                var values = new Array(length);
         | 
| 2906 | 
            +
                for (var i = 0; i < length; i++) {
         | 
| 2907 | 
            +
                  values[i] = obj[keys[i]];
         | 
| 2908 | 
            +
                }
         | 
| 2909 | 
            +
                return values;
         | 
| 2910 | 
            +
              };
         | 
| 2911 | 
            +
             | 
| 2912 | 
            +
              // Convert an object into a list of `[key, value]` pairs.
         | 
| 2913 | 
            +
              _.pairs = function(obj) {
         | 
| 2914 | 
            +
                var keys = _.keys(obj);
         | 
| 2915 | 
            +
                var length = keys.length;
         | 
| 2916 | 
            +
                var pairs = new Array(length);
         | 
| 2917 | 
            +
                for (var i = 0; i < length; i++) {
         | 
| 2918 | 
            +
                  pairs[i] = [keys[i], obj[keys[i]]];
         | 
| 2919 | 
            +
                }
         | 
| 2920 | 
            +
                return pairs;
         | 
| 2921 | 
            +
              };
         | 
| 2922 | 
            +
             | 
| 2923 | 
            +
              // Invert the keys and values of an object. The values must be serializable.
         | 
| 2924 | 
            +
              _.invert = function(obj) {
         | 
| 2925 | 
            +
                var result = {};
         | 
| 2926 | 
            +
                var keys = _.keys(obj);
         | 
| 2927 | 
            +
                for (var i = 0, length = keys.length; i < length; i++) {
         | 
| 2928 | 
            +
                  result[obj[keys[i]]] = keys[i];
         | 
| 2929 | 
            +
                }
         | 
| 2930 | 
            +
                return result;
         | 
| 2931 | 
            +
              };
         | 
| 2932 | 
            +
             | 
| 2933 | 
            +
              // Return a sorted list of the function names available on the object.
         | 
| 2934 | 
            +
              // Aliased as `methods`
         | 
| 2935 | 
            +
              _.functions = _.methods = function(obj) {
         | 
| 2936 | 
            +
                var names = [];
         | 
| 2937 | 
            +
                for (var key in obj) {
         | 
| 2938 | 
            +
                  if (_.isFunction(obj[key])) names.push(key);
         | 
| 2939 | 
            +
                }
         | 
| 2940 | 
            +
                return names.sort();
         | 
| 2941 | 
            +
              };
         | 
| 2942 | 
            +
             | 
| 2943 | 
            +
              // Extend a given object with all the properties in passed-in object(s).
         | 
| 2944 | 
            +
              _.extend = function(obj) {
         | 
| 2945 | 
            +
                each(slice.call(arguments, 1), function(source) {
         | 
| 2946 | 
            +
                  if (source) {
         | 
| 2947 | 
            +
                    for (var prop in source) {
         | 
| 2948 | 
            +
                      obj[prop] = source[prop];
         | 
| 2949 | 
            +
                    }
         | 
| 2950 | 
            +
                  }
         | 
| 2951 | 
            +
                });
         | 
| 2952 | 
            +
                return obj;
         | 
| 2953 | 
            +
              };
         | 
| 2954 | 
            +
             | 
| 2955 | 
            +
              // Return a copy of the object only containing the whitelisted properties.
         | 
| 2956 | 
            +
              _.pick = function(obj) {
         | 
| 2957 | 
            +
                var copy = {};
         | 
| 2958 | 
            +
                var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
         | 
| 2959 | 
            +
                each(keys, function(key) {
         | 
| 2960 | 
            +
                  if (key in obj) copy[key] = obj[key];
         | 
| 2961 | 
            +
                });
         | 
| 2962 | 
            +
                return copy;
         | 
| 2963 | 
            +
              };
         | 
| 2964 | 
            +
             | 
| 2965 | 
            +
               // Return a copy of the object without the blacklisted properties.
         | 
| 2966 | 
            +
              _.omit = function(obj) {
         | 
| 2967 | 
            +
                var copy = {};
         | 
| 2968 | 
            +
                var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
         | 
| 2969 | 
            +
                for (var key in obj) {
         | 
| 2970 | 
            +
                  if (!_.contains(keys, key)) copy[key] = obj[key];
         | 
| 2971 | 
            +
                }
         | 
| 2972 | 
            +
                return copy;
         | 
| 2973 | 
            +
              };
         | 
| 2974 | 
            +
             | 
| 2975 | 
            +
              // Fill in a given object with default properties.
         | 
| 2976 | 
            +
              _.defaults = function(obj) {
         | 
| 2977 | 
            +
                each(slice.call(arguments, 1), function(source) {
         | 
| 2978 | 
            +
                  if (source) {
         | 
| 2979 | 
            +
                    for (var prop in source) {
         | 
| 2980 | 
            +
                      if (obj[prop] === void 0) obj[prop] = source[prop];
         | 
| 2981 | 
            +
                    }
         | 
| 2982 | 
            +
                  }
         | 
| 2983 | 
            +
                });
         | 
| 2984 | 
            +
                return obj;
         | 
| 2985 | 
            +
              };
         | 
| 2986 | 
            +
             | 
| 2987 | 
            +
              // Create a (shallow-cloned) duplicate of an object.
         | 
| 2988 | 
            +
              _.clone = function(obj) {
         | 
| 2989 | 
            +
                if (!_.isObject(obj)) return obj;
         | 
| 2990 | 
            +
                return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
         | 
| 2991 | 
            +
              };
         | 
| 2992 | 
            +
             | 
| 2993 | 
            +
              // Invokes interceptor with the obj, and then returns obj.
         | 
| 2994 | 
            +
              // The primary purpose of this method is to "tap into" a method chain, in
         | 
| 2995 | 
            +
              // order to perform operations on intermediate results within the chain.
         | 
| 2996 | 
            +
              _.tap = function(obj, interceptor) {
         | 
| 2997 | 
            +
                interceptor(obj);
         | 
| 2998 | 
            +
                return obj;
         | 
| 2999 | 
            +
              };
         | 
| 3000 | 
            +
             | 
| 3001 | 
            +
              // Internal recursive comparison function for `isEqual`.
         | 
| 3002 | 
            +
              var eq = function(a, b, aStack, bStack) {
         | 
| 3003 | 
            +
                // Identical objects are equal. `0 === -0`, but they aren't identical.
         | 
| 3004 | 
            +
                // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
         | 
| 3005 | 
            +
                if (a === b) return a !== 0 || 1 / a == 1 / b;
         | 
| 3006 | 
            +
                // A strict comparison is necessary because `null == undefined`.
         | 
| 3007 | 
            +
                if (a == null || b == null) return a === b;
         | 
| 3008 | 
            +
                // Unwrap any wrapped objects.
         | 
| 3009 | 
            +
                if (a instanceof _) a = a._wrapped;
         | 
| 3010 | 
            +
                if (b instanceof _) b = b._wrapped;
         | 
| 3011 | 
            +
                // Compare `[[Class]]` names.
         | 
| 3012 | 
            +
                var className = toString.call(a);
         | 
| 3013 | 
            +
                if (className != toString.call(b)) return false;
         | 
| 3014 | 
            +
                switch (className) {
         | 
| 3015 | 
            +
                  // Strings, numbers, dates, and booleans are compared by value.
         | 
| 3016 | 
            +
                  case '[object String]':
         | 
| 3017 | 
            +
                    // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
         | 
| 3018 | 
            +
                    // equivalent to `new String("5")`.
         | 
| 3019 | 
            +
                    return a == String(b);
         | 
| 3020 | 
            +
                  case '[object Number]':
         | 
| 3021 | 
            +
                    // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
         | 
| 3022 | 
            +
                    // other numeric values.
         | 
| 3023 | 
            +
                    return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
         | 
| 3024 | 
            +
                  case '[object Date]':
         | 
| 3025 | 
            +
                  case '[object Boolean]':
         | 
| 3026 | 
            +
                    // Coerce dates and booleans to numeric primitive values. Dates are compared by their
         | 
| 3027 | 
            +
                    // millisecond representations. Note that invalid dates with millisecond representations
         | 
| 3028 | 
            +
                    // of `NaN` are not equivalent.
         | 
| 3029 | 
            +
                    return +a == +b;
         | 
| 3030 | 
            +
                  // RegExps are compared by their source patterns and flags.
         | 
| 3031 | 
            +
                  case '[object RegExp]':
         | 
| 3032 | 
            +
                    return a.source == b.source &&
         | 
| 3033 | 
            +
                           a.global == b.global &&
         | 
| 3034 | 
            +
                           a.multiline == b.multiline &&
         | 
| 3035 | 
            +
                           a.ignoreCase == b.ignoreCase;
         | 
| 3036 | 
            +
                }
         | 
| 3037 | 
            +
                if (typeof a != 'object' || typeof b != 'object') return false;
         | 
| 3038 | 
            +
                // Assume equality for cyclic structures. The algorithm for detecting cyclic
         | 
| 3039 | 
            +
                // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
         | 
| 3040 | 
            +
                var length = aStack.length;
         | 
| 3041 | 
            +
                while (length--) {
         | 
| 3042 | 
            +
                  // Linear search. Performance is inversely proportional to the number of
         | 
| 3043 | 
            +
                  // unique nested structures.
         | 
| 3044 | 
            +
                  if (aStack[length] == a) return bStack[length] == b;
         | 
| 3045 | 
            +
                }
         | 
| 3046 | 
            +
                // Objects with different constructors are not equivalent, but `Object`s
         | 
| 3047 | 
            +
                // from different frames are.
         | 
| 3048 | 
            +
                var aCtor = a.constructor, bCtor = b.constructor;
         | 
| 3049 | 
            +
                if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
         | 
| 3050 | 
            +
                                         _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
         | 
| 3051 | 
            +
                  return false;
         | 
| 3052 | 
            +
                }
         | 
| 3053 | 
            +
                // Add the first object to the stack of traversed objects.
         | 
| 3054 | 
            +
                aStack.push(a);
         | 
| 3055 | 
            +
                bStack.push(b);
         | 
| 3056 | 
            +
                var size = 0, result = true;
         | 
| 3057 | 
            +
                // Recursively compare objects and arrays.
         | 
| 3058 | 
            +
                if (className == '[object Array]') {
         | 
| 3059 | 
            +
                  // Compare array lengths to determine if a deep comparison is necessary.
         | 
| 3060 | 
            +
                  size = a.length;
         | 
| 3061 | 
            +
                  result = size == b.length;
         | 
| 3062 | 
            +
                  if (result) {
         | 
| 3063 | 
            +
                    // Deep compare the contents, ignoring non-numeric properties.
         | 
| 3064 | 
            +
                    while (size--) {
         | 
| 3065 | 
            +
                      if (!(result = eq(a[size], b[size], aStack, bStack))) break;
         | 
| 3066 | 
            +
                    }
         | 
| 3067 | 
            +
                  }
         | 
| 3068 | 
            +
                } else {
         | 
| 3069 | 
            +
                  // Deep compare objects.
         | 
| 3070 | 
            +
                  for (var key in a) {
         | 
| 3071 | 
            +
                    if (_.has(a, key)) {
         | 
| 3072 | 
            +
                      // Count the expected number of properties.
         | 
| 3073 | 
            +
                      size++;
         | 
| 3074 | 
            +
                      // Deep compare each member.
         | 
| 3075 | 
            +
                      if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
         | 
| 3076 | 
            +
                    }
         | 
| 3077 | 
            +
                  }
         | 
| 3078 | 
            +
                  // Ensure that both objects contain the same number of properties.
         | 
| 3079 | 
            +
                  if (result) {
         | 
| 3080 | 
            +
                    for (key in b) {
         | 
| 3081 | 
            +
                      if (_.has(b, key) && !(size--)) break;
         | 
| 3082 | 
            +
                    }
         | 
| 3083 | 
            +
                    result = !size;
         | 
| 3084 | 
            +
                  }
         | 
| 3085 | 
            +
                }
         | 
| 3086 | 
            +
                // Remove the first object from the stack of traversed objects.
         | 
| 3087 | 
            +
                aStack.pop();
         | 
| 3088 | 
            +
                bStack.pop();
         | 
| 3089 | 
            +
                return result;
         | 
| 3090 | 
            +
              };
         | 
| 3091 | 
            +
             | 
| 3092 | 
            +
              // Perform a deep comparison to check if two objects are equal.
         | 
| 3093 | 
            +
              _.isEqual = function(a, b) {
         | 
| 3094 | 
            +
                return eq(a, b, [], []);
         | 
| 3095 | 
            +
              };
         | 
| 3096 | 
            +
             | 
| 3097 | 
            +
              // Is a given array, string, or object empty?
         | 
| 3098 | 
            +
              // An "empty" object has no enumerable own-properties.
         | 
| 3099 | 
            +
              _.isEmpty = function(obj) {
         | 
| 3100 | 
            +
                if (obj == null) return true;
         | 
| 3101 | 
            +
                if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
         | 
| 3102 | 
            +
                for (var key in obj) if (_.has(obj, key)) return false;
         | 
| 3103 | 
            +
                return true;
         | 
| 3104 | 
            +
              };
         | 
| 3105 | 
            +
             | 
| 3106 | 
            +
              // Is a given value a DOM element?
         | 
| 3107 | 
            +
              _.isElement = function(obj) {
         | 
| 3108 | 
            +
                return !!(obj && obj.nodeType === 1);
         | 
| 3109 | 
            +
              };
         | 
| 3110 | 
            +
             | 
| 3111 | 
            +
              // Is a given value an array?
         | 
| 3112 | 
            +
              // Delegates to ECMA5's native Array.isArray
         | 
| 3113 | 
            +
              _.isArray = nativeIsArray || function(obj) {
         | 
| 3114 | 
            +
                return toString.call(obj) == '[object Array]';
         | 
| 3115 | 
            +
              };
         | 
| 3116 | 
            +
             | 
| 3117 | 
            +
              // Is a given variable an object?
         | 
| 3118 | 
            +
              _.isObject = function(obj) {
         | 
| 3119 | 
            +
                return obj === Object(obj);
         | 
| 3120 | 
            +
              };
         | 
| 3121 | 
            +
             | 
| 3122 | 
            +
              // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
         | 
| 3123 | 
            +
              each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
         | 
| 3124 | 
            +
                _['is' + name] = function(obj) {
         | 
| 3125 | 
            +
                  return toString.call(obj) == '[object ' + name + ']';
         | 
| 3126 | 
            +
                };
         | 
| 3127 | 
            +
              });
         | 
| 3128 | 
            +
             | 
| 3129 | 
            +
              // Define a fallback version of the method in browsers (ahem, IE), where
         | 
| 3130 | 
            +
              // there isn't any inspectable "Arguments" type.
         | 
| 3131 | 
            +
              if (!_.isArguments(arguments)) {
         | 
| 3132 | 
            +
                _.isArguments = function(obj) {
         | 
| 3133 | 
            +
                  return !!(obj && _.has(obj, 'callee'));
         | 
| 3134 | 
            +
                };
         | 
| 3135 | 
            +
              }
         | 
| 3136 | 
            +
             | 
| 3137 | 
            +
              // Optimize `isFunction` if appropriate.
         | 
| 3138 | 
            +
              if (typeof (/./) !== 'function') {
         | 
| 3139 | 
            +
                _.isFunction = function(obj) {
         | 
| 3140 | 
            +
                  return typeof obj === 'function';
         | 
| 3141 | 
            +
                };
         | 
| 3142 | 
            +
              }
         | 
| 3143 | 
            +
             | 
| 3144 | 
            +
              // Is a given object a finite number?
         | 
| 3145 | 
            +
              _.isFinite = function(obj) {
         | 
| 3146 | 
            +
                return isFinite(obj) && !isNaN(parseFloat(obj));
         | 
| 3147 | 
            +
              };
         | 
| 3148 | 
            +
             | 
| 3149 | 
            +
              // Is the given value `NaN`? (NaN is the only number which does not equal itself).
         | 
| 3150 | 
            +
              _.isNaN = function(obj) {
         | 
| 3151 | 
            +
                return _.isNumber(obj) && obj != +obj;
         | 
| 3152 | 
            +
              };
         | 
| 3153 | 
            +
             | 
| 3154 | 
            +
              // Is a given value a boolean?
         | 
| 3155 | 
            +
              _.isBoolean = function(obj) {
         | 
| 3156 | 
            +
                return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
         | 
| 3157 | 
            +
              };
         | 
| 3158 | 
            +
             | 
| 3159 | 
            +
              // Is a given value equal to null?
         | 
| 3160 | 
            +
              _.isNull = function(obj) {
         | 
| 3161 | 
            +
                return obj === null;
         | 
| 3162 | 
            +
              };
         | 
| 3163 | 
            +
             | 
| 3164 | 
            +
              // Is a given variable undefined?
         | 
| 3165 | 
            +
              _.isUndefined = function(obj) {
         | 
| 3166 | 
            +
                return obj === void 0;
         | 
| 3167 | 
            +
              };
         | 
| 3168 | 
            +
             | 
| 3169 | 
            +
              // Shortcut function for checking if an object has a given property directly
         | 
| 3170 | 
            +
              // on itself (in other words, not on a prototype).
         | 
| 3171 | 
            +
              _.has = function(obj, key) {
         | 
| 3172 | 
            +
                return hasOwnProperty.call(obj, key);
         | 
| 3173 | 
            +
              };
         | 
| 3174 | 
            +
             | 
| 3175 | 
            +
              // Utility Functions
         | 
| 3176 | 
            +
              // -----------------
         | 
| 3177 | 
            +
             | 
| 3178 | 
            +
              // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
         | 
| 3179 | 
            +
              // previous owner. Returns a reference to the Underscore object.
         | 
| 3180 | 
            +
              _.noConflict = function() {
         | 
| 3181 | 
            +
                root._ = previousUnderscore;
         | 
| 3182 | 
            +
                return this;
         | 
| 3183 | 
            +
              };
         | 
| 3184 | 
            +
             | 
| 3185 | 
            +
              // Keep the identity function around for default iterators.
         | 
| 3186 | 
            +
              _.identity = function(value) {
         | 
| 3187 | 
            +
                return value;
         | 
| 3188 | 
            +
              };
         | 
| 3189 | 
            +
             | 
| 3190 | 
            +
              // Run a function **n** times.
         | 
| 3191 | 
            +
              _.times = function(n, iterator, context) {
         | 
| 3192 | 
            +
                var accum = Array(Math.max(0, n));
         | 
| 3193 | 
            +
                for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
         | 
| 3194 | 
            +
                return accum;
         | 
| 3195 | 
            +
              };
         | 
| 3196 | 
            +
             | 
| 3197 | 
            +
              // Return a random integer between min and max (inclusive).
         | 
| 3198 | 
            +
              _.random = function(min, max) {
         | 
| 3199 | 
            +
                if (max == null) {
         | 
| 3200 | 
            +
                  max = min;
         | 
| 3201 | 
            +
                  min = 0;
         | 
| 3202 | 
            +
                }
         | 
| 3203 | 
            +
                return min + Math.floor(Math.random() * (max - min + 1));
         | 
| 3204 | 
            +
              };
         | 
| 3205 | 
            +
             | 
| 3206 | 
            +
              // List of HTML entities for escaping.
         | 
| 3207 | 
            +
              var entityMap = {
         | 
| 3208 | 
            +
                escape: {
         | 
| 3209 | 
            +
                  '&': '&',
         | 
| 3210 | 
            +
                  '<': '<',
         | 
| 3211 | 
            +
                  '>': '>',
         | 
| 3212 | 
            +
                  '"': '"',
         | 
| 3213 | 
            +
                  "'": '''
         | 
| 3214 | 
            +
                }
         | 
| 3215 | 
            +
              };
         | 
| 3216 | 
            +
              entityMap.unescape = _.invert(entityMap.escape);
         | 
| 3217 | 
            +
             | 
| 3218 | 
            +
              // Regexes containing the keys and values listed immediately above.
         | 
| 3219 | 
            +
              var entityRegexes = {
         | 
| 3220 | 
            +
                escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
         | 
| 3221 | 
            +
                unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
         | 
| 3222 | 
            +
              };
         | 
| 3223 | 
            +
             | 
| 3224 | 
            +
              // Functions for escaping and unescaping strings to/from HTML interpolation.
         | 
| 3225 | 
            +
              _.each(['escape', 'unescape'], function(method) {
         | 
| 3226 | 
            +
                _[method] = function(string) {
         | 
| 3227 | 
            +
                  if (string == null) return '';
         | 
| 3228 | 
            +
                  return ('' + string).replace(entityRegexes[method], function(match) {
         | 
| 3229 | 
            +
                    return entityMap[method][match];
         | 
| 3230 | 
            +
                  });
         | 
| 3231 | 
            +
                };
         | 
| 3232 | 
            +
              });
         | 
| 3233 | 
            +
             | 
| 3234 | 
            +
              // If the value of the named `property` is a function then invoke it with the
         | 
| 3235 | 
            +
              // `object` as context; otherwise, return it.
         | 
| 3236 | 
            +
              _.result = function(object, property) {
         | 
| 3237 | 
            +
                if (object == null) return void 0;
         | 
| 3238 | 
            +
                var value = object[property];
         | 
| 3239 | 
            +
                return _.isFunction(value) ? value.call(object) : value;
         | 
| 3240 | 
            +
              };
         | 
| 3241 | 
            +
             | 
| 3242 | 
            +
              // Add your own custom functions to the Underscore object.
         | 
| 3243 | 
            +
              _.mixin = function(obj) {
         | 
| 3244 | 
            +
                each(_.functions(obj), function(name) {
         | 
| 3245 | 
            +
                  var func = _[name] = obj[name];
         | 
| 3246 | 
            +
                  _.prototype[name] = function() {
         | 
| 3247 | 
            +
                    var args = [this._wrapped];
         | 
| 3248 | 
            +
                    push.apply(args, arguments);
         | 
| 3249 | 
            +
                    return result.call(this, func.apply(_, args));
         | 
| 3250 | 
            +
                  };
         | 
| 3251 | 
            +
                });
         | 
| 3252 | 
            +
              };
         | 
| 3253 | 
            +
             | 
| 3254 | 
            +
              // Generate a unique integer id (unique within the entire client session).
         | 
| 3255 | 
            +
              // Useful for temporary DOM ids.
         | 
| 3256 | 
            +
              var idCounter = 0;
         | 
| 3257 | 
            +
              _.uniqueId = function(prefix) {
         | 
| 3258 | 
            +
                var id = ++idCounter + '';
         | 
| 3259 | 
            +
                return prefix ? prefix + id : id;
         | 
| 3260 | 
            +
              };
         | 
| 3261 | 
            +
             | 
| 3262 | 
            +
              // By default, Underscore uses ERB-style template delimiters, change the
         | 
| 3263 | 
            +
              // following template settings to use alternative delimiters.
         | 
| 3264 | 
            +
              _.templateSettings = {
         | 
| 3265 | 
            +
                evaluate    : /<%([\s\S]+?)%>/g,
         | 
| 3266 | 
            +
                interpolate : /<%=([\s\S]+?)%>/g,
         | 
| 3267 | 
            +
                escape      : /<%-([\s\S]+?)%>/g
         | 
| 3268 | 
            +
              };
         | 
| 3269 | 
            +
             | 
| 3270 | 
            +
              // When customizing `templateSettings`, if you don't want to define an
         | 
| 3271 | 
            +
              // interpolation, evaluation or escaping regex, we need one that is
         | 
| 3272 | 
            +
              // guaranteed not to match.
         | 
| 3273 | 
            +
              var noMatch = /(.)^/;
         | 
| 3274 | 
            +
             | 
| 3275 | 
            +
              // Certain characters need to be escaped so that they can be put into a
         | 
| 3276 | 
            +
              // string literal.
         | 
| 3277 | 
            +
              var escapes = {
         | 
| 3278 | 
            +
                "'":      "'",
         | 
| 3279 | 
            +
                '\\':     '\\',
         | 
| 3280 | 
            +
                '\r':     'r',
         | 
| 3281 | 
            +
                '\n':     'n',
         | 
| 3282 | 
            +
                '\t':     't',
         | 
| 3283 | 
            +
                '\u2028': 'u2028',
         | 
| 3284 | 
            +
                '\u2029': 'u2029'
         | 
| 3285 | 
            +
              };
         | 
| 3286 | 
            +
             | 
| 3287 | 
            +
              var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
         | 
| 3288 | 
            +
             | 
| 3289 | 
            +
              // JavaScript micro-templating, similar to John Resig's implementation.
         | 
| 3290 | 
            +
              // Underscore templating handles arbitrary delimiters, preserves whitespace,
         | 
| 3291 | 
            +
              // and correctly escapes quotes within interpolated code.
         | 
| 3292 | 
            +
              _.template = function(text, data, settings) {
         | 
| 3293 | 
            +
                var render;
         | 
| 3294 | 
            +
                settings = _.defaults({}, settings, _.templateSettings);
         | 
| 3295 | 
            +
             | 
| 3296 | 
            +
                // Combine delimiters into one regular expression via alternation.
         | 
| 3297 | 
            +
                var matcher = new RegExp([
         | 
| 3298 | 
            +
                  (settings.escape || noMatch).source,
         | 
| 3299 | 
            +
                  (settings.interpolate || noMatch).source,
         | 
| 3300 | 
            +
                  (settings.evaluate || noMatch).source
         | 
| 3301 | 
            +
                ].join('|') + '|$', 'g');
         | 
| 3302 | 
            +
             | 
| 3303 | 
            +
                // Compile the template source, escaping string literals appropriately.
         | 
| 3304 | 
            +
                var index = 0;
         | 
| 3305 | 
            +
                var source = "__p+='";
         | 
| 3306 | 
            +
                text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
         | 
| 3307 | 
            +
                  source += text.slice(index, offset)
         | 
| 3308 | 
            +
                    .replace(escaper, function(match) { return '\\' + escapes[match]; });
         | 
| 3309 | 
            +
             | 
| 3310 | 
            +
                  if (escape) {
         | 
| 3311 | 
            +
                    source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
         | 
| 3312 | 
            +
                  }
         | 
| 3313 | 
            +
                  if (interpolate) {
         | 
| 3314 | 
            +
                    source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
         | 
| 3315 | 
            +
                  }
         | 
| 3316 | 
            +
                  if (evaluate) {
         | 
| 3317 | 
            +
                    source += "';\n" + evaluate + "\n__p+='";
         | 
| 3318 | 
            +
                  }
         | 
| 3319 | 
            +
                  index = offset + match.length;
         | 
| 3320 | 
            +
                  return match;
         | 
| 3321 | 
            +
                });
         | 
| 3322 | 
            +
                source += "';\n";
         | 
| 3323 | 
            +
             | 
| 3324 | 
            +
                // If a variable is not specified, place data values in local scope.
         | 
| 3325 | 
            +
                if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
         | 
| 3326 | 
            +
             | 
| 3327 | 
            +
                source = "var __t,__p='',__j=Array.prototype.join," +
         | 
| 3328 | 
            +
                  "print=function(){__p+=__j.call(arguments,'');};\n" +
         | 
| 3329 | 
            +
                  source + "return __p;\n";
         | 
| 3330 | 
            +
             | 
| 3331 | 
            +
                try {
         | 
| 3332 | 
            +
                  render = new Function(settings.variable || 'obj', '_', source);
         | 
| 3333 | 
            +
                } catch (e) {
         | 
| 3334 | 
            +
                  e.source = source;
         | 
| 3335 | 
            +
                  throw e;
         | 
| 3336 | 
            +
                }
         | 
| 3337 | 
            +
             | 
| 3338 | 
            +
                if (data) return render(data, _);
         | 
| 3339 | 
            +
                var template = function(data) {
         | 
| 3340 | 
            +
                  return render.call(this, data, _);
         | 
| 3341 | 
            +
                };
         | 
| 3342 | 
            +
             | 
| 3343 | 
            +
                // Provide the compiled function source as a convenience for precompilation.
         | 
| 3344 | 
            +
                template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
         | 
| 3345 | 
            +
             | 
| 3346 | 
            +
                return template;
         | 
| 3347 | 
            +
              };
         | 
| 3348 | 
            +
             | 
| 3349 | 
            +
              // Add a "chain" function, which will delegate to the wrapper.
         | 
| 3350 | 
            +
              _.chain = function(obj) {
         | 
| 3351 | 
            +
                return _(obj).chain();
         | 
| 3352 | 
            +
              };
         | 
| 3353 | 
            +
             | 
| 3354 | 
            +
              // OOP
         | 
| 3355 | 
            +
              // ---------------
         | 
| 3356 | 
            +
              // If Underscore is called as a function, it returns a wrapped object that
         | 
| 3357 | 
            +
              // can be used OO-style. This wrapper holds altered versions of all the
         | 
| 3358 | 
            +
              // underscore functions. Wrapped objects may be chained.
         | 
| 3359 | 
            +
             | 
| 3360 | 
            +
              // Helper function to continue chaining intermediate results.
         | 
| 3361 | 
            +
              var result = function(obj) {
         | 
| 3362 | 
            +
                return this._chain ? _(obj).chain() : obj;
         | 
| 3363 | 
            +
              };
         | 
| 3364 | 
            +
             | 
| 3365 | 
            +
              // Add all of the Underscore functions to the wrapper object.
         | 
| 3366 | 
            +
              _.mixin(_);
         | 
| 3367 | 
            +
             | 
| 3368 | 
            +
              // Add all mutator Array functions to the wrapper.
         | 
| 3369 | 
            +
              each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
         | 
| 3370 | 
            +
                var method = ArrayProto[name];
         | 
| 3371 | 
            +
                _.prototype[name] = function() {
         | 
| 3372 | 
            +
                  var obj = this._wrapped;
         | 
| 3373 | 
            +
                  method.apply(obj, arguments);
         | 
| 3374 | 
            +
                  if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
         | 
| 3375 | 
            +
                  return result.call(this, obj);
         | 
| 3376 | 
            +
                };
         | 
| 3377 | 
            +
              });
         | 
| 3378 | 
            +
             | 
| 3379 | 
            +
              // Add all accessor Array functions to the wrapper.
         | 
| 3380 | 
            +
              each(['concat', 'join', 'slice'], function(name) {
         | 
| 3381 | 
            +
                var method = ArrayProto[name];
         | 
| 3382 | 
            +
                _.prototype[name] = function() {
         | 
| 3383 | 
            +
                  return result.call(this, method.apply(this._wrapped, arguments));
         | 
| 3384 | 
            +
                };
         | 
| 3385 | 
            +
              });
         | 
| 3386 | 
            +
             | 
| 3387 | 
            +
              _.extend(_.prototype, {
         | 
| 3388 | 
            +
             | 
| 3389 | 
            +
                // Start chaining a wrapped Underscore object.
         | 
| 3390 | 
            +
                chain: function() {
         | 
| 3391 | 
            +
                  this._chain = true;
         | 
| 3392 | 
            +
                  return this;
         | 
| 3393 | 
            +
                },
         | 
| 3394 | 
            +
             | 
| 3395 | 
            +
                // Extracts the result from a wrapped and chained object.
         | 
| 3396 | 
            +
                value: function() {
         | 
| 3397 | 
            +
                  return this._wrapped;
         | 
| 3398 | 
            +
                }
         | 
| 3399 | 
            +
             | 
| 3400 | 
            +
              });
         | 
| 3401 | 
            +
             | 
| 3402 | 
            +
            }).call(this);
         | 
| 3403 | 
            +
             | 
| 3404 | 
            +
            })()
         | 
| 3405 | 
            +
            },{}],19:[function(require,module,exports){
         | 
| 3406 | 
            +
            (function() {
         | 
| 3407 | 
            +
              var active, createSearch, emptyPage, util, wiki;
         | 
| 3408 | 
            +
             | 
| 3409 | 
            +
              wiki = require('./wiki');
         | 
| 3410 | 
            +
             | 
| 3411 | 
            +
              util = require('./util');
         | 
| 3412 | 
            +
             | 
| 3413 | 
            +
              active = require('./active');
         | 
| 3414 | 
            +
             | 
| 3415 | 
            +
              emptyPage = require('./page').emptyPage;
         | 
| 3416 | 
            +
             | 
| 3417 | 
            +
              createSearch = function(_arg) {
         | 
| 3418 | 
            +
                var neighborhood, performSearch;
         | 
| 3419 | 
            +
                neighborhood = _arg.neighborhood;
         | 
| 3420 | 
            +
                performSearch = function(searchQuery) {
         | 
| 3421 | 
            +
                  var $resultPage, result, resultPage, searchResults, tally, _i, _len, _ref;
         | 
| 3422 | 
            +
                  searchResults = neighborhood.search(searchQuery);
         | 
| 3423 | 
            +
                  tally = searchResults.tally;
         | 
| 3424 | 
            +
                  resultPage = emptyPage();
         | 
| 3425 | 
            +
                  resultPage.setTitle("Search for '" + searchQuery + "'");
         | 
| 3426 | 
            +
                  resultPage.addParagraph("String '" + searchQuery + "' found on " + (tally.finds || 'none') + " of " + (tally.pages || 'no') + " pages from " + (tally.sites || 'no') + " sites.\nText matched on " + (tally.title || 'no') + " titles, " + (tally.text || 'no') + " paragraphs, and " + (tally.slug || 'no') + " slugs.\nElapsed time " + tally.msec + " milliseconds.");
         | 
| 3427 | 
            +
                  _ref = searchResults.finds;
         | 
| 3428 | 
            +
                  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         | 
| 3429 | 
            +
                    result = _ref[_i];
         | 
| 3430 | 
            +
                    resultPage.addItem({
         | 
| 3431 | 
            +
                      "type": "reference",
         | 
| 3432 | 
            +
                      "site": result.site,
         | 
| 3433 | 
            +
                      "slug": result.page.slug,
         | 
| 3434 | 
            +
                      "title": result.page.title,
         | 
| 3435 | 
            +
                      "text": result.page.synopsis || ''
         | 
| 3436 | 
            +
                    });
         | 
| 3437 | 
            +
                  }
         | 
| 3438 | 
            +
                  $resultPage = wiki.createPage(resultPage.getSlug()).addClass('ghost');
         | 
| 3439 | 
            +
                  $resultPage.appendTo($('.main'));
         | 
| 3440 | 
            +
                  wiki.buildPage(resultPage, $resultPage);
         | 
| 3441 | 
            +
                  return active.set($('.page').last());
         | 
| 3442 | 
            +
                };
         | 
| 3443 | 
            +
                return {
         | 
| 3444 | 
            +
                  performSearch: performSearch
         | 
| 3445 | 
            +
                };
         | 
| 3446 | 
            +
              };
         | 
| 3447 | 
            +
             | 
| 3448 | 
            +
              module.exports = createSearch;
         | 
| 3449 | 
            +
             | 
| 3450 | 
            +
            }).call(this);
         | 
| 3451 | 
            +
             | 
| 3452 | 
            +
            },{"./active":10,"./page":12,"./util":6,"./wiki":2}],18:[function(require,module,exports){
         | 
| 3453 | 
            +
            (function() {
         | 
| 3454 | 
            +
              var active, createSearch, neighborhood, nextAvailableFetch, nextFetchInterval, populateSiteInfoFor, util, wiki, _,
         | 
| 3455 | 
            +
                __hasProp = {}.hasOwnProperty;
         | 
| 3456 | 
            +
             | 
| 3457 | 
            +
              _ = require('underscore');
         | 
| 3458 | 
            +
             | 
| 3459 | 
            +
              wiki = require('./wiki');
         | 
| 3460 | 
            +
             | 
| 3461 | 
            +
              active = require('./active');
         | 
| 3462 | 
            +
             | 
| 3463 | 
            +
              util = require('./util');
         | 
| 3464 | 
            +
             | 
| 3465 | 
            +
              createSearch = require('./search');
         | 
| 3466 | 
            +
             | 
| 3467 | 
            +
              module.exports = neighborhood = {};
         | 
| 3468 | 
            +
             | 
| 3469 | 
            +
              if (wiki.neighborhood == null) {
         | 
| 3470 | 
            +
                wiki.neighborhood = {};
         | 
| 3471 | 
            +
              }
         | 
| 3472 | 
            +
             | 
| 3473 | 
            +
              nextAvailableFetch = 0;
         | 
| 3474 | 
            +
             | 
| 3475 | 
            +
              nextFetchInterval = 2000;
         | 
| 3476 | 
            +
             | 
| 3477 | 
            +
              populateSiteInfoFor = function(site, neighborInfo) {
         | 
| 3478 | 
            +
                var fetchMap, now, transition;
         | 
| 3479 | 
            +
                if (neighborInfo.sitemapRequestInflight) {
         | 
| 3480 | 
            +
                  return;
         | 
| 3481 | 
            +
                }
         | 
| 3482 | 
            +
                neighborInfo.sitemapRequestInflight = true;
         | 
| 3483 | 
            +
                transition = function(site, from, to) {
         | 
| 3484 | 
            +
                  return $(".neighbor[data-site=\"" + site + "\"]").find('div').removeClass(from).addClass(to);
         | 
| 3485 | 
            +
                };
         | 
| 3486 | 
            +
                fetchMap = function() {
         | 
| 3487 | 
            +
                  var request, sitemapUrl;
         | 
| 3488 | 
            +
                  sitemapUrl = "http://" + site + "/system/sitemap.json";
         | 
| 3489 | 
            +
                  transition(site, 'wait', 'fetch');
         | 
| 3490 | 
            +
                  request = $.ajax({
         | 
| 3491 | 
            +
                    type: 'GET',
         | 
| 3492 | 
            +
                    dataType: 'json',
         | 
| 3493 | 
            +
                    url: sitemapUrl
         | 
| 3494 | 
            +
                  });
         | 
| 3495 | 
            +
                  return request.always(function() {
         | 
| 3496 | 
            +
                    return neighborInfo.sitemapRequestInflight = false;
         | 
| 3497 | 
            +
                  }).done(function(data) {
         | 
| 3498 | 
            +
                    neighborInfo.sitemap = data;
         | 
| 3499 | 
            +
                    transition(site, 'fetch', 'done');
         | 
| 3500 | 
            +
                    return $('body').trigger('new-neighbor-done', site);
         | 
| 3501 | 
            +
                  }).fail(function(data) {
         | 
| 3502 | 
            +
                    return transition(site, 'fetch', 'fail');
         | 
| 3503 | 
            +
                  });
         | 
| 3504 | 
            +
                };
         | 
| 3505 | 
            +
                now = Date.now();
         | 
| 3506 | 
            +
                if (now > nextAvailableFetch) {
         | 
| 3507 | 
            +
                  nextAvailableFetch = now + nextFetchInterval;
         | 
| 3508 | 
            +
                  return setTimeout(fetchMap, 100);
         | 
| 3509 | 
            +
                } else {
         | 
| 3510 | 
            +
                  setTimeout(fetchMap, nextAvailableFetch - now);
         | 
| 3511 | 
            +
                  return nextAvailableFetch += nextFetchInterval;
         | 
| 3512 | 
            +
                }
         | 
| 3513 | 
            +
              };
         | 
| 3514 | 
            +
             | 
| 3515 | 
            +
              wiki.registerNeighbor = neighborhood.registerNeighbor = function(site) {
         | 
| 3516 | 
            +
                var neighborInfo;
         | 
| 3517 | 
            +
                if (wiki.neighborhood[site] != null) {
         | 
| 3518 | 
            +
                  return;
         | 
| 3519 | 
            +
                }
         | 
| 3520 | 
            +
                neighborInfo = {};
         | 
| 3521 | 
            +
                wiki.neighborhood[site] = neighborInfo;
         | 
| 3522 | 
            +
                populateSiteInfoFor(site, neighborInfo);
         | 
| 3523 | 
            +
                return $('body').trigger('new-neighbor', site);
         | 
| 3524 | 
            +
              };
         | 
| 3525 | 
            +
             | 
| 3526 | 
            +
              neighborhood.listNeighbors = function() {
         | 
| 3527 | 
            +
                return _.keys(wiki.neighborhood);
         | 
| 3528 | 
            +
              };
         | 
| 3529 | 
            +
             | 
| 3530 | 
            +
              neighborhood.search = function(searchQuery) {
         | 
| 3531 | 
            +
                var finds, match, matchingPages, neighborInfo, neighborSite, sitemap, start, tally, tick, _ref;
         | 
| 3532 | 
            +
                finds = [];
         | 
| 3533 | 
            +
                tally = {};
         | 
| 3534 | 
            +
                tick = function(key) {
         | 
| 3535 | 
            +
                  if (tally[key] != null) {
         | 
| 3536 | 
            +
                    return tally[key]++;
         | 
| 3537 | 
            +
                  } else {
         | 
| 3538 | 
            +
                    return tally[key] = 1;
         | 
| 3539 | 
            +
                  }
         | 
| 3540 | 
            +
                };
         | 
| 3541 | 
            +
                match = function(key, text) {
         | 
| 3542 | 
            +
                  var hit;
         | 
| 3543 | 
            +
                  hit = (text != null) && text.toLowerCase().indexOf(searchQuery.toLowerCase()) >= 0;
         | 
| 3544 | 
            +
                  if (hit) {
         | 
| 3545 | 
            +
                    tick(key);
         | 
| 3546 | 
            +
                  }
         | 
| 3547 | 
            +
                  return hit;
         | 
| 3548 | 
            +
                };
         | 
| 3549 | 
            +
                start = Date.now();
         | 
| 3550 | 
            +
                _ref = wiki.neighborhood;
         | 
| 3551 | 
            +
                for (neighborSite in _ref) {
         | 
| 3552 | 
            +
                  if (!__hasProp.call(_ref, neighborSite)) continue;
         | 
| 3553 | 
            +
                  neighborInfo = _ref[neighborSite];
         | 
| 3554 | 
            +
                  sitemap = neighborInfo.sitemap;
         | 
| 3555 | 
            +
                  if (sitemap != null) {
         | 
| 3556 | 
            +
                    tick('sites');
         | 
| 3557 | 
            +
                  }
         | 
| 3558 | 
            +
                  matchingPages = _.each(sitemap, function(page) {
         | 
| 3559 | 
            +
                    tick('pages');
         | 
| 3560 | 
            +
                    if (!(match('title', page.title) || match('text', page.synopsis) || match('slug', page.slug))) {
         | 
| 3561 | 
            +
                      return;
         | 
| 3562 | 
            +
                    }
         | 
| 3563 | 
            +
                    tick('finds');
         | 
| 3564 | 
            +
                    return finds.push({
         | 
| 3565 | 
            +
                      page: page,
         | 
| 3566 | 
            +
                      site: neighborSite,
         | 
| 3567 | 
            +
                      rank: 1
         | 
| 3568 | 
            +
                    });
         | 
| 3569 | 
            +
                  });
         | 
| 3570 | 
            +
                }
         | 
| 3571 | 
            +
                tally['msec'] = Date.now() - start;
         | 
| 3572 | 
            +
                return {
         | 
| 3573 | 
            +
                  finds: finds,
         | 
| 3574 | 
            +
                  tally: tally
         | 
| 3575 | 
            +
                };
         | 
| 3576 | 
            +
              };
         | 
| 3577 | 
            +
             | 
| 3578 | 
            +
              $(function() {
         | 
| 3579 | 
            +
                var $neighborhood, flag, search;
         | 
| 3580 | 
            +
                $neighborhood = $('.neighborhood');
         | 
| 3581 | 
            +
                flag = function(site) {
         | 
| 3582 | 
            +
                  return "<span class=\"neighbor\" data-site=\"" + site + "\">\n  <div class=\"wait\">\n    <img src=\"http://" + site + "/favicon.png\" title=\"" + site + "\">\n  </div>\n</span>";
         | 
| 3583 | 
            +
                };
         | 
| 3584 | 
            +
                $('body').on('new-neighbor', function(e, site) {
         | 
| 3585 | 
            +
                  return $neighborhood.append(flag(site));
         | 
| 3586 | 
            +
                }).delegate('.neighbor img', 'click', function(e) {
         | 
| 3587 | 
            +
                  return wiki.doInternalLink('welcome-visitors', null, this.title);
         | 
| 3588 | 
            +
                });
         | 
| 3589 | 
            +
                search = createSearch({
         | 
| 3590 | 
            +
                  neighborhood: neighborhood
         | 
| 3591 | 
            +
                });
         | 
| 3592 | 
            +
                return $('input.search').on('keypress', function(e) {
         | 
| 3593 | 
            +
                  var searchQuery;
         | 
| 3594 | 
            +
                  if (e.keyCode !== 13) {
         | 
| 3595 | 
            +
                    return;
         | 
| 3596 | 
            +
                  }
         | 
| 3597 | 
            +
                  searchQuery = $(this).val();
         | 
| 3598 | 
            +
                  search.performSearch(searchQuery);
         | 
| 3599 | 
            +
                  return $(this).val("");
         | 
| 3600 | 
            +
                });
         | 
| 3601 | 
            +
              });
         | 
| 3602 | 
            +
             | 
| 3603 | 
            +
            }).call(this);
         | 
| 3604 | 
            +
             | 
| 3605 | 
            +
            },{"./active":10,"./search":19,"./util":6,"./wiki":2,"underscore":17}]},{},[1])
         | 
| 3606 | 
            +
            //@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvY2xpZW50LmNvZmZlZSIsIi9Vc2Vycy93Y3VubmluZ2hhbS9GZWRXaWtpL1NtYWxsZXN0LUZlZGVyYXRlZC1XaWtpL2NsaWVudC9ub2RlX21vZHVsZXMvd2lraS1jbGllbnQvbGliL3dpa2kuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9sZWdhY3kuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9zeW5vcHNpcy5qcyIsIi9Vc2Vycy93Y3VubmluZ2hhbS9GZWRXaWtpL1NtYWxsZXN0LUZlZGVyYXRlZC1XaWtpL2NsaWVudC9ub2RlX21vZHVsZXMvd2lraS1jbGllbnQvbGliL3BlcnNvbmEuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9hY3RpdmUuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi91dGlsLmpzIiwiL1VzZXJzL3djdW5uaW5naGFtL0ZlZFdpa2kvU21hbGxlc3QtRmVkZXJhdGVkLVdpa2kvY2xpZW50L25vZGVfbW9kdWxlcy93aWtpLWNsaWVudC9saWIvcGx1Z2luLmpzIiwiL1VzZXJzL3djdW5uaW5naGFtL0ZlZFdpa2kvU21hbGxlc3QtRmVkZXJhdGVkLVdpa2kvY2xpZW50L25vZGVfbW9kdWxlcy93aWtpLWNsaWVudC9saWIvc3RhdGUuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9yZXZpc2lvbi5qcyIsIi9Vc2Vycy93Y3VubmluZ2hhbS9GZWRXaWtpL1NtYWxsZXN0LUZlZGVyYXRlZC1XaWtpL2NsaWVudC9ub2RlX21vZHVsZXMvd2lraS1jbGllbnQvbGliL3JlZmVyZW5jZS5qcyIsIi9Vc2Vycy93Y3VubmluZ2hhbS9GZWRXaWtpL1NtYWxsZXN0LUZlZGVyYXRlZC1XaWtpL2NsaWVudC9ub2RlX21vZHVsZXMvd2lraS1jbGllbnQvbGliL2ZhY3RvcnkuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9hZGRUb0pvdXJuYWwuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9wYWdlSGFuZGxlci5qcyIsIi9Vc2Vycy93Y3VubmluZ2hhbS9GZWRXaWtpL1NtYWxsZXN0LUZlZGVyYXRlZC1XaWtpL2NsaWVudC9ub2RlX21vZHVsZXMvd2lraS1jbGllbnQvbGliL3JlZnJlc2guanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9wYWdlLmpzIiwiL1VzZXJzL3djdW5uaW5naGFtL0ZlZFdpa2kvU21hbGxlc3QtRmVkZXJhdGVkLVdpa2kvY2xpZW50L25vZGVfbW9kdWxlcy91bmRlcnNjb3JlL3VuZGVyc2NvcmUuanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9zZWFyY2guanMiLCIvVXNlcnMvd2N1bm5pbmdoYW0vRmVkV2lraS9TbWFsbGVzdC1GZWRlcmF0ZWQtV2lraS9jbGllbnQvbm9kZV9tb2R1bGVzL3dpa2ktY2xpZW50L2xpYi9uZWlnaGJvcmhvb2QuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLENBQU8sRUFBTyxDQUFkLEVBQU0sQ0FBUSxlQUFBOztBQUNkLENBREEsTUFDQSxpQkFBQTs7OztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDek9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzd2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzQ29udGVudCI6WyJ3aW5kb3cud2lraSA9IHJlcXVpcmUoJ3dpa2ktY2xpZW50L2xpYi93aWtpJylcbnJlcXVpcmUoJ3dpa2ktY2xpZW50L2xpYi9sZWdhY3knKVxuXG4iLCIoZnVuY3Rpb24oKSB7XG4gIHZhciBjcmVhdGVTeW5vcHNpcywgd2lraSxcbiAgICBfX3NsaWNlID0gW10uc2xpY2U7XG5cbiAgY3JlYXRlU3lub3BzaXMgPSByZXF1aXJlKCcuL3N5bm9wc2lzJyk7XG5cbiAgd2lraSA9IHtcbiAgICBjcmVhdGVTeW5vcHNpczogY3JlYXRlU3lub3BzaXNcbiAgfTtcblxuICB3aWtpLnBlcnNvbmEgPSByZXF1aXJlKCcuL3BlcnNvbmEnKTtcblxuICB3aWtpLmxvZyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciB0aGluZ3M7XG4gICAgdGhpbmdzID0gMSA8PSBhcmd1bWVudHMubGVuZ3RoID8gX19zbGljZS5jYWxsKGFyZ3VtZW50cywgMCkgOiBbXTtcbiAgICBpZiAoKHR5cGVvZiBjb25zb2xlICE9PSBcInVuZGVmaW5lZFwiICYmIGNvbnNvbGUgIT09IG51bGwgPyBjb25zb2xlLmxvZyA6IHZvaWQgMCkgIT0gbnVsbCkge1xuICAgICAgcmV0dXJuIGNvbnNvbGUubG9nLmFwcGx5KGNvbnNvbGUsIHRoaW5ncyk7XG4gICAgfVxuICB9O1xuXG4gIHdpa2kuYXNTbHVnID0gZnVuY3Rpb24obmFtZSkge1xuICAgIHJldHVybiBuYW1lLnJlcGxhY2UoL1xccy9nLCAnLScpLnJlcGxhY2UoL1teQS1aYS16MC05LV0vZywgJycpLnRvTG93ZXJDYXNlKCk7XG4gIH07XG5cbiAgd2lraS51c2VMb2NhbFN0b3JhZ2UgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gJChcIi5sb2dpblwiKS5sZW5ndGggPiAwO1xuICB9O1xuXG4gIHdpa2kucmVzb2x1dGlvbkNvbnRleHQgPSBbXTtcblxuICB3aWtpLnJlc29sdmVGcm9tID0gZnVuY3Rpb24oYWRkaXRpb24sIGNhbGxiYWNrKSB7XG4gICAgd2lraS5yZXNvbHV0aW9uQ29udGV4dC5wdXNoKGFkZGl0aW9uKTtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGNhbGxiYWNrKCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHdpa2kucmVzb2x1dGlvbkNvbnRleHQucG9wKCk7XG4gICAgfVxuICB9O1xuXG4gIHdpa2kuZ2V0RGF0YSA9IGZ1bmN0aW9uKHZpcykge1xuICAgIHZhciBpZHgsIHdobztcbiAgICBpZiAodmlzKSB7XG4gICAgICBpZHggPSAkKCcuaXRlbScpLmluZGV4KHZpcyk7XG4gICAgICB3aG8gPSAkKFwiLml0ZW06bHQoXCIgKyBpZHggKyBcIilcIikuZmlsdGVyKCcuY2hhcnQsLmRhdGEsLmNhbGN1bGF0b3InKS5sYXN0KCk7XG4gICAgICBpZiAod2hvICE9IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHdoby5kYXRhKCdpdGVtJykuZGF0YTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB7fTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgd2hvID0gJCgnLmNoYXJ0LC5kYXRhLC5jYWxjdWxhdG9yJykubGFzdCgpO1xuICAgICAgaWYgKHdobyAhPSBudWxsKSB7XG4gICAgICAgIHJldHVybiB3aG8uZGF0YSgnaXRlbScpLmRhdGE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4ge307XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIHdpa2kuZ2V0RGF0YU5vZGVzID0gZnVuY3Rpb24odmlzKSB7XG4gICAgdmFyIGlkeCwgd2hvO1xuICAgIGlmICh2aXMpIHtcbiAgICAgIGlkeCA9ICQoJy5pdGVtJykuaW5kZXgodmlzKTtcbiAgICAgIHdobyA9ICQoXCIuaXRlbTpsdChcIiArIGlkeCArIFwiKVwiKS5maWx0ZXIoJy5jaGFydCwuZGF0YSwuY2FsY3VsYXRvcicpLnRvQXJyYXkoKS5yZXZlcnNlKCk7XG4gICAgICByZXR1cm4gJCh3aG8pO1xuICAgIH0gZWxzZSB7XG4gICAgICB3aG8gPSAkKCcuY2hhcnQsLmRhdGEsLmNhbGN1bGF0b3InKS50b0FycmF5KCkucmV2ZXJzZSgpO1xuICAgICAgcmV0dXJuICQod2hvKTtcbiAgICB9XG4gIH07XG5cbiAgd2lraS5jcmVhdGVQYWdlID0gZnVuY3Rpb24obmFtZSwgbG9jKSB7XG4gICAgdmFyICRwYWdlLCBzaXRlO1xuICAgIGlmIChsb2MgJiYgbG9jICE9PSAndmlldycpIHtcbiAgICAgIHNpdGUgPSBsb2M7XG4gICAgfVxuICAgICRwYWdlID0gJChcIjxkaXYgY2xhc3M9XFxcInBhZ2VcXFwiIGlkPVxcXCJcIiArIG5hbWUgKyBcIlxcXCI+XFxuICA8ZGl2IGNsYXNzPVxcXCJ0d2luc1xcXCI+IDxwPiA8L3A+IDwvZGl2PlxcbiAgPGRpdiBjbGFzcz1cXFwiaGVhZGVyXFxcIj5cXG4gICAgPGgxPiA8aW1nIGNsYXNzPVxcXCJmYXZpY29uXFxcIiBzcmM9XFxcIlwiICsgKHNpdGUgPyBcIi8vXCIgKyBzaXRlIDogXCJcIikgKyBcIi9mYXZpY29uLnBuZ1xcXCIgaGVpZ2h0PVxcXCIzMnB4XFxcIj4gXCIgKyBuYW1lICsgXCIgPC9oMT5cXG4gIDwvZGl2PlxcbjwvZGl2PlwiKTtcbiAgICBpZiAoc2l0ZSkge1xuICAgICAgJHBhZ2UuZGF0YSgnc2l0ZScsIHNpdGUpO1xuICAgIH1cbiAgICByZXR1cm4gJHBhZ2U7XG4gIH07XG5cbiAgd2lraS5nZXRJdGVtID0gZnVuY3Rpb24oZWxlbWVudCkge1xuICAgIGlmICgkKGVsZW1lbnQpLmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiAkKGVsZW1lbnQpLmRhdGEoXCJpdGVtXCIpIHx8ICQoZWxlbWVudCkuZGF0YSgnc3RhdGljSXRlbScpO1xuICAgIH1cbiAgfTtcblxuICB3aWtpLnJlc29sdmVMaW5rcyA9IGZ1bmN0aW9uKHN0cmluZykge1xuICAgIHZhciByZW5kZXJJbnRlcm5hbExpbms7XG4gICAgcmVuZGVySW50ZXJuYWxMaW5rID0gZnVuY3Rpb24obWF0Y2gsIG5hbWUpIHtcbiAgICAgIHZhciBzbHVnO1xuICAgICAgc2x1ZyA9IHdpa2kuYXNTbHVnKG5hbWUpO1xuICAgICAgcmV0dXJuIFwiPGEgY2xhc3M9XFxcImludGVybmFsXFxcIiBocmVmPVxcXCIvXCIgKyBzbHVnICsgXCIuaHRtbFxcXCIgZGF0YS1wYWdlLW5hbWU9XFxcIlwiICsgc2x1ZyArIFwiXFxcIiB0aXRsZT1cXFwiXCIgKyAod2lraS5yZXNvbHV0aW9uQ29udGV4dC5qb2luKCcgPT4gJykpICsgXCJcXFwiPlwiICsgbmFtZSArIFwiPC9hPlwiO1xuICAgIH07XG4gICAgcmV0dXJuIHN0cmluZy5yZXBsYWNlKC9cXFtcXFsoW15cXF1dKylcXF1cXF0vZ2ksIHJlbmRlckludGVybmFsTGluaykucmVwbGFjZSgvXFxbKGh0dHAuKj8pICguKj8pXFxdL2dpLCBcIjxhIGNsYXNzPVxcXCJleHRlcm5hbFxcXCIgdGFyZ2V0PVxcXCJfYmxhbmtcXFwiIGhyZWY9XFxcIiQxXFxcIiB0aXRsZT1cXFwiJDFcXFwiIHJlbD1cXFwibm9mb2xsb3dcXFwiPiQyIDxpbWcgc3JjPVxcXCIvaW1hZ2VzL2V4dGVybmFsLWxpbmstbHRyLWljb24ucG5nXFxcIj48L2E+XCIpO1xuICB9O1xuXG4gIG1vZHVsZS5leHBvcnRzID0gd2lraTtcblxufSkuY2FsbCh0aGlzKTtcbiIsIihmdW5jdGlvbigpIHtcbiAgdmFyIGFjdGl2ZSwgbmV3UGFnZSwgcGFnZUhhbmRsZXIsIHBsdWdpbiwgcmVmcmVzaCwgc3RhdGUsIHV0aWwsIHdpa2k7XG5cbiAgd2lraSA9IHJlcXVpcmUoJy4vd2lraScpO1xuXG4gIHV0aWwgPSByZXF1aXJlKCcuL3V0aWwnKTtcblxuICBwYWdlSGFuZGxlciA9IHdpa2kucGFnZUhhbmRsZXIgPSByZXF1aXJlKCcuL3BhZ2VIYW5kbGVyJyk7XG5cbiAgcGx1Z2luID0gcmVxdWlyZSgnLi9wbHVnaW4nKTtcblxuICBzdGF0ZSA9IHJlcXVpcmUoJy4vc3RhdGUnKTtcblxuICBhY3RpdmUgPSByZXF1aXJlKCcuL2FjdGl2ZScpO1xuXG4gIHJlZnJlc2ggPSByZXF1aXJlKCcuL3JlZnJlc2gnKTtcblxuICBuZXdQYWdlID0gcmVxdWlyZSgnLi9wYWdlJykubmV3UGFnZTtcblxuICBBcnJheS5wcm90b3R5cGUubGFzdCA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzW3RoaXMubGVuZ3RoIC0gMV07XG4gIH07XG5cbiAgJChmdW5jdGlvbigpIHtcbiAgICB2YXIgTEVGVEFSUk9XLCBSSUdIVEFSUk9XLCBjcmVhdGVUZXh0RWxlbWVudCwgZG9JbnRlcm5hbExpbmssIGZpbmlzaENsaWNrLCBnZXRUZW1wbGF0ZSwgc2xlZXAsIHRleHRFZGl0b3I7XG4gICAgd2luZG93LmRpYWxvZyA9ICQoJzxkaXY+PC9kaXY+JykuaHRtbCgnVGhpcyBkaWFsb2cgd2lsbCBzaG93IGV2ZXJ5IHRpbWUhJykuZGlhbG9nKHtcbiAgICAgIGF1dG9PcGVuOiBmYWxzZSxcbiAgICAgIHRpdGxlOiAnQmFzaWMgRGlhbG9nJyxcbiAgICAgIGhlaWdodDogNjAwLFxuICAgICAgd2lkdGg6IDgwMFxuICAgIH0pO1xuICAgIHdpa2kuZGlhbG9nID0gZnVuY3Rpb24odGl0bGUsIGh0bWwpIHtcbiAgICAgIHdpbmRvdy5kaWFsb2cuaHRtbChodG1sKTtcbiAgICAgIHdpbmRvdy5kaWFsb2cuZGlhbG9nKFwib3B0aW9uXCIsIFwidGl0bGVcIiwgd2lraS5yZXNvbHZlTGlua3ModGl0bGUpKTtcbiAgICAgIHJldHVybiB3aW5kb3cuZGlhbG9nLmRpYWxvZygnb3BlbicpO1xuICAgIH07XG4gICAgc2xlZXAgPSBmdW5jdGlvbih0aW1lLCBkb25lKSB7XG4gICAgICByZXR1cm4gc2V0VGltZW91dChkb25lLCB0aW1lKTtcbiAgICB9O1xuICAgIHdpa2kucmVtb3ZlSXRlbSA9IGZ1bmN0aW9uKCRpdGVtLCBpdGVtKSB7XG4gICAgICBwYWdlSGFuZGxlci5wdXQoJGl0ZW0ucGFyZW50cygnLnBhZ2U6Zmlyc3QnKSwge1xuICAgICAgICB0eXBlOiAncmVtb3ZlJyxcbiAgICAgICAgaWQ6IGl0ZW0uaWRcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuICRpdGVtLnJlbW92ZSgpO1xuICAgIH07XG4gICAgd2lraS5jcmVhdGVJdGVtID0gZnVuY3Rpb24oJHBhZ2UsICRiZWZvcmUsIGl0ZW0pIHtcbiAgICAgIHZhciAkaXRlbSwgYmVmb3JlO1xuICAgICAgaWYgKCRwYWdlID09IG51bGwpIHtcbiAgICAgICAgJHBhZ2UgPSAkYmVmb3JlLnBhcmVudHMoJy5wYWdlJyk7XG4gICAgICB9XG4gICAgICBpdGVtLmlkID0gdXRpbC5yYW5kb21CeXRlcyg4KTtcbiAgICAgICRpdGVtID0gJChcIjxkaXYgY2xhc3M9XFxcIml0ZW0gXCIgKyBpdGVtLnR5cGUgKyBcIlxcXCIgZGF0YS1pZD1cXFwiXCIgKyBcIlxcXCI8L2Rpdj5cIik7XG4gICAgICAkaXRlbS5kYXRhKCdpdGVtJywgaXRlbSkuZGF0YSgncGFnZUVsZW1lbnQnLCAkcGFnZSk7XG4gICAgICBpZiAoJGJlZm9yZSAhPSBudWxsKSB7XG4gICAgICAgICRiZWZvcmUuYWZ0ZXIoJGl0ZW0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgJHBhZ2UuZmluZCgnLnN0b3J5JykuYXBwZW5kKCRpdGVtKTtcbiAgICAgIH1cbiAgICAgIHBsdWdpbltcImRvXCJdKCRpdGVtLCBpdGVtKTtcbiAgICAgIGJlZm9yZSA9IHdpa2kuZ2V0SXRlbSgkYmVmb3JlKTtcbiAgICAgIHNsZWVwKDUwMCwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBwYWdlSGFuZGxlci5wdXQoJHBhZ2UsIHtcbiAgICAgICAgICBpdGVtOiBpdGVtLFxuICAgICAgICAgIGlkOiBpdGVtLmlkLFxuICAgICAgICAgIHR5cGU6ICdhZGQnLFxuICAgICAgICAgIGFmdGVyOiBiZWZvcmUgIT0gbnVsbCA/IGJlZm9yZS5pZCA6IHZvaWQgMFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuICRpdGVtO1xuICAgIH07XG4gICAgY3JlYXRlVGV4dEVsZW1lbnQgPSBmdW5jdGlvbihwYWdlRWxlbWVudCwgYmVmb3JlRWxlbWVudCwgaW5pdGlhbFRleHQpIHtcbiAgICAgIHZhciBpdGVtLCBpdGVtQmVmb3JlLCBpdGVtRWxlbWVudDtcbiAgICAgIGl0ZW0gPSB7XG4gICAgICAgIHR5cGU6ICdwYXJhZ3JhcGgnLFxuICAgICAgICBpZDogdXRpbC5yYW5kb21CeXRlcyg4KSxcbiAgICAgICAgdGV4dDogaW5pdGlhbFRleHRcbiAgICAgIH07XG4gICAgICBpdGVtRWxlbWVudCA9ICQoXCI8ZGl2IGNsYXNzPVxcXCJpdGVtIHBhcmFncmFwaFxcXCIgZGF0YS1pZD1cIiArIGl0ZW0uaWQgKyBcIj48L2Rpdj5cIik7XG4gICAgICBpdGVtRWxlbWVudC5kYXRhKCdpdGVtJywgaXRlbSkuZGF0YSgncGFnZUVsZW1lbnQnLCBwYWdlRWxlbWVudCk7XG4gICAgICBiZWZvcmVFbGVtZW50LmFmdGVyKGl0ZW1FbGVtZW50KTtcbiAgICAgIHBsdWdpbltcImRvXCJdKGl0ZW1FbGVtZW50LCBpdGVtKTtcbiAgICAgIGl0ZW1CZWZvcmUgPSB3aWtpLmdldEl0ZW0oYmVmb3JlRWxlbWVudCk7XG4gICAgICB3aWtpLnRleHRFZGl0b3IoaXRlbUVsZW1lbnQsIGl0ZW0pO1xuICAgICAgcmV0dXJuIHNsZWVwKDUwMCwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBwYWdlSGFuZGxlci5wdXQocGFnZUVsZW1lbnQsIHtcbiAgICAgICAgICBpdGVtOiBpdGVtLFxuICAgICAgICAgIGlkOiBpdGVtLmlkLFxuICAgICAgICAgIHR5cGU6ICdhZGQnLFxuICAgICAgICAgIGFmdGVyOiBpdGVtQmVmb3JlICE9IG51bGwgPyBpdGVtQmVmb3JlLmlkIDogdm9pZCAwXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfTtcbiAgICB0ZXh0RWRpdG9yID0gd2lraS50ZXh0RWRpdG9yID0gZnVuY3Rpb24oZGl2LCBpdGVtLCBjYXJldFBvcywgZG91YmxlQ2xpY2tlZCkge1xuICAgICAgdmFyIG9yaWdpbmFsLCB0ZXh0YXJlYSwgX3JlZjtcbiAgICAgIGlmIChkaXYuaGFzQ2xhc3MoJ3RleHRFZGl0aW5nJykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgZGl2LmFkZENsYXNzKCd0ZXh0RWRpdGluZycpO1xuICAgICAgdGV4dGFyZWEgPSAkKFwiPHRleHRhcmVhPlwiICsgKG9yaWdpbmFsID0gKF9yZWYgPSBpdGVtLnRleHQpICE9IG51bGwgPyBfcmVmIDogJycpICsgXCI8L3RleHRhcmVhPlwiKS5mb2N1c291dChmdW5jdGlvbigpIHtcbiAgICAgICAgZGl2LnJlbW92ZUNsYXNzKCd0ZXh0RWRpdGluZycpO1xuICAgICAgICBpZiAoaXRlbS50ZXh0ID0gdGV4dGFyZWEudmFsKCkpIHtcbiAgICAgICAgICBwbHVnaW5bXCJkb1wiXShkaXYuZW1wdHkoKSwgaXRlbSk7XG4gICAgICAgICAgaWYgKGl0ZW0udGV4dCA9PT0gb3JpZ2luYWwpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgcGFnZUhhbmRsZXIucHV0KGRpdi5wYXJlbnRzKCcucGFnZTpmaXJzdCcpLCB7XG4gICAgICAgICAgICB0eXBlOiAnZWRpdCcsXG4gICAgICAgICAgICBpZDogaXRlbS5pZCxcbiAgICAgICAgICAgIGl0ZW06IGl0ZW1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwYWdlSGFuZGxlci5wdXQoZGl2LnBhcmVudHMoJy5wYWdlOmZpcnN0JyksIHtcbiAgICAgICAgICAgIHR5cGU6ICdyZW1vdmUnLFxuICAgICAgICAgICAgaWQ6IGl0ZW0uaWRcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBkaXYucmVtb3ZlKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9KS5iaW5kKCdrZXlkb3duJywgZnVuY3Rpb24oZSkge1xuICAgICAgICB2YXIgbWlkZGxlLCBwYWdlLCBwYWdlRWxlbWVudCwgcHJlZml4LCBwcmV2SXRlbSwgcHJldlRleHRMZW4sIHNlbCwgc3VmZml4LCB0ZXh0O1xuICAgICAgICBpZiAoKGUuYWx0S2V5IHx8IGUuY3RsS2V5IHx8IGUubWV0YUtleSkgJiYgZS53aGljaCA9PT0gODMpIHtcbiAgICAgICAgICB0ZXh0YXJlYS5mb2N1c291dCgpO1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoKGUuYWx0S2V5IHx8IGUuY3RsS2V5IHx8IGUubWV0YUtleSkgJiYgZS53aGljaCA9PT0gNzMpIHtcbiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgaWYgKCFlLnNoaWZ0S2V5KSB7XG4gICAgICAgICAgICBwYWdlID0gJChlLnRhcmdldCkucGFyZW50cygnLnBhZ2UnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZG9JbnRlcm5hbExpbmsoXCJhYm91dCBcIiArIGl0ZW0udHlwZSArIFwiIHBsdWdpblwiLCBwYWdlKTtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGl0ZW0udHlwZSA9PT0gJ3BhcmFncmFwaCcpIHtcbiAgICAgICAgICBzZWwgPSB1dGlsLmdldFNlbGVjdGlvblBvcyh0ZXh0YXJlYSk7XG4gICAgICAgICAgaWYgKGUud2hpY2ggPT09ICQudWkua2V5Q29kZS5CQUNLU1BBQ0UgJiYgc2VsLnN0YXJ0ID09PSAwICYmIHNlbC5zdGFydCA9PT0gc2VsLmVuZCkge1xuICAgICAgICAgICAgcHJldkl0ZW0gPSB3aWtpLmdldEl0ZW0oZGl2LnByZXYoKSk7XG4gICAgICAgICAgICBpZiAocHJldkl0ZW0udHlwZSAhPT0gJ3BhcmFncmFwaCcpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcHJldlRleHRMZW4gPSBwcmV2SXRlbS50ZXh0Lmxlbmd0aDtcbiAgICAgICAgICAgIHByZXZJdGVtLnRleHQgKz0gdGV4dGFyZWEudmFsKCk7XG4gICAgICAgICAgICB0ZXh0YXJlYS52YWwoJycpO1xuICAgICAgICAgICAgdGV4dEVkaXRvcihkaXYucHJldigpLCBwcmV2SXRlbSwgcHJldlRleHRMZW4pO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZS53aGljaCA9PT0gJC51aS5rZXlDb2RlLkVOVEVSICYmIGl0ZW0udHlwZSA9PT0gJ3BhcmFncmFwaCcpIHtcbiAgICAgICAgICAgIGlmICghc2VsKSB7XG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRleHQgPSB0ZXh0YXJlYS52YWwoKTtcbiAgICAgICAgICAgIHByZWZpeCA9IHRleHQuc3Vic3RyaW5nKDAsIHNlbC5zdGFydCk7XG4gICAgICAgICAgICBpZiAoc2VsLnN0YXJ0ICE9PSBzZWwuZW5kKSB7XG4gICAgICAgICAgICAgIG1pZGRsZSA9IHRleHQuc3Vic3RyaW5nKHNlbC5zdGFydCwgc2VsLmVuZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzdWZmaXggPSB0ZXh0LnN1YnN0cmluZyhzZWwuZW5kKTtcbiAgICAgICAgICAgIGlmIChwcmVmaXggPT09ICcnKSB7XG4gICAgICAgICAgICAgIHRleHRhcmVhLnZhbCgnICcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGV4dGFyZWEudmFsKHByZWZpeCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0ZXh0YXJlYS5mb2N1c291dCgpO1xuICAgICAgICAgICAgcGFnZUVsZW1lbnQgPSBkaXYucGFyZW50KCkucGFyZW50KCk7XG4gICAgICAgICAgICBjcmVhdGVUZXh0RWxlbWVudChwYWdlRWxlbWVudCwgZGl2LCBzdWZmaXgpO1xuICAgICAgICAgICAgaWYgKG1pZGRsZSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgIGNyZWF0ZVRleHRFbGVtZW50KHBhZ2VFbGVtZW50LCBkaXYsIG1pZGRsZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocHJlZml4ID09PSAnJykge1xuICAgICAgICAgICAgICBjcmVhdGVUZXh0RWxlbWVudChwYWdlRWxlbWVudCwgZGl2LCAnJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGRpdi5odG1sKHRleHRhcmVhKTtcbiAgICAgIGlmIChjYXJldFBvcyAhPSBudWxsKSB7XG4gICAgICAgIHJldHVybiB1dGlsLnNldENhcmV0UG9zaXRpb24odGV4dGFyZWEsIGNhcmV0UG9zKTtcbiAgICAgIH0gZWxzZSBpZiAoZG91YmxlQ2xpY2tlZCkge1xuICAgICAgICB1dGlsLnNldENhcmV0UG9zaXRpb24odGV4dGFyZWEsIHRleHRhcmVhLnZhbCgpLmxlbmd0aCk7XG4gICAgICAgIHJldHVybiB0ZXh0YXJlYS5zY3JvbGxUb3AodGV4dGFyZWFbMF0uc2Nyb2xsSGVpZ2h0IC0gdGV4dGFyZWEuaGVpZ2h0KCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRleHRhcmVhLmZvY3VzKCk7XG4gICAgICB9XG4gICAgfTtcbiAgICBkb0ludGVybmFsTGluayA9IHdpa2kuZG9JbnRlcm5hbExpbmsgPSBmdW5jdGlvbihuYW1lLCBwYWdlLCBzaXRlKSB7XG4gICAgICBpZiAoc2l0ZSA9PSBudWxsKSB7XG4gICAgICAgIHNpdGUgPSBudWxsO1xuICAgICAgfVxuICAgICAgbmFtZSA9IHdpa2kuYXNTbHVnKG5hbWUpO1xuICAgICAgaWYgKHBhZ2UgIT0gbnVsbCkge1xuICAgICAgICAkKHBhZ2UpLm5leHRBbGwoKS5yZW1vdmUoKTtcbiAgICAgIH1cbiAgICAgIHdpa2kuY3JlYXRlUGFnZShuYW1lLCBzaXRlKS5hcHBlbmRUbygkKCcubWFpbicpKS5lYWNoKHJlZnJlc2gpO1xuICAgICAgcmV0dXJuIGFjdGl2ZS5zZXQoJCgnLnBhZ2UnKS5sYXN0KCkpO1xuICAgIH07XG4gICAgTEVGVEFSUk9XID0gMzc7XG4gICAgUklHSFRBUlJPVyA9IDM5O1xuICAgICQoZG9jdW1lbnQpLmtleWRvd24oZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAgIHZhciBkaXJlY3Rpb24sIG5ld0luZGV4LCBwYWdlcztcbiAgICAgIGRpcmVjdGlvbiA9IChmdW5jdGlvbigpIHtcbiAgICAgICAgc3dpdGNoIChldmVudC53aGljaCkge1xuICAgICAgICAgIGNhc2UgTEVGVEFSUk9XOlxuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgIGNhc2UgUklHSFRBUlJPVzpcbiAgICAgICAgICAgIHJldHVybiArMTtcbiAgICAgICAgfVxuICAgICAgfSkoKTtcbiAgICAgIGlmIChkaXJlY3Rpb24gJiYgIShldmVudC50YXJnZXQudGFnTmFtZSA9PT0gXCJURVhUQVJFQVwiKSkge1xuICAgICAgICBwYWdlcyA9ICQoJy5wYWdlJyk7XG4gICAgICAgIG5ld0luZGV4ID0gcGFnZXMuaW5kZXgoJCgnLmFjdGl2ZScpKSArIGRpcmVjdGlvbjtcbiAgICAgICAgaWYgKCgwIDw9IG5ld0luZGV4ICYmIG5ld0luZGV4IDwgcGFnZXMubGVuZ3RoKSkge1xuICAgICAgICAgIHJldHVybiBhY3RpdmUuc2V0KHBhZ2VzLmVxKG5ld0luZGV4KSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICAkKHdpbmRvdykub24oJ3BvcHN0YXRlJywgc3RhdGUuc2hvdyk7XG4gICAgJChkb2N1bWVudCkuYWpheEVycm9yKGZ1bmN0aW9uKGV2ZW50LCByZXF1ZXN0LCBzZXR0aW5ncykge1xuICAgICAgaWYgKHJlcXVlc3Quc3RhdHVzID09PSAwIHx8IHJlcXVlc3Quc3RhdHVzID09PSA0MDQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgd2lraS5sb2coJ2FqYXggZXJyb3InLCBldmVudCwgcmVxdWVzdCwgc2V0dGluZ3MpO1xuICAgICAgcmV0dXJuICQoJy5tYWluJykucHJlcGVuZChcIjxsaSBjbGFzcz0nZXJyb3InPlxcbiAgRXJyb3Igb24gXCIgKyBzZXR0aW5ncy51cmwgKyBcIjogXCIgKyByZXF1ZXN0LnJlc3BvbnNlVGV4dCArIFwiXFxuPC9saT5cIik7XG4gICAgfSk7XG4gICAgZ2V0VGVtcGxhdGUgPSBmdW5jdGlvbihzbHVnLCBkb25lKSB7XG4gICAgICBpZiAoIXNsdWcpIHtcbiAgICAgICAgcmV0dXJuIGRvbmUobnVsbCk7XG4gICAgICB9XG4gICAgICB3aWtpLmxvZygnZ2V0VGVtcGxhdGUnLCBzbHVnKTtcbiAgICAgIHJldHVybiBwYWdlSGFuZGxlci5nZXQoe1xuICAgICAgICB3aGVuR290dGVuOiBmdW5jdGlvbihkYXRhLCBzaXRlRm91bmQpIHtcbiAgICAgICAgICByZXR1cm4gZG9uZShkYXRhLnN0b3J5KTtcbiAgICAgICAgfSxcbiAgICAgICAgd2hlbk5vdEdvdHRlbjogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIGRvbmUobnVsbCk7XG4gICAgICAgIH0sXG4gICAgICAgIHBhZ2VJbmZvcm1hdGlvbjoge1xuICAgICAgICAgIHNsdWc6IHNsdWdcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcbiAgICBmaW5pc2hDbGljayA9IGZ1bmN0aW9uKGUsIG5hbWUpIHtcbiAgICAgIHZhciBwYWdlO1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgaWYgKCFlLnNoaWZ0S2V5KSB7XG4gICAgICAgIHBhZ2UgPSAkKGUudGFyZ2V0KS5wYXJlbnRzKCcucGFnZScpO1xuICAgICAgfVxuICAgICAgZG9JbnRlcm5hbExpbmsobmFtZSwgcGFnZSwgJChlLnRhcmdldCkuZGF0YSgnc2l0ZScpKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9O1xuICAgICQoJy5tYWluJykuZGVsZWdhdGUoJy5zaG93LXBhZ2Utc291cmNlJywgJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgdmFyIGpzb24sIHBhZ2VFbGVtZW50O1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgcGFnZUVsZW1lbnQgPSAkKHRoaXMpLnBhcmVudCgpLnBhcmVudCgpO1xuICAgICAganNvbiA9IHBhZ2VFbGVtZW50LmRhdGEoJ2RhdGEnKTtcbiAgICAgIHJldHVybiB3aWtpLmRpYWxvZyhcIkpTT04gZm9yIFwiICsganNvbi50aXRsZSwgJCgnPHByZS8+JykudGV4dChKU09OLnN0cmluZ2lmeShqc29uLCBudWxsLCAyKSkpO1xuICAgIH0pLmRlbGVnYXRlKCcucGFnZScsICdjbGljaycsIGZ1bmN0aW9uKGUpIHtcbiAgICAgIGlmICghJChlLnRhcmdldCkuaXMoXCJhXCIpKSB7XG4gICAgICAgIHJldHVybiBhY3RpdmUuc2V0KHRoaXMpO1xuICAgICAgfVxuICAgIH0pLmRlbGVnYXRlKCcuaW50ZXJuYWwnLCAnY2xpY2snLCBmdW5jdGlvbihlKSB7XG4gICAgICB2YXIgbmFtZTtcbiAgICAgIG5hbWUgPSAkKGUudGFyZ2V0KS5kYXRhKCdwYWdlTmFtZScpO1xuICAgICAgcGFnZUhhbmRsZXIuY29udGV4dCA9ICQoZS50YXJnZXQpLmF0dHIoJ3RpdGxlJykuc3BsaXQoJyA9PiAnKTtcbiAgICAgIHJldHVybiBmaW5pc2hDbGljayhlLCBuYW1lKTtcbiAgICB9KS5kZWxlZ2F0ZSgnaW1nLnJlbW90ZScsICdjbGljaycsIGZ1bmN0aW9uKGUpIHtcbiAgICAgIHZhciBuYW1lO1xuICAgICAgbmFtZSA9ICQoZS50YXJnZXQpLmRhdGEoJ3NsdWcnKTtcbiAgICAgIHBhZ2VIYW5kbGVyLmNvbnRleHQgPSBbJChlLnRhcmdldCkuZGF0YSgnc2l0ZScpXTtcbiAgICAgIHJldHVybiBmaW5pc2hDbGljayhlLCBuYW1lKTtcbiAgICB9KS5kZWxlZ2F0ZSgnLnJldmlzaW9uJywgJ2RibGNsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgdmFyICRwYWdlLCBhY3Rpb24sIGpzb24sIHBhZ2UsIHJldjtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICRwYWdlID0gJCh0aGlzKS5wYXJlbnRzKCcucGFnZScpO1xuICAgICAgcGFnZSA9ICRwYWdlLmRhdGEoJ2RhdGEnKTtcbiAgICAgIHJldiA9IHBhZ2Uuam91cm5hbC5sZW5ndGggLSAxO1xuICAgICAgYWN0aW9uID0gcGFnZS5qb3VybmFsW3Jldl07XG4gICAgICBqc29uID0gSlNPTi5zdHJpbmdpZnkoYWN0aW9uLCBudWxsLCAyKTtcbiAgICAgIHJldHVybiB3aWtpLmRpYWxvZyhcIlJldmlzaW9uIFwiICsgcmV2ICsgXCIsIFwiICsgYWN0aW9uLnR5cGUgKyBcIiBhY3Rpb25cIiwgJCgnPHByZS8+JykudGV4dChqc29uKSk7XG4gICAgfSkuZGVsZWdhdGUoJy5hY3Rpb24nLCAnY2xpY2snLCBmdW5jdGlvbihlKSB7XG4gICAgICB2YXIgJGFjdGlvbiwgJHBhZ2UsIG5hbWUsIHJldiwgc2x1ZztcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICRhY3Rpb24gPSAkKGUudGFyZ2V0KTtcbiAgICAgIGlmICgkYWN0aW9uLmlzKCcuZm9yaycpICYmICgobmFtZSA9ICRhY3Rpb24uZGF0YSgnc2x1ZycpKSAhPSBudWxsKSkge1xuICAgICAgICBwYWdlSGFuZGxlci5jb250ZXh0ID0gWyRhY3Rpb24uZGF0YSgnc2l0ZScpXTtcbiAgICAgICAgcmV0dXJuIGZpbmlzaENsaWNrKGUsIChuYW1lLnNwbGl0KCdfJykpWzBdKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgICRwYWdlID0gJCh0aGlzKS5wYXJlbnRzKCcucGFnZScpO1xuICAgICAgICBzbHVnID0gd2lraS5hc1NsdWcoJHBhZ2UuZGF0YSgnZGF0YScpLnRpdGxlKTtcbiAgICAgICAgcmV2ID0gJCh0aGlzKS5wYXJlbnQoKS5jaGlsZHJlbigpLmluZGV4KCRhY3Rpb24pO1xuICAgICAgICBpZiAoIWUuc2hpZnRLZXkpIHtcbiAgICAgICAgICAkcGFnZS5uZXh0QWxsKCkucmVtb3ZlKCk7XG4gICAgICAgIH1cbiAgICAgICAgd2lraS5jcmVhdGVQYWdlKFwiXCIgKyBzbHVnICsgXCJfcmV2XCIgKyByZXYsICRwYWdlLmRhdGEoJ3NpdGUnKSkuYXBwZW5kVG8oJCgnLm1haW4nKSkuZWFjaChyZWZyZXNoKTtcbiAgICAgICAgcmV0dXJuIGFjdGl2ZS5zZXQoJCgnLnBhZ2UnKS5sYXN0KCkpO1xuICAgICAgfVxuICAgIH0pLmRlbGVnYXRlKCcuZm9yay1wYWdlJywgJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgdmFyIGl0ZW0sIHBhZ2VFbGVtZW50LCByZW1vdGVTaXRlO1xuICAgICAgcGFnZUVsZW1lbnQgPSAkKGUudGFyZ2V0KS5wYXJlbnRzKCcucGFnZScpO1xuICAgICAgaWYgKHBhZ2VFbGVtZW50Lmhhc0NsYXNzKCdsb2NhbCcpKSB7XG4gICAgICAgIGlmICghd2lraS51c2VMb2NhbFN0b3JhZ2UoKSkge1xuICAgICAgICAgIGl0ZW0gPSBwYWdlRWxlbWVudC5kYXRhKCdkYXRhJyk7XG4gICAgICAgICAgcGFnZUVsZW1lbnQucmVtb3ZlQ2xhc3MoJ2xvY2FsJyk7XG4gICAgICAgICAgcmV0dXJuIHBhZ2VIYW5kbGVyLnB1dChwYWdlRWxlbWVudCwge1xuICAgICAgICAgICAgdHlwZTogJ2ZvcmsnLFxuICAgICAgICAgICAgaXRlbTogaXRlbVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoKHJlbW90ZVNpdGUgPSBwYWdlRWxlbWVudC5kYXRhKCdzaXRlJykpICE9IG51bGwpIHtcbiAgICAgICAgICByZXR1cm4gcGFnZUhhbmRsZXIucHV0KHBhZ2VFbGVtZW50LCB7XG4gICAgICAgICAgICB0eXBlOiAnZm9yaycsXG4gICAgICAgICAgICBzaXRlOiByZW1vdGVTaXRlXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KS5kZWxlZ2F0ZSgnLmFjdGlvbicsICdob3ZlcicsIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGlkO1xuICAgICAgaWQgPSAkKHRoaXMpLmF0dHIoJ2RhdGEtaWQnKTtcbiAgICAgICQoXCJbZGF0YS1pZD1cIiArIGlkICsgXCJdXCIpLnRvZ2dsZUNsYXNzKCd0YXJnZXQnKTtcbiAgICAgIHJldHVybiAkKCcubWFpbicpLnRyaWdnZXIoJ3JldicpO1xuICAgIH0pLmRlbGVnYXRlKCcuaXRlbScsICdob3ZlcicsIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGlkO1xuICAgICAgaWQgPSAkKHRoaXMpLmF0dHIoJ2RhdGEtaWQnKTtcbiAgICAgIHJldHVybiAkKFwiLmFjdGlvbltkYXRhLWlkPVwiICsgaWQgKyBcIl1cIikudG9nZ2xlQ2xhc3MoJ3RhcmdldCcpO1xuICAgIH0pLmRlbGVnYXRlKCdidXR0b24uY3JlYXRlJywgJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgcmV0dXJuIGdldFRlbXBsYXRlKCQoZS50YXJnZXQpLmRhdGEoJ3NsdWcnKSwgZnVuY3Rpb24oc3RvcnkpIHtcbiAgICAgICAgdmFyICRwYWdlLCBwYWdlLCBwYWdlT2JqZWN0O1xuICAgICAgICAkcGFnZSA9ICQoZS50YXJnZXQpLnBhcmVudHMoJy5wYWdlOmZpcnN0Jyk7XG4gICAgICAgICRwYWdlLnJlbW92ZUNsYXNzKCdnaG9zdCcpO1xuICAgICAgICBwYWdlID0gJHBhZ2UuZGF0YSgnZGF0YScpO1xuICAgICAgICBwYWdlLnN0b3J5ID0gc3RvcnkgfHwgW107XG4gICAgICAgIHBhZ2VPYmplY3QgPSBuZXdQYWdlKHBhZ2UsIG51bGwpO1xuICAgICAgICBwYWdlID0gcGFnZU9iamVjdC5nZXRSYXdQYWdlKCk7XG4gICAgICAgIHBhZ2VIYW5kbGVyLnB1dCgkcGFnZSwge1xuICAgICAgICAgIHR5cGU6ICdjcmVhdGUnLFxuICAgICAgICAgIGlkOiBwYWdlLmlkLFxuICAgICAgICAgIGl0ZW06IHtcbiAgICAgICAgICAgIHRpdGxlOiBwYWdlLnRpdGxlLFxuICAgICAgICAgICAgc3Rvcnk6IHBhZ2Uuc3RvcnlcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gd2lraS5idWlsZFBhZ2UocGFnZU9iamVjdCwgJHBhZ2UuZW1wdHkoKSk7XG4gICAgICB9KTtcbiAgICB9KS5kZWxlZ2F0ZSgnLmdob3N0JywgJ3JldicsIGZ1bmN0aW9uKGUpIHtcbiAgICAgIHZhciAkaXRlbSwgJHBhZ2UsIHBvc2l0aW9uO1xuICAgICAgd2lraS5sb2coJ3JldicsIGUpO1xuICAgICAgJHBhZ2UgPSAkKGUudGFyZ2V0KS5wYXJlbnRzKCcucGFnZTpmaXJzdCcpO1xuICAgICAgJGl0ZW0gPSAkcGFnZS5maW5kKCcudGFyZ2V0Jyk7XG4gICAgICBwb3NpdGlvbiA9ICRpdGVtLm9mZnNldCgpLnRvcCArICRwYWdlLnNjcm9sbFRvcCgpIC0gJHBhZ2UuaGVpZ2h0KCkgLyAyO1xuICAgICAgd2lraS5sb2coJ3Njcm9sbCcsICRwYWdlLCAkaXRlbSwgcG9zaXRpb24pO1xuICAgICAgcmV0dXJuICRwYWdlLnN0b3AoKS5hbmltYXRlKHtcbiAgICAgICAgc2Nyb2xsVG9wOiBwb3N0aW9uXG4gICAgICB9LCAnc2xvdycpO1xuICAgIH0pLmRlbGVnYXRlKCcuc2NvcmUnLCAnaG92ZXInLCBmdW5jdGlvbihlKSB7XG4gICAgICByZXR1cm4gJCgnLm1haW4nKS50cmlnZ2VyKCd0aHVtYicsICQoZS50YXJnZXQpLmRhdGEoJ3RodW1iJykpO1xuICAgIH0pO1xuICAgICQoXCIucHJvdmlkZXIgaW5wdXRcIikuY2xpY2soZnVuY3Rpb24oKSB7XG4gICAgICAkKFwiZm9vdGVyIGlucHV0OmZpcnN0XCIpLnZhbCgkKHRoaXMpLmF0dHIoJ2RhdGEtcHJvdmlkZXInKSk7XG4gICAgICByZXR1cm4gJChcImZvb3RlciBmb3JtXCIpLnN1Ym1pdCgpO1xuICAgIH0pO1xuICAgICQoJ2JvZHknKS5vbignbmV3LW5laWdoYm9yLWRvbmUnLCBmdW5jdGlvbihlLCBuZWlnaGJvcikge1xuICAgICAgcmV0dXJuICQoJy5wYWdlJykuZWFjaChmdW5jdGlvbihpbmRleCwgZWxlbWVudCkge1xuICAgICAgICByZXR1cm4gd2lraS5lbWl0VHdpbnMoJChlbGVtZW50KSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICByZXR1cm4gJChmdW5jdGlvbigpIHtcbiAgICAgIHN0YXRlLmZpcnN0KCk7XG4gICAgICAkKCcucGFnZScpLmVhY2gocmVmcmVzaCk7XG4gICAgICByZXR1cm4gYWN0aXZlLnNldCgkKCcucGFnZScpLmxhc3QoKSk7XG4gICAgfSk7XG4gIH0pO1xuXG59KS5jYWxsKHRoaXMpO1xuIiwiKGZ1bmN0aW9uKCkge1xuICBtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHBhZ2UpIHtcbiAgICB2YXIgcDEsIHAyLCBzeW5vcHNpcztcbiAgICBzeW5vcHNpcyA9IHBhZ2Uuc3lub3BzaXM7XG4gICAgaWYgKChwYWdlICE9IG51bGwpICYmIChwYWdlLnN0b3J5ICE9IG51bGwpKSB7XG4gICAgICBwMSA9IHBhZ2Uuc3RvcnlbMF07XG4gICAgICBwMiA9IHBhZ2Uuc3RvcnlbMV07XG4gICAgICBpZiAocDEgJiYgcDEudHlwZSA9PT0gJ3BhcmFncmFwaCcpIHtcbiAgICAgICAgc3lub3BzaXMgfHwgKHN5bm9wc2lzID0gcDEudGV4dCk7XG4gICAgICB9XG4gICAgICBpZiAocDIgJiYgcDIudHlwZSA9PT0gJ3BhcmFncmFwaCcpIHtcbiAgICAgICAgc3lub3BzaXMgfHwgKHN5bm9wc2lzID0gcDIudGV4dCk7XG4gICAgICB9XG4gICAgICBpZiAocDEgJiYgKHAxLnRleHQgIT0gbnVsbCkpIHtcbiAgICAgICAgc3lub3BzaXMgfHwgKHN5bm9wc2lzID0gcDEudGV4dCk7XG4gICAgICB9XG4gICAgICBpZiAocDIgJiYgKHAyLnRleHQgIT0gbnVsbCkpIHtcbiAgICAgICAgc3lub3BzaXMgfHwgKHN5bm9wc2lzID0gcDIudGV4dCk7XG4gICAgICB9XG4gICAgICBzeW5vcHNpcyB8fCAoc3lub3BzaXMgPSAocGFnZS5zdG9yeSAhPSBudWxsKSAmJiAoXCJBIHBhZ2Ugd2l0aCBcIiArIHBhZ2Uuc3RvcnkubGVuZ3RoICsgXCIgaXRlbXMuXCIpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3lub3BzaXMgPSAnQSBwYWdlIHdpdGggbm8gc3RvcnkuJztcbiAgICB9XG4gICAgcmV0dXJuIHN5bm9wc2lzO1xuICB9O1xuXG59KS5jYWxsKHRoaXMpO1xuIiwiKGZ1bmN0aW9uKCkge1xuICBtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKG93bmVyKSB7XG4gICAgJChcIiN1c2VyLWVtYWlsXCIpLmhpZGUoKTtcbiAgICAkKFwiI3BlcnNvbmEtbG9naW4tYnRuXCIpLmhpZGUoKTtcbiAgICAkKFwiI3BlcnNvbmEtbG9nb3V0LWJ0blwiKS5oaWRlKCk7XG4gICAgbmF2aWdhdG9yLmlkLndhdGNoKHtcbiAgICAgIGxvZ2dlZEluVXNlcjogb3duZXIsXG4gICAgICBvbmxvZ2luOiBmdW5jdGlvbihhc3NlcnRpb24pIHtcbiAgICAgICAgcmV0dXJuICQucG9zdChcIi9wZXJzb25hX2xvZ2luXCIsIHtcbiAgICAgICAgICBhc3NlcnRpb246IGFzc2VydGlvblxuICAgICAgICB9LCBmdW5jdGlvbih2ZXJpZmllZCkge1xuICAgICAgICAgIHZlcmlmaWVkID0gSlNPTi5wYXJzZSh2ZXJpZmllZCk7XG4gICAgICAgICAgaWYgKFwib2theVwiID09PSB2ZXJpZmllZC5zdGF0dXMpIHtcbiAgICAgICAgICAgIHJldHVybiB3aW5kb3cubG9jYXRpb24gPSBcIi9cIjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbmF2aWdhdG9yLmlkLmxvZ291dCgpO1xuICAgICAgICAgICAgaWYgKFwid3JvbmctYWRkcmVzc1wiID09PSB2ZXJpZmllZC5zdGF0dXMpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHdpbmRvdy5sb2NhdGlvbiA9IFwiL29vcHNcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICAgIG9ubG9nb3V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuICQucG9zdChcIi9wZXJzb25hX2xvZ291dFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gd2luZG93LmxvY2F0aW9uID0gXCIvXCI7XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICAgIG9ucmVhZHk6IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAob3duZXIpIHtcbiAgICAgICAgICAkKFwiI3BlcnNvbmEtbG9naW4tYnRuXCIpLmhpZGUoKTtcbiAgICAgICAgICByZXR1cm4gJChcIiNwZXJzb25hLWxvZ291dC1idG5cIikuc2hvdygpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICQoXCIjcGVyc29uYS1sb2dpbi1idG5cIikuc2hvdygpO1xuICAgICAgICAgIHJldHVybiAkKFwiI3BlcnNvbmEtbG9nb3V0LWJ0blwiKS5oaWRlKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICAkKFwiI3BlcnNvbmEtbG9naW4tYnRuXCIpLmNsaWNrKGZ1bmN0aW9uKGUpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIHJldHVybiBuYXZpZ2F0b3IuaWQucmVxdWVzdCh7fSk7XG4gICAgfSk7XG4gICAgcmV0dXJuICQoXCIjcGVyc29uYS1sb2dvdXQtYnRuXCIpLmNsaWNrKGZ1bmN0aW9uKGUpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIHJldHVybiBuYXZpZ2F0b3IuaWQubG9nb3V0KCk7XG4gICAgfSk7XG4gIH07XG5cbn0pLmNhbGwodGhpcyk7XG4iLCIoZnVuY3Rpb24oKSB7XG4gIHZhciBhY3RpdmUsIGZpbmRTY3JvbGxDb250YWluZXIsIHNjcm9sbFRvO1xuXG4gIG1vZHVsZS5leHBvcnRzID0gYWN0aXZlID0ge307XG5cbiAgYWN0aXZlLnNjcm9sbENvbnRhaW5lciA9IHZvaWQgMDtcblxuICBmaW5kU2Nyb2xsQ29udGFpbmVyID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHNjcm9sbGVkO1xuICAgIHNjcm9sbGVkID0gJChcImJvZHksIGh0bWxcIikuZmlsdGVyKGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuICQodGhpcykuc2Nyb2xsTGVmdCgpID4gMDtcbiAgICB9KTtcbiAgICBpZiAoc2Nyb2xsZWQubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIHNjcm9sbGVkO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gJChcImJvZHksIGh0bWxcIikuc2Nyb2xsTGVmdCgxMikuZmlsdGVyKGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gJCh0aGlzKS5zY3JvbGxMZWZ0KCkgPiAwO1xuICAgICAgfSkuc2Nyb2xsVG9wKDApO1xuICAgIH1cbiAgfTtcblxuICBzY3JvbGxUbyA9IGZ1bmN0aW9uKGVsKSB7XG4gICAgdmFyIGJvZHlXaWR0aCwgY29udGVudFdpZHRoLCBtYXhYLCBtaW5YLCB0YXJnZXQsIHdpZHRoO1xuICAgIGlmIChhY3RpdmUuc2Nyb2xsQ29udGFpbmVyID09IG51bGwpIHtcbiAgICAgIGFjdGl2ZS5zY3JvbGxDb250YWluZXIgPSBmaW5kU2Nyb2xsQ29udGFpbmVyKCk7XG4gICAgfVxuICAgIGJvZHlXaWR0aCA9ICQoXCJib2R5XCIpLndpZHRoKCk7XG4gICAgbWluWCA9IGFjdGl2ZS5zY3JvbGxDb250YWluZXIuc2Nyb2xsTGVmdCgpO1xuICAgIG1heFggPSBtaW5YICsgYm9keVdpZHRoO1xuICAgIHRhcmdldCA9IGVsLnBvc2l0aW9uKCkubGVmdDtcbiAgICB3aWR0aCA9IGVsLm91dGVyV2lkdGgodHJ1ZSk7XG4gICAgY29udGVudFdpZHRoID0gJChcIi5wYWdlXCIpLm91dGVyV2lkdGgodHJ1ZSkgKiAkKFwiLnBhZ2VcIikuc2l6ZSgpO1xuICAgIGlmICh0YXJnZXQgPCBtaW5YKSB7XG4gICAgICByZXR1cm4gYWN0aXZlLnNjcm9sbENvbnRhaW5lci5hbmltYXRlKHtcbiAgICAgICAgc2Nyb2xsTGVmdDogdGFyZ2V0XG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKHRhcmdldCArIHdpZHRoID4gbWF4WCkge1xuICAgICAgcmV0dXJuIGFjdGl2ZS5zY3JvbGxDb250YWluZXIuYW5pbWF0ZSh7XG4gICAgICAgIHNjcm9sbExlZnQ6IHRhcmdldCAtIChib2R5V2lkdGggLSB3aWR0aClcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAobWF4WCA+ICQoXCIucGFnZXNcIikub3V0ZXJXaWR0aCgpKSB7XG4gICAgICByZXR1cm4gYWN0aXZlLnNjcm9sbENvbnRhaW5lci5hbmltYXRlKHtcbiAgICAgICAgc2Nyb2xsTGVmdDogTWF0aC5taW4odGFyZ2V0LCBjb250ZW50V2lkdGggLSBib2R5V2lkdGgpXG4gICAgICB9KTtcbiAgICB9XG4gIH07XG5cbiAgYWN0aXZlLnNldCA9IGZ1bmN0aW9uKGVsKSB7XG4gICAgZWwgPSAkKGVsKTtcbiAgICAkKFwiLmFjdGl2ZVwiKS5yZW1vdmVDbGFzcyhcImFjdGl2ZVwiKTtcbiAgICByZXR1cm4gc2Nyb2xsVG8oZWwuYWRkQ2xhc3MoXCJhY3RpdmVcIikpO1xuICB9O1xuXG59KS5jYWxsKHRoaXMpO1xuIiwiKGZ1bmN0aW9uKCkge1xuICB2YXIgdXRpbCwgd2lraTtcblxuICB3aWtpID0gcmVxdWlyZSgnLi93aWtpJyk7XG5cbiAgbW9kdWxlLmV4cG9ydHMgPSB3aWtpLnV0aWwgPSB1dGlsID0ge307XG5cbiAgdXRpbC5zeW1ib2xzID0ge1xuICAgIGNyZWF0ZTogJ+KYvCcsXG4gICAgYWRkOiAnKycsXG4gICAgZWRpdDogJ+KcjicsXG4gICAgZm9yazogJ+KakScsXG4gICAgbW92ZTogJ+KGlScsXG4gICAgcmVtb3ZlOiAn4pyVJ1xuICB9O1xuXG4gIHV0aWwucmFuZG9tQnl0ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiAoKCgxICsgTWF0aC5yYW5kb20oKSkgKiAweDEwMCkgfCAwKS50b1N0cmluZygxNikuc3Vic3RyaW5nKDEpO1xuICB9O1xuXG4gIHV0aWwucmFuZG9tQnl0ZXMgPSBmdW5jdGlvbihuKSB7XG4gICAgcmV0dXJuICgoZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgX2ksIF9yZXN1bHRzO1xuICAgICAgX3Jlc3VsdHMgPSBbXTtcbiAgICAgIGZvciAoX2kgPSAxOyAxIDw9IG4gPyBfaSA8PSBuIDogX2kgPj0gbjsgMSA8PSBuID8gX2krKyA6IF9pLS0pIHtcbiAgICAgICAgX3Jlc3VsdHMucHVzaCh1dGlsLnJhbmRvbUJ5dGUoKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gX3Jlc3VsdHM7XG4gICAgfSkoKSkuam9pbignJyk7XG4gIH07XG5cbiAgdXRpbC5mb3JtYXRUaW1lID0gZnVuY3Rpb24odGltZSkge1xuICAgIHZhciBhbSwgZCwgaCwgbWksIG1vO1xuICAgIGQgPSBuZXcgRGF0ZSgodGltZSA+IDEwMDAwMDAwMDAwID8gdGltZSA6IHRpbWUgKiAxMDAwKSk7XG4gICAgbW8gPSBbJ0phbicsICdGZWInLCAnTWFyJywgJ0FwcicsICdNYXknLCAnSnVuJywgJ0p1bCcsICdBdWcnLCAnU2VwJywgJ09jdCcsICdOb3YnLCAnRGVjJ11bZC5nZXRNb250aCgpXTtcbiAgICBoID0gZC5nZXRIb3VycygpO1xuICAgIGFtID0gaCA8IDEyID8gJ0FNJyA6ICdQTSc7XG4gICAgaCA9IGggPT09IDAgPyAxMiA6IGggPiAxMiA/IGggLSAxMiA6IGg7XG4gICAgbWkgPSAoZC5nZXRNaW51dGVzKCkgPCAxMCA/IFwiMFwiIDogXCJcIikgKyBkLmdldE1pbnV0ZXMoKTtcbiAgICByZXR1cm4gXCJcIiArIGggKyBcIjpcIiArIG1pICsgXCIgXCIgKyBhbSArIFwiPGJyPlwiICsgKGQuZ2V0RGF0ZSgpKSArIFwiIFwiICsgbW8gKyBcIiBcIiArIChkLmdldEZ1bGxZZWFyKCkpO1xuICB9O1xuXG4gIHV0aWwuZm9ybWF0RGF0ZSA9IGZ1bmN0aW9uKG1zU2luY2VFcG9jaCkge1xuICAgIHZhciBhbSwgZCwgZGF5LCBoLCBtaSwgbW8sIHNlYywgd2ssIHlyO1xuICAgIGQgPSBuZXcgRGF0ZShtc1NpbmNlRXBvY2gpO1xuICAgIHdrID0gWydTdW4nLCAnTW9uJywgJ1R1ZScsICdXZWQnLCAnVGh1JywgJ0ZyaScsICdTYXQnXVtkLmdldERheSgpXTtcbiAgICBtbyA9IFsnSmFuJywgJ0ZlYicsICdNYXInLCAnQXByJywgJ01heScsICdKdW4nLCAnSnVsJywgJ0F1ZycsICdTZXAnLCAnT2N0JywgJ05vdicsICdEZWMnXVtkLmdldE1vbnRoKCldO1xuICAgIGRheSA9IGQuZ2V0RGF0ZSgpO1xuICAgIHlyID0gZC5nZXRGdWxsWWVhcigpO1xuICAgIGggPSBkLmdldEhvdXJzKCk7XG4gICAgYW0gPSBoIDwgMTIgPyAnQU0nIDogJ1BNJztcbiAgICBoID0gaCA9PT0gMCA/IDEyIDogaCA+IDEyID8gaCAtIDEyIDogaDtcbiAgICBtaSA9IChkLmdldE1pbnV0ZXMoKSA8IDEwID8gXCIwXCIgOiBcIlwiKSArIGQuZ2V0TWludXRlcygpO1xuICAgIHNlYyA9IChkLmdldFNlY29uZHMoKSA8IDEwID8gXCIwXCIgOiBcIlwiKSArIGQuZ2V0U2Vjb25kcygpO1xuICAgIHJldHVybiBcIlwiICsgd2sgKyBcIiBcIiArIG1vICsgXCIgXCIgKyBkYXkgKyBcIiwgXCIgKyB5ciArIFwiPGJyPlwiICsgaCArIFwiOlwiICsgbWkgKyBcIjpcIiArIHNlYyArIFwiIFwiICsgYW07XG4gIH07XG5cbiAgdXRpbC5mb3JtYXRFbGFwc2VkVGltZSA9IGZ1bmN0aW9uKG1zU2luY2VFcG9jaCkge1xuICAgIHZhciBkYXlzLCBocnMsIG1pbnMsIG1vbnRocywgbXNlY3MsIHNlY3MsIHdlZWtzLCB5ZWFycztcbiAgICBtc2VjcyA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gbXNTaW5jZUVwb2NoO1xuICAgIGlmICgoc2VjcyA9IG1zZWNzIC8gMTAwMCkgPCAyKSB7XG4gICAgICByZXR1cm4gXCJcIiArIChNYXRoLmZsb29yKG1zZWNzKSkgKyBcIiBtaWxsaXNlY29uZHMgYWdvXCI7XG4gICAgfVxuICAgIGlmICgobWlucyA9IHNlY3MgLyA2MCkgPCAyKSB7XG4gICAgICByZXR1cm4gXCJcIiArIChNYXRoLmZsb29yKHNlY3MpKSArIFwiIHNlY29uZHMgYWdvXCI7XG4gICAgfVxuICAgIGlmICgoaHJzID0gbWlucyAvIDYwKSA8IDIpIHtcbiAgICAgIHJldHVybiBcIlwiICsgKE1hdGguZmxvb3IobWlucykpICsgXCIgbWludXRlcyBhZ29cIjtcbiAgICB9XG4gICAgaWYgKChkYXlzID0gaHJzIC8gMjQpIDwgMikge1xuICAgICAgcmV0dXJuIFwiXCIgKyAoTWF0aC5mbG9vcihocnMpKSArIFwiIGhvdXJzIGFnb1wiO1xuICAgIH1cbiAgICBpZiAoKHdlZWtzID0gZGF5cyAvIDcpIDwgMikge1xuICAgICAgcmV0dXJuIFwiXCIgKyAoTWF0aC5mbG9vcihkYXlzKSkgKyBcIiBkYXlzIGFnb1wiO1xuICAgIH1cbiAgICBpZiAoKG1vbnRocyA9IGRheXMgLyAzMSkgPCAyKSB7XG4gICAgICByZXR1cm4gXCJcIiArIChNYXRoLmZsb29yKHdlZWtzKSkgKyBcIiB3ZWVrcyBhZ29cIjtcbiAgICB9XG4gICAgaWYgKCh5ZWFycyA9IGRheXMgLyAzNjUpIDwgMikge1xuICAgICAgcmV0dXJuIFwiXCIgKyAoTWF0aC5mbG9vcihtb250aHMpKSArIFwiIG1vbnRocyBhZ29cIjtcbiAgICB9XG4gICAgcmV0dXJuIFwiXCIgKyAoTWF0aC5mbG9vcih5ZWFycykpICsgXCIgeWVhcnMgYWdvXCI7XG4gIH07XG5cbiAgdXRpbC5lbXB0eVBhZ2UgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdGl0bGU6ICdlbXB0eScsXG4gICAgICBzdG9yeTogW10sXG4gICAgICBqb3VybmFsOiBbXVxuICAgIH07XG4gIH07XG5cbiAgdXRpbC5nZXRTZWxlY3Rpb25Qb3MgPSBmdW5jdGlvbihqUXVlcnlFbGVtZW50KSB7XG4gICAgdmFyIGVsLCBpZVBvcywgc2VsO1xuICAgIGVsID0galF1ZXJ5RWxlbWVudC5nZXQoMCk7XG4gICAgaWYgKGRvY3VtZW50LnNlbGVjdGlvbikge1xuICAgICAgZWwuZm9jdXMoKTtcbiAgICAgIHNlbCA9IGRvY3VtZW50LnNlbGVjdGlvbi5jcmVhdGVSYW5nZSgpO1xuICAgICAgc2VsLm1vdmVTdGFydCgnY2hhcmFjdGVyJywgLWVsLnZhbHVlLmxlbmd0aCk7XG4gICAgICBpZVBvcyA9IHNlbC50ZXh0Lmxlbmd0aDtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN0YXJ0OiBpZVBvcyxcbiAgICAgICAgZW5kOiBpZVBvc1xuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3RhcnQ6IGVsLnNlbGVjdGlvblN0YXJ0LFxuICAgICAgICBlbmQ6IGVsLnNlbGVjdGlvbkVuZFxuICAgICAgfTtcbiAgICB9XG4gIH07XG5cbiAgdXRpbC5zZXRDYXJldFBvc2l0aW9uID0gZnVuY3Rpb24oalF1ZXJ5RWxlbWVudCwgY2FyZXRQb3MpIHtcbiAgICB2YXIgZWwsIHJhbmdlO1xuICAgIGVsID0galF1ZXJ5RWxlbWVudC5nZXQoMCk7XG4gICAgaWYgKGVsICE9IG51bGwpIHtcbiAgICAgIGlmIChlbC5jcmVhdGVUZXh0UmFuZ2UpIHtcbiAgICAgICAgcmFuZ2UgPSBlbC5jcmVhdGVUZXh0UmFuZ2UoKTtcbiAgICAgICAgcmFuZ2UubW92ZShcImNoYXJhY3RlclwiLCBjYXJldFBvcyk7XG4gICAgICAgIHJhbmdlLnNlbGVjdCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWwuc2V0U2VsZWN0aW9uUmFuZ2UoY2FyZXRQb3MsIGNhcmV0UG9zKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBlbC5mb2N1cygpO1xuICAgIH1cbiAgfTtcblxufSkuY2FsbCh0aGlzKTtcbiIsIihmdW5jdGlvbigpIHtcbiAgdmFyIGdldFNjcmlwdCwgcGx1Z2luLCBzY3JpcHRzLCB1dGlsLCB3aWtpO1xuXG4gIHV0aWwgPSByZXF1aXJlKCcuL3V0aWwnKTtcblxuICB3aWtpID0gcmVxdWlyZSgnLi93aWtpJyk7XG5cbiAgbW9kdWxlLmV4cG9ydHMgPSBwbHVnaW4gPSB7fTtcblxuICBzY3JpcHRzID0ge307XG5cbiAgZ2V0U2NyaXB0ID0gd2lraS5nZXRTY3JpcHQgPSBmdW5jdGlvbih1cmwsIGNhbGxiYWNrKSB7XG4gICAgaWYgKGNhbGxiYWNrID09IG51bGwpIHtcbiAgICAgIGNhbGxiYWNrID0gZnVuY3Rpb24oKSB7fTtcbiAgICB9XG4gICAgaWYgKHNjcmlwdHNbdXJsXSAhPSBudWxsKSB7XG4gICAgICByZXR1cm4gY2FsbGJhY2soKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuICQuZ2V0U2NyaXB0KHVybCkuZG9uZShmdW5jdGlvbigpIHtcbiAgICAgICAgc2NyaXB0c1t1cmxdID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrKCk7XG4gICAgICB9KS5mYWlsKGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gY2FsbGJhY2soKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfTtcblxuICBwbHVnaW4uZ2V0ID0gd2lraS5nZXRQbHVnaW4gPSBmdW5jdGlvbihuYW1lLCBjYWxsYmFjaykge1xuICAgIGlmICh3aW5kb3cucGx1Z2luc1tuYW1lXSkge1xuICAgICAgcmV0dXJuIGNhbGxiYWNrKHdpbmRvdy5wbHVnaW5zW25hbWVdKTtcbiAgICB9XG4gICAgcmV0dXJuIGdldFNjcmlwdChcIi9wbHVnaW5zL1wiICsgbmFtZSArIFwiL1wiICsgbmFtZSArIFwiLmpzXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKHdpbmRvdy5wbHVnaW5zW25hbWVdKSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayh3aW5kb3cucGx1Z2luc1tuYW1lXSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZ2V0U2NyaXB0KFwiL3BsdWdpbnMvXCIgKyBuYW1lICsgXCIuanNcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayh3aW5kb3cucGx1Z2luc1tuYW1lXSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfTtcblxuICBwbHVnaW5bXCJkb1wiXSA9IHdpa2kuZG9QbHVnaW4gPSBmdW5jdGlvbihkaXYsIGl0ZW0sIGRvbmUpIHtcbiAgICB2YXIgZXJyb3I7XG4gICAgaWYgKGRvbmUgPT0gbnVsbCkge1xuICAgICAgZG9uZSA9IGZ1bmN0aW9uKCkge307XG4gICAgfVxuICAgIGVycm9yID0gZnVuY3Rpb24oZXgpIHtcbiAgICAgIHZhciBlcnJvckVsZW1lbnQ7XG4gICAgICBlcnJvckVsZW1lbnQgPSAkKFwiPGRpdiAvPlwiKS5hZGRDbGFzcygnZXJyb3InKTtcbiAgICAgIGVycm9yRWxlbWVudC50ZXh0KGV4LnRvU3RyaW5nKCkpO1xuICAgICAgcmV0dXJuIGRpdi5hcHBlbmQoZXJyb3JFbGVtZW50KTtcbiAgICB9O1xuICAgIGRpdi5kYXRhKCdwYWdlRWxlbWVudCcsIGRpdi5wYXJlbnRzKFwiLnBhZ2VcIikpO1xuICAgIGRpdi5kYXRhKCdpdGVtJywgaXRlbSk7XG4gICAgcmV0dXJuIHBsdWdpbi5nZXQoaXRlbS50eXBlLCBmdW5jdGlvbihzY3JpcHQpIHtcbiAgICAgIHZhciBlcnI7XG4gICAgICB0cnkge1xuICAgICAgICBpZiAoc2NyaXB0ID09IG51bGwpIHtcbiAgICAgICAgICB0aHJvdyBUeXBlRXJyb3IoXCJDYW4ndCBmaW5kIHBsdWdpbiBmb3IgJ1wiICsgaXRlbS50eXBlICsgXCInXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzY3JpcHQuZW1pdC5sZW5ndGggPiAyKSB7XG4gICAgICAgICAgcmV0dXJuIHNjcmlwdC5lbWl0KGRpdiwgaXRlbSwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBzY3JpcHQuYmluZChkaXYsIGl0ZW0pO1xuICAgICAgICAgICAgcmV0dXJuIGRvbmUoKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzY3JpcHQuZW1pdChkaXYsIGl0ZW0pO1xuICAgICAgICAgIHNjcmlwdC5iaW5kKGRpdiwgaXRlbSk7XG4gICAgICAgICAgcmV0dXJuIGRvbmUoKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICAgIGVyciA9IF9lcnJvcjtcbiAgICAgICAgd2lraS5sb2coJ3BsdWdpbiBlcnJvcicsIGVycik7XG4gICAgICAgIGVycm9yKGVycik7XG4gICAgICAgIHJldHVybiBkb25lKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgd2lraS5yZWdpc3RlclBsdWdpbiA9IGZ1bmN0aW9uKHBsdWdpbk5hbWUsIHBsdWdpbkZuKSB7XG4gICAgcmV0dXJuIHdpbmRvdy5wbHVnaW5zW3BsdWdpbk5hbWVdID0gcGx1Z2luRm4oJCk7XG4gIH07XG5cbiAgd2luZG93LnBsdWdpbnMgPSB7XG4gICAgcmVmZXJlbmNlOiByZXF1aXJlKCcuL3JlZmVyZW5jZScpLFxuICAgIGZhY3Rvcnk6IHJlcXVpcmUoJy4vZmFjdG9yeScpLFxuICAgIHBhcmFncmFwaDoge1xuICAgICAgZW1pdDogZnVuY3Rpb24oZGl2LCBpdGVtKSB7XG4gICAgICAgIHZhciB0ZXh0LCBfaSwgX2xlbiwgX3JlZiwgX3Jlc3VsdHM7XG4gICAgICAgIF9yZWYgPSBpdGVtLnRleHQuc3BsaXQoL1xcblxcbisvKTtcbiAgICAgICAgX3Jlc3VsdHMgPSBbXTtcbiAgICAgICAgZm9yIChfaSA9IDAsIF9sZW4gPSBfcmVmLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICAgICAgdGV4dCA9IF9yZWZbX2ldO1xuICAgICAgICAgIGlmICh0ZXh0Lm1hdGNoKC9cXFMvKSkge1xuICAgICAgICAgICAgX3Jlc3VsdHMucHVzaChkaXYuYXBwZW5kKFwiPHA+XCIgKyAod2lraS5yZXNvbHZlTGlua3ModGV4dCkpICsgXCI8L3A+XCIpKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgX3Jlc3VsdHMucHVzaCh2b2lkIDApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gX3Jlc3VsdHM7XG4gICAgICB9LFxuICAgICAgYmluZDogZnVuY3Rpb24oZGl2LCBpdGVtKSB7XG4gICAgICAgIHJldHVybiBkaXYuZGJsY2xpY2soZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIHdpa2kudGV4dEVkaXRvcihkaXYsIGl0ZW0sIG51bGwsIHRydWUpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LFxuICAgIGltYWdlOiB7XG4gICAgICBlbWl0OiBmdW5jdGlvbihkaXYsIGl0ZW0pIHtcbiAgICAgICAgaXRlbS50ZXh0IHx8IChpdGVtLnRleHQgPSBpdGVtLmNhcHRpb24pO1xuICAgICAgICByZXR1cm4gZGl2LmFwcGVuZChcIjxpbWcgY2xhc3M9dGh1bWJuYWlsIHNyYz1cXFwiXCIgKyBpdGVtLnVybCArIFwiXFxcIj4gPHA+XCIgKyAod2lraS5yZXNvbHZlTGlua3MoaXRlbS50ZXh0KSkgKyBcIjwvcD5cIik7XG4gICAgICB9LFxuICAgICAgYmluZDogZnVuY3Rpb24oZGl2LCBpdGVtKSB7XG4gICAgICAgIGRpdi5kYmxjbGljayhmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gd2lraS50ZXh0RWRpdG9yKGRpdiwgaXRlbSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gZGl2LmZpbmQoJ2ltZycpLmRibGNsaWNrKGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiB3aWtpLmRpYWxvZyhpdGVtLnRleHQsIHRoaXMpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LFxuICAgIGZ1dHVyZToge1xuICAgICAgZW1pdDogZnVuY3Rpb24oZGl2LCBpdGVtKSB7XG4gICAgICAgIHZhciBpbmZvLCBfaSwgX2xlbiwgX3JlZiwgX3Jlc3VsdHM7XG4gICAgICAgIGRpdi5hcHBlbmQoXCJcIiArIGl0ZW0udGV4dCArIFwiPGJyPjxicj48YnV0dG9uIGNsYXNzPVxcXCJjcmVhdGVcXFwiPmNyZWF0ZTwvYnV0dG9uPiBuZXcgYmxhbmsgcGFnZVwiKTtcbiAgICAgICAgaWYgKCgoaW5mbyA9IHdpa2kubmVpZ2hib3Job29kW2xvY2F0aW9uLmhvc3RdKSAhPSBudWxsKSAmJiAoaW5mby5zaXRlbWFwICE9IG51bGwpKSB7XG4gICAgICAgICAgX3JlZiA9IGluZm8uc2l0ZW1hcDtcbiAgICAgICAgICBfcmVzdWx0cyA9IFtdO1xuICAgICAgICAgIGZvciAoX2kgPSAwLCBfbGVuID0gX3JlZi5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgICAgICAgaXRlbSA9IF9yZWZbX2ldO1xuICAgICAgICAgICAgaWYgKGl0ZW0uc2x1Zy5tYXRjaCgvLXRlbXBsYXRlJC8pKSB7XG4gICAgICAgICAgICAgIF9yZXN1bHRzLnB1c2goZGl2LmFwcGVuZChcIjxicj48YnV0dG9uIGNsYXNzPVxcXCJjcmVhdGVcXFwiIGRhdGEtc2x1Zz1cIiArIGl0ZW0uc2x1ZyArIFwiPmNyZWF0ZTwvYnV0dG9uPiBmcm9tIFwiICsgKHdpa2kucmVzb2x2ZUxpbmtzKFwiW1tcIiArIGl0ZW0udGl0bGUgKyBcIl1dXCIpKSkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgX3Jlc3VsdHMucHVzaCh2b2lkIDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gX3Jlc3VsdHM7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBiaW5kOiBmdW5jdGlvbihkaXYsIGl0ZW0pIHt9XG4gICAgfVxuICB9O1xuXG59KS5jYWxsKHRoaXMpO1xuIiwiKGZ1bmN0aW9uKCkge1xuICB2YXIgYWN0aXZlLCBzdGF0ZSwgd2lraSxcbiAgICBfX2luZGV4T2YgPSBbXS5pbmRleE9mIHx8IGZ1bmN0aW9uKGl0ZW0pIHsgZm9yICh2YXIgaSA9IDAsIGwgPSB0aGlzLmxlbmd0aDsgaSA8IGw7IGkrKykgeyBpZiAoaSBpbiB0aGlzICYmIHRoaXNbaV0gPT09IGl0ZW0pIHJldHVybiBpOyB9IHJldHVybiAtMTsgfTtcblxuICB3aWtpID0gcmVxdWlyZSgnLi93aWtpJyk7XG5cbiAgYWN0aXZlID0gcmVxdWlyZSgnLi9hY3RpdmUnKTtcblxuICBtb2R1bGUuZXhwb3J0cyA9IHN0YXRlID0ge307XG5cbiAgc3RhdGUucGFnZXNJbkRvbSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiAkLm1ha2VBcnJheSgkKFwiLnBhZ2VcIikubWFwKGZ1bmN0aW9uKF8sIGVsKSB7XG4gICAgICByZXR1cm4gZWwuaWQ7XG4gICAgfSkpO1xuICB9O1xuXG4gIHN0YXRlLnVybFBhZ2VzID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGk7XG4gICAgcmV0dXJuICgoZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgX2ksIF9sZW4sIF9yZWYsIF9yZXN1bHRzO1xuICAgICAgX3JlZiA9ICQobG9jYXRpb24pLmF0dHIoJ3BhdGhuYW1lJykuc3BsaXQoJy8nKTtcbiAgICAgIF9yZXN1bHRzID0gW107XG4gICAgICBmb3IgKF9pID0gMCwgX2xlbiA9IF9yZWYubGVuZ3RoOyBfaSA8IF9sZW47IF9pICs9IDIpIHtcbiAgICAgICAgaSA9IF9yZWZbX2ldO1xuICAgICAgICBfcmVzdWx0cy5wdXNoKGkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIF9yZXN1bHRzO1xuICAgIH0pKCkpLnNsaWNlKDEpO1xuICB9O1xuXG4gIHN0YXRlLmxvY3NJbkRvbSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiAkLm1ha2VBcnJheSgkKFwiLnBhZ2VcIikubWFwKGZ1bmN0aW9uKF8sIGVsKSB7XG4gICAgICByZXR1cm4gJChlbCkuZGF0YSgnc2l0ZScpIHx8ICd2aWV3JztcbiAgICB9KSk7XG4gIH07XG5cbiAgc3RhdGUudXJsTG9jcyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBqLCBfaSwgX2xlbiwgX3JlZiwgX3Jlc3VsdHM7XG4gICAgX3JlZiA9ICQobG9jYXRpb24pLmF0dHIoJ3BhdGhuYW1lJykuc3BsaXQoJy8nKS5zbGljZSgxKTtcbiAgICBfcmVzdWx0cyA9IFtdO1xuICAgIGZvciAoX2kgPSAwLCBfbGVuID0gX3JlZi5sZW5ndGg7IF9pIDwgX2xlbjsgX2kgKz0gMikge1xuICAgICAgaiA9IF9yZWZbX2ldO1xuICAgICAgX3Jlc3VsdHMucHVzaChqKTtcbiAgICB9XG4gICAgcmV0dXJuIF9yZXN1bHRzO1xuICB9O1xuXG4gIHN0YXRlLnNldFVybCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBpZHgsIGxvY3MsIHBhZ2UsIHBhZ2VzLCB1cmwsIF9yZWY7XG4gICAgZG9jdW1lbnQudGl0bGUgPSAoX3JlZiA9ICQoJy5wYWdlOmxhc3QnKS5kYXRhKCdkYXRhJykpICE9IG51bGwgPyBfcmVmLnRpdGxlIDogdm9pZCAwO1xuICAgIGlmIChoaXN0b3J5ICYmIGhpc3RvcnkucHVzaFN0YXRlKSB7XG4gICAgICBsb2NzID0gc3RhdGUubG9jc0luRG9tKCk7XG4gICAgICBwYWdlcyA9IHN0YXRlLnBhZ2VzSW5Eb20oKTtcbiAgICAgIHVybCA9ICgoZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBfaSwgX2xlbiwgX3Jlc3VsdHM7XG4gICAgICAgIF9yZXN1bHRzID0gW107XG4gICAgICAgIGZvciAoaWR4ID0gX2kgPSAwLCBfbGVuID0gcGFnZXMubGVuZ3RoOyBfaSA8IF9sZW47IGlkeCA9ICsrX2kpIHtcbiAgICAgICAgICBwYWdlID0gcGFnZXNbaWR4XTtcbiAgICAgICAgICBfcmVzdWx0cy5wdXNoKFwiL1wiICsgKChsb2NzICE9IG51bGwgPyBsb2NzW2lkeF0gOiB2b2lkIDApIHx8ICd2aWV3JykgKyBcIi9cIiArIHBhZ2UpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfcmVzdWx0cztcbiAgICAgIH0pKCkpLmpvaW4oJycpO1xuICAgICAgaWYgKHVybCAhPT0gJChsb2NhdGlvbikuYXR0cigncGF0aG5hbWUnKSkge1xuICAgICAgICByZXR1cm4gaGlzdG9yeS5wdXNoU3RhdGUobnVsbCwgbnVsbCwgdXJsKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgc3RhdGUuc2hvdyA9IGZ1bmN0aW9uKGUpIHtcbiAgICB2YXIgaWR4LCBuYW1lLCBuZXdMb2NzLCBuZXdQYWdlcywgb2xkLCBvbGRMb2NzLCBvbGRQYWdlcywgcHJldmlvdXMsIF9pLCBfbGVuLCBfcmVmO1xuICAgIG9sZFBhZ2VzID0gc3RhdGUucGFnZXNJbkRvbSgpO1xuICAgIG5ld1BhZ2VzID0gc3RhdGUudXJsUGFnZXMoKTtcbiAgICBvbGRMb2NzID0gc3RhdGUubG9jc0luRG9tKCk7XG4gICAgbmV3TG9jcyA9IHN0YXRlLnVybExvY3MoKTtcbiAgICBpZiAoIWxvY2F0aW9uLnBhdGhuYW1lIHx8IGxvY2F0aW9uLnBhdGhuYW1lID09PSAnLycpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgcHJldmlvdXMgPSAkKCcucGFnZScpLmVxKDApO1xuICAgIGZvciAoaWR4ID0gX2kgPSAwLCBfbGVuID0gbmV3UGFnZXMubGVuZ3RoOyBfaSA8IF9sZW47IGlkeCA9ICsrX2kpIHtcbiAgICAgIG5hbWUgPSBuZXdQYWdlc1tpZHhdO1xuICAgICAgaWYgKG5hbWUgIT09IG9sZFBhZ2VzW2lkeF0pIHtcbiAgICAgICAgb2xkID0gJCgnLnBhZ2UnKS5lcShpZHgpO1xuICAgICAgICBpZiAob2xkKSB7XG4gICAgICAgICAgb2xkLnJlbW92ZSgpO1xuICAgICAgICB9XG4gICAgICAgIHdpa2kuY3JlYXRlUGFnZShuYW1lLCBuZXdMb2NzW2lkeF0pLmluc2VydEFmdGVyKHByZXZpb3VzKS5lYWNoKHdpa2kucmVmcmVzaCk7XG4gICAgICB9XG4gICAgICBwcmV2aW91cyA9ICQoJy5wYWdlJykuZXEoaWR4KTtcbiAgICB9XG4gICAgcHJldmlvdXMubmV4dEFsbCgpLnJlbW92ZSgpO1xuICAgIGFjdGl2ZS5zZXQoJCgnLnBhZ2UnKS5sYXN0KCkpO1xuICAgIHJldHVybiBkb2N1bWVudC50aXRsZSA9IChfcmVmID0gJCgnLnBhZ2U6bGFzdCcpLmRhdGEoJ2RhdGEnKSkgIT0gbnVsbCA/IF9yZWYudGl0bGUgOiB2b2lkIDA7XG4gIH07XG5cbiAgc3RhdGUuZmlyc3QgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgZmlyc3RVcmxMb2NzLCBmaXJzdFVybFBhZ2VzLCBpZHgsIG9sZFBhZ2VzLCB1cmxQYWdlLCBfaSwgX2xlbiwgX3Jlc3VsdHM7XG4gICAgc3RhdGUuc2V0VXJsKCk7XG4gICAgZmlyc3RVcmxQYWdlcyA9IHN0YXRlLnVybFBhZ2VzKCk7XG4gICAgZmlyc3RVcmxMb2NzID0gc3RhdGUudXJsTG9jcygpO1xuICAgIG9sZFBhZ2VzID0gc3RhdGUucGFnZXNJbkRvbSgpO1xuICAgIF9yZXN1bHRzID0gW107XG4gICAgZm9yIChpZHggPSBfaSA9IDAsIF9sZW4gPSBmaXJzdFVybFBhZ2VzLmxlbmd0aDsgX2kgPCBfbGVuOyBpZHggPSArK19pKSB7XG4gICAgICB1cmxQYWdlID0gZmlyc3RVcmxQYWdlc1tpZHhdO1xuICAgICAgaWYgKF9faW5kZXhPZi5jYWxsKG9sZFBhZ2VzLCB1cmxQYWdlKSA8IDApIHtcbiAgICAgICAgaWYgKHVybFBhZ2UgIT09ICcnKSB7XG4gICAgICAgICAgX3Jlc3VsdHMucHVzaCh3aWtpLmNyZWF0ZVBhZ2UodXJsUGFnZSwgZmlyc3RVcmxMb2NzW2lkeF0pLmFwcGVuZFRvKCcubWFpbicpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBfcmVzdWx0cy5wdXNoKHZvaWQgMCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIF9yZXN1bHRzO1xuICB9O1xuXG59KS5jYWxsKHRoaXMpO1xuIiwiKGZ1bmN0aW9uKCkge1xuICB2YXIgY3JlYXRlO1xuXG4gIGNyZWF0ZSA9IGZ1bmN0aW9uKHJldkluZGV4LCBkYXRhKSB7XG4gICAgdmFyIGFmdGVySW5kZXgsIGVkaXRJbmRleCwgaXRlbUlkLCBpdGVtcywgam91cm5hbCwgam91cm5hbEVudHJ5LCByZW1vdmVJbmRleCwgcmV2Sm91cm5hbCwgcmV2U3RvcnksIHJldlN0b3J5SWRzLCByZXZUaXRsZSwgc3RvcnlJdGVtLCBfaSwgX2osIF9rLCBfbGVuLCBfbGVuMSwgX2xlbjIsIF9yZWY7XG4gICAgam91cm5hbCA9IGRhdGEuam91cm5hbDtcbiAgICByZXZUaXRsZSA9IGRhdGEudGl0bGU7XG4gICAgcmV2U3RvcnkgPSBbXTtcbiAgICByZXZKb3VybmFsID0gam91cm5hbC5zbGljZSgwLCArKCtyZXZJbmRleCkgKyAxIHx8IDllOSk7XG4gICAgZm9yIChfaSA9IDAsIF9sZW4gPSByZXZKb3VybmFsLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICBqb3VybmFsRW50cnkgPSByZXZKb3VybmFsW19pXTtcbiAgICAgIHJldlN0b3J5SWRzID0gcmV2U3RvcnkubWFwKGZ1bmN0aW9uKHN0b3J5SXRlbSkge1xuICAgICAgICByZXR1cm4gc3RvcnlJdGVtLmlkO1xuICAgICAgfSk7XG4gICAgICBzd2l0Y2ggKGpvdXJuYWxFbnRyeS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ2NyZWF0ZSc6XG4gICAgICAgICAgaWYgKGpvdXJuYWxFbnRyeS5pdGVtLnRpdGxlICE9IG51bGwpIHtcbiAgICAgICAgICAgIHJldlRpdGxlID0gam91cm5hbEVudHJ5Lml0ZW0udGl0bGU7XG4gICAgICAgICAgICByZXZTdG9yeSA9IGpvdXJuYWxFbnRyeS5pdGVtLnN0b3J5IHx8IFtdO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnYWRkJzpcbiAgICAgICAgICBpZiAoKGFmdGVySW5kZXggPSByZXZTdG9yeUlkcy5pbmRleE9mKGpvdXJuYWxFbnRyeS5hZnRlcikpICE9PSAtMSkge1xuICAgICAgICAgICAgcmV2U3Rvcnkuc3BsaWNlKGFmdGVySW5kZXggKyAxLCAwLCBqb3VybmFsRW50cnkuaXRlbSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldlN0b3J5LnB1c2goam91cm5hbEVudHJ5Lml0ZW0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnZWRpdCc6XG4gICAgICAgICAgaWYgKChlZGl0SW5kZXggPSByZXZTdG9yeUlkcy5pbmRleE9mKGpvdXJuYWxFbnRyeS5pZCkpICE9PSAtMSkge1xuICAgICAgICAgICAgcmV2U3Rvcnkuc3BsaWNlKGVkaXRJbmRleCwgMSwgam91cm5hbEVudHJ5Lml0ZW0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXZTdG9yeS5wdXNoKGpvdXJuYWxFbnRyeS5pdGVtKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ21vdmUnOlxuICAgICAgICAgIGl0ZW1zID0ge307XG4gICAgICAgICAgZm9yIChfaiA9IDAsIF9sZW4xID0gcmV2U3RvcnkubGVuZ3RoOyBfaiA8IF9sZW4xOyBfaisrKSB7XG4gICAgICAgICAgICBzdG9yeUl0ZW0gPSByZXZTdG9yeVtfal07XG4gICAgICAgICAgICBpdGVtc1tzdG9yeUl0ZW0uaWRdID0gc3RvcnlJdGVtO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXZTdG9yeSA9IFtdO1xuICAgICAgICAgIF9yZWYgPSBqb3VybmFsRW50cnkub3JkZXI7XG4gICAgICAgICAgZm9yIChfayA9IDAsIF9sZW4yID0gX3JlZi5sZW5ndGg7IF9rIDwgX2xlbjI7IF9rKyspIHtcbiAgICAgICAgICAgIGl0ZW1JZCA9IF9yZWZbX2tdO1xuICAgICAgICAgICAgaWYgKGl0ZW1zW2l0ZW1JZF0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICByZXZTdG9yeS5wdXNoKGl0ZW1zW2l0ZW1JZF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAncmVtb3ZlJzpcbiAgICAgICAgICBpZiAoKHJlbW92ZUluZGV4ID0gcmV2U3RvcnlJZHMuaW5kZXhPZihqb3VybmFsRW50cnkuaWQpKSAhPT0gLTEpIHtcbiAgICAgICAgICAgIHJldlN0b3J5LnNwbGljZShyZW1vdmVJbmRleCwgMSk7XG4gICAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgc3Rvcnk6IHJldlN0b3J5LFxuICAgICAgam91cm5hbDogcmV2Sm91cm5hbCxcbiAgICAgIHRpdGxlOiByZXZUaXRsZVxuICAgIH07XG4gIH07XG5cbiAgZXhwb3J0cy5jcmVhdGUgPSBjcmVhdGU7XG5cbn0pLmNhbGwodGhpcyk7XG4iLCIoZnVuY3Rpb24oKSB7XG4gIHZhciBiaW5kLCBlbWl0O1xuXG4gIGVtaXQgPSBmdW5jdGlvbigkaXRlbSwgaXRlbSkge1xuICAgIHZhciBzaXRlLCBzbHVnO1xuICAgIHNsdWcgPSBpdGVtLnNsdWcgfHwgJ3dlbGNvbWUtdmlzaXRvcnMnO1xuICAgIHNpdGUgPSBpdGVtLnNpdGU7XG4gICAgcmV0dXJuIHdpa2kucmVzb2x2ZUZyb20oc2l0ZSwgZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gJGl0ZW0uYXBwZW5kKFwiPHAgc3R5bGU9J21hcmdpbi1ib3R0b206M3B4Oyc+XFxuICA8aW1nIGNsYXNzPSdyZW1vdGUnXFxuICAgIHNyYz0nLy9cIiArIHNpdGUgKyBcIi9mYXZpY29uLnBuZydcXG4gICAgdGl0bGU9J1wiICsgc2l0ZSArIFwiJ1xcbiAgICBkYXRhLXNpdGU9XFxcIlwiICsgc2l0ZSArIFwiXFxcIlxcbiAgICBkYXRhLXNsdWc9XFxcIlwiICsgc2x1ZyArIFwiXFxcIlxcbiAgPlxcbiAgXCIgKyAod2lraS5yZXNvbHZlTGlua3MoXCJbW1wiICsgKGl0ZW0udGl0bGUgfHwgc2x1ZykgKyBcIl1dXCIpKSArIFwiXFxuPC9wPlxcbjxkaXY+XFxuICBcIiArICh3aWtpLnJlc29sdmVMaW5rcyhpdGVtLnRleHQpKSArIFwiXFxuPC9kaXY+XCIpO1xuICAgIH0pO1xuICB9O1xuXG4gIGJpbmQgPSBmdW5jdGlvbigkaXRlbSwgaXRlbSkge1xuICAgIHJldHVybiAkaXRlbS5kYmxjbGljayhmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiB3aWtpLnRleHRFZGl0b3IoJGl0ZW0sIGl0ZW0pO1xuICAgIH0pO1xuICB9O1xuXG4gIG1vZHVsZS5leHBvcnRzID0ge1xuICAgIGVtaXQ6IGVtaXQsXG4gICAgYmluZDogYmluZFxuICB9O1xuXG59KS5jYWxsKHRoaXMpO1xuIiwiKGZ1bmN0aW9uKCkge1xuICB2YXIgYXJyYXlUb0pzb24sIGJpbmQsIGNzdlRvQXJyYXksIGVtaXQsXG4gICAgX19pbmRleE9mID0gW10uaW5kZXhPZiB8fCBmdW5jdGlvbihpdGVtKSB7IGZvciAodmFyIGkgPSAwLCBsID0gdGhpcy5sZW5ndGg7IGkgPCBsOyBpKyspIHsgaWYgKGkgaW4gdGhpcyAmJiB0aGlzW2ldID09PSBpdGVtKSByZXR1cm4gaTsgfSByZXR1cm4gLTE7IH07XG5cbiAgZW1pdCA9IGZ1bmN0aW9uKGRpdiwgaXRlbSkge1xuICAgIHZhciBzaG93TWVudSwgc2hvd1Byb21wdDtcbiAgICBkaXYuYXBwZW5kKCc8cD5Eb3VibGUtQ2xpY2sgdG8gRWRpdDxicj5Ecm9wIFRleHQgb3IgSW1hZ2UgdG8gSW5zZXJ0PC9wPicpO1xuICAgIHNob3dNZW51ID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgaW5mbywgbWVudSwgbWVudUl0ZW0sIG5hbWUsIF9pLCBfbGVuLCBfcmVmLCBfcmVmMTtcbiAgICAgIG1lbnUgPSBkaXYuZmluZCgncCcpLmFwcGVuZChcIjxicj5PciBDaG9vc2UgYSBQbHVnaW5cIik7XG4gICAgICBtZW51SXRlbSA9IGZ1bmN0aW9uKHRpdGxlLCBuYW1lKSB7XG4gICAgICAgIHJldHVybiBtZW51LmFwcGVuZChcIjxsaT48YSBjbGFzcz1cXFwibWVudVxcXCIgaHJlZj1cXFwiI1xcXCIgdGl0bGU9XFxcIlwiICsgdGl0bGUgKyBcIlxcXCI+XCIgKyBuYW1lICsgXCI8L2E+PC9saT5cIik7XG4gICAgICB9O1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkod2luZG93LmNhdGFsb2cpKSB7XG4gICAgICAgIF9yZWYgPSB3aW5kb3cuY2F0YWxvZztcbiAgICAgICAgZm9yIChfaSA9IDAsIF9sZW4gPSBfcmVmLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICAgICAgaW5mbyA9IF9yZWZbX2ldO1xuICAgICAgICAgIG1lbnVJdGVtKGluZm8udGl0bGUsIGluZm8ubmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIF9yZWYxID0gd2luZG93LmNhdGFsb2c7XG4gICAgICAgIGZvciAobmFtZSBpbiBfcmVmMSkge1xuICAgICAgICAgIGluZm8gPSBfcmVmMVtuYW1lXTtcbiAgICAgICAgICBtZW51SXRlbShpbmZvLm1lbnUsIG5hbWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gbWVudS5maW5kKCdhLm1lbnUnKS5jbGljayhmdW5jdGlvbihldnQpIHtcbiAgICAgICAgZGl2LnJlbW92ZUNsYXNzKCdmYWN0b3J5JykuYWRkQ2xhc3MoaXRlbS50eXBlID0gZXZ0LnRhcmdldC50ZXh0LnRvTG93ZXJDYXNlKCkpO1xuICAgICAgICBkaXYudW5iaW5kKCk7XG4gICAgICAgIHJldHVybiB3aWtpLnRleHRFZGl0b3IoZGl2LCBpdGVtKTtcbiAgICAgIH0pO1xuICAgIH07XG4gICAgc2hvd1Byb21wdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIGRpdi5hcHBlbmQoXCI8cD5cIiArICh3aWtpLnJlc29sdmVMaW5rcyhpdGVtLnByb21wdCkpICsgXCI8L2I+XCIpO1xuICAgIH07XG4gICAgaWYgKGl0ZW0ucHJvbXB0KSB7XG4gICAgICByZXR1cm4gc2hvd1Byb21wdCgpO1xuICAgIH0gZWxzZSBpZiAod2luZG93LmNhdGFsb2cgIT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHNob3dNZW51KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiAkLmdldEpTT04oJy9zeXN0ZW0vZmFjdG9yaWVzLmpzb24nLCBmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgIHdpbmRvdy5jYXRhbG9nID0gZGF0YTtcbiAgICAgICAgcmV0dXJuIHNob3dNZW51KCk7XG4gICAgICB9KTtcbiAgICB9XG4gIH07XG5cbiAgYmluZCA9IGZ1bmN0aW9uKGRpdiwgaXRlbSkge1xuICAgIHZhciBzeW5jRWRpdEFjdGlvbjtcbiAgICBzeW5jRWRpdEFjdGlvbiA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGVyciwgcGFnZUVsZW1lbnQ7XG4gICAgICB3aWtpLmxvZygnZmFjdG9yeSBpdGVtJywgaXRlbSk7XG4gICAgICBkaXYuZW1wdHkoKS51bmJpbmQoKTtcbiAgICAgIGRpdi5yZW1vdmVDbGFzcyhcImZhY3RvcnlcIikuYWRkQ2xhc3MoaXRlbS50eXBlKTtcbiAgICAgIHBhZ2VFbGVtZW50ID0gZGl2LnBhcmVudHMoJy5wYWdlOmZpcnN0Jyk7XG4gICAgICB0cnkge1xuICAgICAgICBkaXYuZGF0YSgncGFnZUVsZW1lbnQnLCBwYWdlRWxlbWVudCk7XG4gICAgICAgIGRpdi5kYXRhKCdpdGVtJywgaXRlbSk7XG4gICAgICAgIHdpa2kuZ2V0UGx1Z2luKGl0ZW0udHlwZSwgZnVuY3Rpb24ocGx1Z2luKSB7XG4gICAgICAgICAgcGx1Z2luLmVtaXQoZGl2LCBpdGVtKTtcbiAgICAgICAgICByZXR1cm4gcGx1Z2luLmJpbmQoZGl2LCBpdGVtKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChfZXJyb3IpIHtcbiAgICAgICAgZXJyID0gX2Vycm9yO1xuICAgICAgICBkaXYuYXBwZW5kKFwiPHAgY2xhc3M9J2Vycm9yJz5cIiArIGVyciArIFwiPC9wPlwiKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB3aWtpLnBhZ2VIYW5kbGVyLnB1dChwYWdlRWxlbWVudCwge1xuICAgICAgICB0eXBlOiAnZWRpdCcsXG4gICAgICAgIGlkOiBpdGVtLmlkLFxuICAgICAgICBpdGVtOiBpdGVtXG4gICAgICB9KTtcbiAgICB9O1xuICAgIGRpdi5kYmxjbGljayhmdW5jdGlvbigpIHtcbiAgICAgIGRpdi5yZW1vdmVDbGFzcygnZmFjdG9yeScpLmFkZENsYXNzKGl0ZW0udHlwZSA9ICdwYXJhZ3JhcGgnKTtcbiAgICAgIGRpdi51bmJpbmQoKTtcbiAgICAgIHJldHVybiB3aWtpLnRleHRFZGl0b3IoZGl2LCBpdGVtKTtcbiAgICB9KTtcbiAgICBkaXYuYmluZCgnZHJhZ2VudGVyJywgZnVuY3Rpb24oZXZ0KSB7XG4gICAgICByZXR1cm4gZXZ0LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSk7XG4gICAgZGl2LmJpbmQoJ2RyYWdvdmVyJywgZnVuY3Rpb24oZXZ0KSB7XG4gICAgICByZXR1cm4gZXZ0LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGRpdi5iaW5kKFwiZHJvcFwiLCBmdW5jdGlvbihkcm9wRXZlbnQpIHtcbiAgICAgIHZhciBkdCwgZm91bmQsIGlnbm9yZSwgb3JpZ2luLCBwdW50LCByZWFkRmlsZSwgdXJsO1xuICAgICAgcHVudCA9IGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgICAgaXRlbS5wcm9tcHQgPSBcIjxiPlVuZXhwZWN0ZWQgSXRlbTwvYj48YnI+V2UgY2FuJ3QgbWFrZSBzZW5zZSBvZiB0aGUgZHJvcC48YnI+XCIgKyAoSlNPTi5zdHJpbmdpZnkoZGF0YSkpICsgXCI8YnI+VHJ5IHNvbWV0aGluZyBlbHNlIG9yIHNlZSBbW0Fib3V0IEZhY3RvcnkgUGx1Z2luXV0uXCI7XG4gICAgICAgIGRhdGEudXNlckFnZW50ID0gbmF2aWdhdG9yLnVzZXJBZ2VudDtcbiAgICAgICAgaXRlbS5wdW50ID0gZGF0YTtcbiAgICAgICAgd2lraS5sb2coJ2ZhY3RvcnkgcHVudCcsIGRyb3BFdmVudCk7XG4gICAgICAgIHJldHVybiBzeW5jRWRpdEFjdGlvbigpO1xuICAgICAgfTtcbiAgICAgIHJlYWRGaWxlID0gZnVuY3Rpb24oZmlsZSkge1xuICAgICAgICB2YXIgbWFqb3JUeXBlLCBtaW5vclR5cGUsIHJlYWRlciwgX3JlZjtcbiAgICAgICAgaWYgKGZpbGUgIT0gbnVsbCkge1xuICAgICAgICAgIF9yZWYgPSBmaWxlLnR5cGUuc3BsaXQoXCIvXCIpLCBtYWpvclR5cGUgPSBfcmVmWzBdLCBtaW5vclR5cGUgPSBfcmVmWzFdO1xuICAgICAgICAgIHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XG4gICAgICAgICAgaWYgKG1ham9yVHlwZSA9PT0gXCJpbWFnZVwiKSB7XG4gICAgICAgICAgICByZWFkZXIub25sb2FkID0gZnVuY3Rpb24obG9hZEV2ZW50KSB7XG4gICAgICAgICAgICAgIGl0ZW0udHlwZSA9ICdpbWFnZSc7XG4gICAgICAgICAgICAgIGl0ZW0udXJsID0gbG9hZEV2ZW50LnRhcmdldC5yZXN1bHQ7XG4gICAgICAgICAgICAgIGl0ZW0uY2FwdGlvbiB8fCAoaXRlbS5jYXB0aW9uID0gXCJVcGxvYWRlZCBpbWFnZVwiKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHN5bmNFZGl0QWN0aW9uKCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGUpO1xuICAgICAgICAgIH0gZWxzZSBpZiAobWFqb3JUeXBlID09PSBcInRleHRcIikge1xuICAgICAgICAgICAgcmVhZGVyLm9ubG9hZCA9IGZ1bmN0aW9uKGxvYWRFdmVudCkge1xuICAgICAgICAgICAgICB2YXIgYXJyYXksIHJlc3VsdDtcbiAgICAgICAgICAgICAgcmVzdWx0ID0gbG9hZEV2ZW50LnRhcmdldC5yZXN1bHQ7XG4gICAgICAgICAgICAgIGlmIChtaW5vclR5cGUgPT09ICdjc3YnKSB7XG4gICAgICAgICAgICAgICAgaXRlbS50eXBlID0gJ2RhdGEnO1xuICAgICAgICAgICAgICAgIGl0ZW0uY29sdW1ucyA9IChhcnJheSA9IGNzdlRvQXJyYXkocmVzdWx0KSlbMF07XG4gICAgICAgICAgICAgICAgaXRlbS5kYXRhID0gYXJyYXlUb0pzb24oYXJyYXkpO1xuICAgICAgICAgICAgICAgIGl0ZW0udGV4dCA9IGZpbGUuZmlsZU5hbWU7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaXRlbS50eXBlID0gJ3BhcmFncmFwaCc7XG4gICAgICAgICAgICAgICAgaXRlbS50ZXh0ID0gcmVzdWx0O1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiBzeW5jRWRpdEFjdGlvbigpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiByZWFkZXIucmVhZEFzVGV4dChmaWxlKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHB1bnQoe1xuICAgICAgICAgICAgICBudW1iZXI6IDEsXG4gICAgICAgICAgICAgIG5hbWU6IGZpbGUuZmlsZU5hbWUsXG4gICAgICAgICAgICAgIHR5cGU6IGZpbGUudHlwZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBwdW50KHtcbiAgICAgICAgICAgIG51bWJlcjogMixcbiAgICAgICAgICAgIHR5cGVzOiBkcm9wRXZlbnQub3JpZ2luYWxFdmVudC5kYXRhVHJhbnNmZXIudHlwZXNcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIGRyb3BFdmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgaWYgKChkdCA9IGRyb3BFdmVudC5vcmlnaW5hbEV2ZW50LmRhdGFUcmFuc2ZlcikgIT0gbnVsbCkge1xuICAgICAgICBpZiAoKGR0LnR5cGVzICE9IG51bGwpICYmIChfX2luZGV4T2YuY2FsbChkdC50eXBlcywgJ3RleHQvdXJpLWxpc3QnKSA+PSAwIHx8IF9faW5kZXhPZi5jYWxsKGR0LnR5cGVzLCAndGV4dC94LW1vei11cmwnKSA+PSAwKSAmJiAhKF9faW5kZXhPZi5jYWxsKGR0LnR5cGVzLCAnRmlsZXMnKSA+PSAwKSkge1xuICAgICAgICAgIHVybCA9IGR0LmdldERhdGEoJ1VSTCcpO1xuICAgICAgICAgIGlmIChmb3VuZCA9IHVybC5tYXRjaCgvXmh0dHA6XFwvXFwvKFthLXpBLVowLTk6Li1dKykoXFwvKFthLXpBLVowLTk6Li1dKylcXC8oW2EtejAtOS1dKyhfcmV2XFxkKyk/KSkrJC8pKSB7XG4gICAgICAgICAgICB3aWtpLmxvZygnZmFjdG9yeSBkcm9wIHVybCcsIGZvdW5kKTtcbiAgICAgICAgICAgIGlnbm9yZSA9IGZvdW5kWzBdLCBvcmlnaW4gPSBmb3VuZFsxXSwgaWdub3JlID0gZm91bmRbMl0sIGl0ZW0uc2l0ZSA9IGZvdW5kWzNdLCBpdGVtLnNsdWcgPSBmb3VuZFs0XSwgaWdub3JlID0gZm91bmRbNV07XG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGl0ZW0uc2l0ZSwgWyd2aWV3JywgJ2xvY2FsJywgJ29yaWdpbiddKSA+PSAwKSB7XG4gICAgICAgICAgICAgIGl0ZW0uc2l0ZSA9IG9yaWdpbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAkLmdldEpTT04oXCJodHRwOi8vXCIgKyBpdGVtLnNpdGUgKyBcIi9cIiArIGl0ZW0uc2x1ZyArIFwiLmpzb25cIiwgZnVuY3Rpb24ocmVtb3RlKSB7XG4gICAgICAgICAgICAgIHdpa2kubG9nKCdmYWN0b3J5IHJlbW90ZScsIHJlbW90ZSk7XG4gICAgICAgICAgICAgIGl0ZW0udHlwZSA9ICdyZWZlcmVuY2UnO1xuICAgICAgICAgICAgICBpdGVtLnRpdGxlID0gcmVtb3RlLnRpdGxlIHx8IGl0ZW0uc2x1ZztcbiAgICAgICAgICAgICAgaXRlbS50ZXh0ID0gd2lraS5jcmVhdGVTeW5vcHNpcyhyZW1vdGUpO1xuICAgICAgICAgICAgICBzeW5jRWRpdEFjdGlvbigpO1xuICAgICAgICAgICAgICBpZiAoaXRlbS5zaXRlICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gd2lraS5yZWdpc3Rlck5laWdoYm9yKGl0ZW0uc2l0ZSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gcHVudCh7XG4gICAgICAgICAgICAgIG51bWJlcjogNCxcbiAgICAgICAgICAgICAgdXJsOiB1cmwsXG4gICAgICAgICAgICAgIHR5cGVzOiBkdC50eXBlc1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKF9faW5kZXhPZi5jYWxsKGR0LnR5cGVzLCAnRmlsZXMnKSA+PSAwKSB7XG4gICAgICAgICAgcmV0dXJuIHJlYWRGaWxlKGR0LmZpbGVzWzBdKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gcHVudCh7XG4gICAgICAgICAgICBudW1iZXI6IDUsXG4gICAgICAgICAgICB0eXBlczogZHQudHlwZXNcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHB1bnQoe1xuICAgICAgICAgIG51bWJlcjogNixcbiAgICAgICAgICB0cm91YmxlOiBcIm5vIGRhdGEgdHJhbnNmZXIgb2JqZWN0XCJcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgY3N2VG9BcnJheSA9IGZ1bmN0aW9uKHN0ckRhdGEsIHN0ckRlbGltaXRlcikge1xuICAgIHZhciBhcnJEYXRhLCBhcnJNYXRjaGVzLCBvYmpQYXR0ZXJuLCBzdHJNYXRjaGVkRGVsaW1pdGVyLCBzdHJNYXRjaGVkVmFsdWU7XG4gICAgc3RyRGVsaW1pdGVyID0gc3RyRGVsaW1pdGVyIHx8IFwiLFwiO1xuICAgIG9ialBhdHRlcm4gPSBuZXcgUmVnRXhwKFwiKFxcXFxcIiArIHN0ckRlbGltaXRlciArIFwifFxcXFxyP1xcXFxufFxcXFxyfF4pXCIgKyBcIig/OlxcXCIoW15cXFwiXSooPzpcXFwiXFxcIlteXFxcIl0qKSopXFxcInxcIiArIFwiKFteXFxcIlxcXFxcIiArIHN0ckRlbGltaXRlciArIFwiXFxcXHJcXFxcbl0qKSlcIiwgXCJnaVwiKTtcbiAgICBhcnJEYXRhID0gW1tdXTtcbiAgICBhcnJNYXRjaGVzID0gbnVsbDtcbiAgICB3aGlsZSAoYXJyTWF0Y2hlcyA9IG9ialBhdHRlcm4uZXhlYyhzdHJEYXRhKSkge1xuICAgICAgc3RyTWF0Y2hlZERlbGltaXRlciA9IGFyck1hdGNoZXNbMV07XG4gICAgICBpZiAoc3RyTWF0Y2hlZERlbGltaXRlci5sZW5ndGggJiYgKHN0ck1hdGNoZWREZWxpbWl0ZXIgIT09IHN0ckRlbGltaXRlcikpIHtcbiAgICAgICAgYXJyRGF0YS5wdXNoKFtdKTtcbiAgICAgIH1cbiAgICAgIGlmIChhcnJNYXRjaGVzWzJdKSB7XG4gICAgICAgIHN0ck1hdGNoZWRWYWx1ZSA9IGFyck1hdGNoZXNbMl0ucmVwbGFjZShuZXcgUmVnRXhwKFwiXFxcIlxcXCJcIiwgXCJnXCIpLCBcIlxcXCJcIik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdHJNYXRjaGVkVmFsdWUgPSBhcnJNYXRjaGVzWzNdO1xuICAgICAgfVxuICAgICAgYXJyRGF0YVthcnJEYXRhLmxlbmd0aCAtIDFdLnB1c2goc3RyTWF0Y2hlZFZhbHVlKTtcbiAgICB9XG4gICAgcmV0dXJuIGFyckRhdGE7XG4gIH07XG5cbiAgYXJyYXlUb0pzb24gPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHZhciBjb2xzLCByb3csIHJvd1RvT2JqZWN0LCBfaSwgX2xlbiwgX3Jlc3VsdHM7XG4gICAgY29scyA9IGFycmF5LnNoaWZ0KCk7XG4gICAgcm93VG9PYmplY3QgPSBmdW5jdGlvbihyb3cpIHtcbiAgICAgIHZhciBrLCBvYmosIHYsIF9pLCBfbGVuLCBfcmVmLCBfcmVmMTtcbiAgICAgIG9iaiA9IHt9O1xuICAgICAgX3JlZiA9IF8uemlwKGNvbHMsIHJvdyk7XG4gICAgICBmb3IgKF9pID0gMCwgX2xlbiA9IF9yZWYubGVuZ3RoOyBfaSA8IF9sZW47IF9pKyspIHtcbiAgICAgICAgX3JlZjEgPSBfcmVmW19pXSwgayA9IF9yZWYxWzBdLCB2ID0gX3JlZjFbMV07XG4gICAgICAgIGlmICgodiAhPSBudWxsKSAmJiAodi5tYXRjaCgvXFxTLykpICYmIHYgIT09ICdOVUxMJykge1xuICAgICAgICAgIG9ialtrXSA9IHY7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmo7XG4gICAgfTtcbiAgICBfcmVzdWx0cyA9IFtdO1xuICAgIGZvciAoX2kgPSAwLCBfbGVuID0gYXJyYXkubGVuZ3RoOyBfaSA8IF9sZW47IF9pKyspIHtcbiAgICAgIHJvdyA9IGFycmF5W19pXTtcbiAgICAgIF9yZXN1bHRzLnB1c2gocm93VG9PYmplY3Qocm93KSk7XG4gICAgfVxuICAgIHJldHVybiBfcmVzdWx0cztcbiAgfTtcblxuICBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBlbWl0OiBlbWl0LFxuICAgIGJpbmQ6IGJpbmRcbiAgfTtcblxufSkuY2FsbCh0aGlzKTtcbiIsIihmdW5jdGlvbigpIHtcbiAgdmFyIHV0aWw7XG5cbiAgdXRpbCA9IHJlcXVpcmUoJy4vdXRpbCcpO1xuXG4gIG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oam91cm5hbEVsZW1lbnQsIGFjdGlvbikge1xuICAgIHZhciBhY3Rpb25FbGVtZW50LCBhY3Rpb25UaXRsZSwgY29udHJvbHMsIHBhZ2VFbGVtZW50O1xuICAgIHBhZ2VFbGVtZW50ID0gam91cm5hbEVsZW1lbnQucGFyZW50cygnLnBhZ2U6Zmlyc3QnKTtcbiAgICBhY3Rpb25UaXRsZSA9IGFjdGlvbi50eXBlIHx8ICdzZXBhcmF0b3InO1xuICAgIGlmIChhY3Rpb24uZGF0ZSAhPSBudWxsKSB7XG4gICAgICBhY3Rpb25UaXRsZSArPSBcIiBcIiArICh1dGlsLmZvcm1hdEVsYXBzZWRUaW1lKGFjdGlvbi5kYXRlKSk7XG4gICAgfVxuICAgIGFjdGlvbkVsZW1lbnQgPSAkKFwiPGEgaHJlZj1cXFwiI1xcXCIgLz4gXCIpLmFkZENsYXNzKFwiYWN0aW9uXCIpLmFkZENsYXNzKGFjdGlvbi50eXBlIHx8ICdzZXBhcmF0b3InKS50ZXh0KGFjdGlvbi5zeW1ib2wgfHwgdXRpbC5zeW1ib2xzW2FjdGlvbi50eXBlXSkuYXR0cigndGl0bGUnLCBhY3Rpb25UaXRsZSkuYXR0cignZGF0YS1pZCcsIGFjdGlvbi5pZCB8fCBcIjBcIikuZGF0YSgnYWN0aW9uJywgYWN0aW9uKTtcbiAgICBjb250cm9scyA9IGpvdXJuYWxFbGVtZW50LmNoaWxkcmVuKCcuY29udHJvbC1idXR0b25zJyk7XG4gICAgaWYgKGNvbnRyb2xzLmxlbmd0aCA+IDApIHtcbiAgICAgIGFjdGlvbkVsZW1lbnQuaW5zZXJ0QmVmb3JlKGNvbnRyb2xzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYWN0aW9uRWxlbWVudC5hcHBlbmRUbyhqb3VybmFsRWxlbWVudCk7XG4gICAgfVxuICAgIGlmIChhY3Rpb24udHlwZSA9PT0gJ2ZvcmsnICYmIChhY3Rpb24uc2l0ZSAhPSBudWxsKSkge1xuICAgICAgcmV0dXJuIGFjdGlvbkVsZW1lbnQuY3NzKFwiYmFja2dyb3VuZC1pbWFnZVwiLCBcInVybCgvL1wiICsgYWN0aW9uLnNpdGUgKyBcIi9mYXZpY29uLnBuZylcIikuYXR0cihcImhyZWZcIiwgXCIvL1wiICsgYWN0aW9uLnNpdGUgKyBcIi9cIiArIChwYWdlRWxlbWVudC5hdHRyKCdpZCcpKSArIFwiLmh0bWxcIikuZGF0YShcInNpdGVcIiwgYWN0aW9uLnNpdGUpLmRhdGEoXCJzbHVnXCIsIHBhZ2VFbGVtZW50LmF0dHIoJ2lkJykpO1xuICAgIH1cbiAgfTtcblxufSkuY2FsbCh0aGlzKTtcbiIsIihmdW5jdGlvbigpIHtcbiAgdmFyIGFkZFRvSm91cm5hbCwgbmV3UGFnZSwgcGFnZUZyb21Mb2NhbFN0b3JhZ2UsIHBhZ2VIYW5kbGVyLCBwdXNoVG9Mb2NhbCwgcHVzaFRvU2VydmVyLCByZWN1cnNpdmVHZXQsIHJldmlzaW9uLCBzdGF0ZSwgdXRpbCwgd2lraSwgXztcblxuICBfID0gcmVxdWlyZSgndW5kZXJzY29yZScpO1xuXG4gIHdpa2kgPSByZXF1aXJlKCcuL3dpa2knKTtcblxuICB1dGlsID0gcmVxdWlyZSgnLi91dGlsJyk7XG5cbiAgc3RhdGUgPSByZXF1aXJlKCcuL3N0YXRlJyk7XG5cbiAgcmV2aXNpb24gPSByZXF1aXJlKCcuL3JldmlzaW9uJyk7XG5cbiAgYWRkVG9Kb3VybmFsID0gcmVxdWlyZSgnLi9hZGRUb0pvdXJuYWwnKTtcblxuICBuZXdQYWdlID0gcmVxdWlyZSgnLi9wYWdlJykubmV3UGFnZTtcblxuICBtb2R1bGUuZXhwb3J0cyA9IHBhZ2VIYW5kbGVyID0ge307XG5cbiAgcGFnZUZyb21Mb2NhbFN0b3JhZ2UgPSBmdW5jdGlvbihzbHVnKSB7XG4gICAgdmFyIGpzb247XG4gICAgaWYgKGpzb24gPSBsb2NhbFN0b3JhZ2Vbc2x1Z10pIHtcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKGpzb24pO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdm9pZCAwO1xuICAgIH1cbiAgfTtcblxuICByZWN1cnNpdmVHZXQgPSBmdW5jdGlvbihfYXJnKSB7XG4gICAgdmFyIGxvY2FsQ29udGV4dCwgbG9jYWxQYWdlLCBwYWdlSW5mb3JtYXRpb24sIHJldiwgc2l0ZSwgc2x1ZywgdXJsLCB3aGVuR290dGVuLCB3aGVuTm90R290dGVuO1xuICAgIHBhZ2VJbmZvcm1hdGlvbiA9IF9hcmcucGFnZUluZm9ybWF0aW9uLCB3aGVuR290dGVuID0gX2FyZy53aGVuR290dGVuLCB3aGVuTm90R290dGVuID0gX2FyZy53aGVuTm90R290dGVuLCBsb2NhbENvbnRleHQgPSBfYXJnLmxvY2FsQ29udGV4dDtcbiAgICBzbHVnID0gcGFnZUluZm9ybWF0aW9uLnNsdWcsIHJldiA9IHBhZ2VJbmZvcm1hdGlvbi5yZXYsIHNpdGUgPSBwYWdlSW5mb3JtYXRpb24uc2l0ZTtcbiAgICBpZiAoc2l0ZSkge1xuICAgICAgbG9jYWxDb250ZXh0ID0gW107XG4gICAgfSBlbHNlIHtcbiAgICAgIHNpdGUgPSBsb2NhbENvbnRleHQuc2hpZnQoKTtcbiAgICB9XG4gICAgaWYgKHNpdGUgPT09IHdpbmRvdy5sb2NhdGlvbi5ob3N0KSB7XG4gICAgICBzaXRlID0gJ29yaWdpbic7XG4gICAgfVxuICAgIGlmIChzaXRlID09PSAndmlldycpIHtcbiAgICAgIHNpdGUgPSBudWxsO1xuICAgIH1cbiAgICBpZiAoc2l0ZSAhPSBudWxsKSB7XG4gICAgICBpZiAoc2l0ZSA9PT0gJ2xvY2FsJykge1xuICAgICAgICBpZiAobG9jYWxQYWdlID0gcGFnZUZyb21Mb2NhbFN0b3JhZ2UocGFnZUluZm9ybWF0aW9uLnNsdWcpKSB7XG4gICAgICAgICAgcmV0dXJuIHdoZW5Hb3R0ZW4obmV3UGFnZShsb2NhbFBhZ2UsICdsb2NhbCcpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gd2hlbk5vdEdvdHRlbigpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoc2l0ZSA9PT0gJ29yaWdpbicpIHtcbiAgICAgICAgICB1cmwgPSBcIi9cIiArIHNsdWcgKyBcIi5qc29uXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdXJsID0gXCJodHRwOi8vXCIgKyBzaXRlICsgXCIvXCIgKyBzbHVnICsgXCIuanNvblwiO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHVybCA9IFwiL1wiICsgc2x1ZyArIFwiLmpzb25cIjtcbiAgICB9XG4gICAgcmV0dXJuICQuYWpheCh7XG4gICAgICB0eXBlOiAnR0VUJyxcbiAgICAgIGRhdGFUeXBlOiAnanNvbicsXG4gICAgICB1cmw6IHVybCArIChcIj9yYW5kb209XCIgKyAodXRpbC5yYW5kb21CeXRlcyg0KSkpLFxuICAgICAgc3VjY2VzczogZnVuY3Rpb24ocGFnZSkge1xuICAgICAgICBpZiAocmV2KSB7XG4gICAgICAgICAgcGFnZSA9IHJldmlzaW9uLmNyZWF0ZShyZXYsIHBhZ2UpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB3aGVuR290dGVuKG5ld1BhZ2UocGFnZSwgc2l0ZSkpO1xuICAgICAgfSxcbiAgICAgIGVycm9yOiBmdW5jdGlvbih4aHIsIHR5cGUsIG1zZykge1xuICAgICAgICB2YXIgcmVwb3J0O1xuICAgICAgICBpZiAoKHhoci5zdGF0dXMgIT09IDQwNCkgJiYgKHhoci5zdGF0dXMgIT09IDApKSB7XG4gICAgICAgICAgd2lraS5sb2coJ3BhZ2VIYW5kbGVyLmdldCBlcnJvcicsIHhociwgeGhyLnN0YXR1cywgdHlwZSwgbXNnKTtcbiAgICAgICAgICByZXBvcnQgPSB7XG4gICAgICAgICAgICAndGl0bGUnOiBcIlwiICsgeGhyLnN0YXR1cyArIFwiIFwiICsgbXNnLFxuICAgICAgICAgICAgJ3N0b3J5JzogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgJ3R5cGUnOiAncGFyYWdyYXBoJyxcbiAgICAgICAgICAgICAgICAnaWQnOiAnOTI4NzM5MTg3MjQzJyxcbiAgICAgICAgICAgICAgICAndGV4dCc6IFwiPHByZT5cIiArIHhoci5yZXNwb25zZVRleHRcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH07XG4gICAgICAgICAgcmV0dXJuIHdoZW5Hb3R0ZW4ocmVwb3J0LCAnbG9jYWwnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobG9jYWxDb250ZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICByZXR1cm4gcmVjdXJzaXZlR2V0KHtcbiAgICAgICAgICAgIHBhZ2VJbmZvcm1hdGlvbjogcGFnZUluZm9ybWF0aW9uLFxuICAgICAgICAgICAgd2hlbkdvdHRlbjogd2hlbkdvdHRlbixcbiAgICAgICAgICAgIHdoZW5Ob3RHb3R0ZW46IHdoZW5Ob3RHb3R0ZW4sXG4gICAgICAgICAgICBsb2NhbENvbnRleHQ6IGxvY2FsQ29udGV4dFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiB3aGVuTm90R290dGVuKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcblxuICBwYWdlSGFuZGxlci5nZXQgPSBmdW5jdGlvbihfYXJnKSB7XG4gICAgdmFyIGxvY2FsUGFnZSwgcGFnZUluZm9ybWF0aW9uLCB3aGVuR290dGVuLCB3aGVuTm90R290dGVuO1xuICAgIHdoZW5Hb3R0ZW4gPSBfYXJnLndoZW5Hb3R0ZW4sIHdoZW5Ob3RHb3R0ZW4gPSBfYXJnLndoZW5Ob3RHb3R0ZW4sIHBhZ2VJbmZvcm1hdGlvbiA9IF9hcmcucGFnZUluZm9ybWF0aW9uO1xuICAgIGlmICghcGFnZUluZm9ybWF0aW9uLnNpdGUpIHtcbiAgICAgIGlmIChsb2NhbFBhZ2UgPSBwYWdlRnJvbUxvY2FsU3RvcmFnZShwYWdlSW5mb3JtYXRpb24uc2x1ZykpIHtcbiAgICAgICAgaWYgKHBhZ2VJbmZvcm1hdGlvbi5yZXYpIHtcbiAgICAgICAgICBsb2NhbFBhZ2UgPSByZXZpc2lvbi5jcmVhdGUocGFnZUluZm9ybWF0aW9uLnJldiwgbG9jYWxQYWdlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gd2hlbkdvdHRlbihuZXdQYWdlKGxvY2FsUGFnZSwgJ2xvY2FsJykpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIXBhZ2VIYW5kbGVyLmNvbnRleHQubGVuZ3RoKSB7XG4gICAgICBwYWdlSGFuZGxlci5jb250ZXh0ID0gWyd2aWV3J107XG4gICAgfVxuICAgIHJldHVybiByZWN1cnNpdmVHZXQoe1xuICAgICAgcGFnZUluZm9ybWF0aW9uOiBwYWdlSW5mb3JtYXRpb24sXG4gICAgICB3aGVuR290dGVuOiB3aGVuR290dGVuLFxuICAgICAgd2hlbk5vdEdvdHRlbjogd2hlbk5vdEdvdHRlbixcbiAgICAgIGxvY2FsQ29udGV4dDogXy5jbG9uZShwYWdlSGFuZGxlci5jb250ZXh0KVxuICAgIH0pO1xuICB9O1xuXG4gIHBhZ2VIYW5kbGVyLmNvbnRleHQgPSBbXTtcblxuICBwdXNoVG9Mb2NhbCA9IGZ1bmN0aW9uKHBhZ2VFbGVtZW50LCBwYWdlUHV0SW5mbywgYWN0aW9uKSB7XG4gICAgdmFyIHBhZ2UsIHNpdGU7XG4gICAgaWYgKGFjdGlvbi50eXBlID09PSAnY3JlYXRlJykge1xuICAgICAgcGFnZSA9IHtcbiAgICAgICAgdGl0bGU6IGFjdGlvbi5pdGVtLnRpdGxlLFxuICAgICAgICBzdG9yeTogW10sXG4gICAgICAgIGpvdXJuYWw6IFtdXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBwYWdlID0gcGFnZUZyb21Mb2NhbFN0b3JhZ2UocGFnZVB1dEluZm8uc2x1Zyk7XG4gICAgICBwYWdlIHx8IChwYWdlID0gcGFnZUVsZW1lbnQuZGF0YShcImRhdGFcIikpO1xuICAgICAgaWYgKHBhZ2Uuam91cm5hbCA9PSBudWxsKSB7XG4gICAgICAgIHBhZ2Uuam91cm5hbCA9IFtdO1xuICAgICAgfVxuICAgICAgaWYgKChzaXRlID0gYWN0aW9uWydmb3JrJ10pICE9IG51bGwpIHtcbiAgICAgICAgcGFnZS5qb3VybmFsID0gcGFnZS5qb3VybmFsLmNvbmNhdCh7XG4gICAgICAgICAgJ3R5cGUnOiAnZm9yaycsXG4gICAgICAgICAgJ3NpdGUnOiBzaXRlXG4gICAgICAgIH0pO1xuICAgICAgICBkZWxldGUgYWN0aW9uWydmb3JrJ107XG4gICAgICB9XG4gICAgICBwYWdlLnN0b3J5ID0gJChwYWdlRWxlbWVudCkuZmluZChcIi5pdGVtXCIpLm1hcChmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuICQodGhpcykuZGF0YShcIml0ZW1cIik7XG4gICAgICB9KS5nZXQoKTtcbiAgICB9XG4gICAgcGFnZS5qb3VybmFsID0gcGFnZS5qb3VybmFsLmNvbmNhdChhY3Rpb24pO1xuICAgIGxvY2FsU3RvcmFnZVtwYWdlUHV0SW5mby5zbHVnXSA9IEpTT04uc3RyaW5naWZ5KHBhZ2UpO1xuICAgIHJldHVybiBhZGRUb0pvdXJuYWwocGFnZUVsZW1lbnQuZmluZCgnLmpvdXJuYWwnKSwgYWN0aW9uKTtcbiAgfTtcblxuICBwdXNoVG9TZXJ2ZXIgPSBmdW5jdGlvbihwYWdlRWxlbWVudCwgcGFnZVB1dEluZm8sIGFjdGlvbikge1xuICAgIHJldHVybiAkLmFqYXgoe1xuICAgICAgdHlwZTogJ1BVVCcsXG4gICAgICB1cmw6IFwiL3BhZ2UvXCIgKyBwYWdlUHV0SW5mby5zbHVnICsgXCIvYWN0aW9uXCIsXG4gICAgICBkYXRhOiB7XG4gICAgICAgICdhY3Rpb24nOiBKU09OLnN0cmluZ2lmeShhY3Rpb24pXG4gICAgICB9LFxuICAgICAgc3VjY2VzczogZnVuY3Rpb24oKSB7XG4gICAgICAgIGFkZFRvSm91cm5hbChwYWdlRWxlbWVudC5maW5kKCcuam91cm5hbCcpLCBhY3Rpb24pO1xuICAgICAgICBpZiAoYWN0aW9uLnR5cGUgPT09ICdmb3JrJykge1xuICAgICAgICAgIGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKHBhZ2VFbGVtZW50LmF0dHIoJ2lkJykpO1xuICAgICAgICAgIHJldHVybiBzdGF0ZS5zZXRVcmw7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBlcnJvcjogZnVuY3Rpb24oeGhyLCB0eXBlLCBtc2cpIHtcbiAgICAgICAgcmV0dXJuIHdpa2kubG9nKFwicGFnZUhhbmRsZXIucHV0IGFqYXggZXJyb3IgY2FsbGJhY2tcIiwgdHlwZSwgbXNnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcblxuICBwYWdlSGFuZGxlci5wdXQgPSBmdW5jdGlvbihwYWdlRWxlbWVudCwgYWN0aW9uKSB7XG4gICAgdmFyIGNoZWNrZWRTaXRlLCBmb3JrRnJvbSwgcGFnZVB1dEluZm87XG4gICAgY2hlY2tlZFNpdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBzaXRlO1xuICAgICAgc3dpdGNoIChzaXRlID0gcGFnZUVsZW1lbnQuZGF0YSgnc2l0ZScpKSB7XG4gICAgICAgIGNhc2UgJ29yaWdpbic6XG4gICAgICAgIGNhc2UgJ2xvY2FsJzpcbiAgICAgICAgY2FzZSAndmlldyc6XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIGNhc2UgbG9jYXRpb24uaG9zdDpcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gc2l0ZTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHBhZ2VQdXRJbmZvID0ge1xuICAgICAgc2x1ZzogcGFnZUVsZW1lbnQuYXR0cignaWQnKS5zcGxpdCgnX3JldicpWzBdLFxuICAgICAgcmV2OiBwYWdlRWxlbWVudC5hdHRyKCdpZCcpLnNwbGl0KCdfcmV2JylbMV0sXG4gICAgICBzaXRlOiBjaGVja2VkU2l0ZSgpLFxuICAgICAgbG9jYWw6IHBhZ2VFbGVtZW50Lmhhc0NsYXNzKCdsb2NhbCcpXG4gICAgfTtcbiAgICBmb3JrRnJvbSA9IHBhZ2VQdXRJbmZvLnNpdGU7XG4gICAgd2lraS5sb2coJ3BhZ2VIYW5kbGVyLnB1dCcsIGFjdGlvbiwgcGFnZVB1dEluZm8pO1xuICAgIGlmICh3aWtpLnVzZUxvY2FsU3RvcmFnZSgpKSB7XG4gICAgICBpZiAocGFnZVB1dEluZm8uc2l0ZSAhPSBudWxsKSB7XG4gICAgICAgIHdpa2kubG9nKCdyZW1vdGUgPT4gbG9jYWwnKTtcbiAgICAgIH0gZWxzZSBpZiAoIXBhZ2VQdXRJbmZvLmxvY2FsKSB7XG4gICAgICAgIHdpa2kubG9nKCdvcmlnaW4gPT4gbG9jYWwnKTtcbiAgICAgICAgYWN0aW9uLnNpdGUgPSBmb3JrRnJvbSA9IGxvY2F0aW9uLmhvc3Q7XG4gICAgICB9XG4gICAgfVxuICAgIGFjdGlvbi5kYXRlID0gKG5ldyBEYXRlKCkpLmdldFRpbWUoKTtcbiAgICBpZiAoYWN0aW9uLnNpdGUgPT09ICdvcmlnaW4nKSB7XG4gICAgICBkZWxldGUgYWN0aW9uLnNpdGU7XG4gICAgfVxuICAgIGlmIChmb3JrRnJvbSkge1xuICAgICAgcGFnZUVsZW1lbnQuZmluZCgnaDEgaW1nJykuYXR0cignc3JjJywgJy9mYXZpY29uLnBuZycpO1xuICAgICAgcGFnZUVsZW1lbnQuZmluZCgnaDEgYScpLmF0dHIoJ2hyZWYnLCAnLycpO1xuICAgICAgcGFnZUVsZW1lbnQuZGF0YSgnc2l0ZScsIG51bGwpO1xuICAgICAgcGFnZUVsZW1lbnQucmVtb3ZlQ2xhc3MoJ3JlbW90ZScpO1xuICAgICAgc3RhdGUuc2V0VXJsKCk7XG4gICAgICBpZiAoYWN0aW9uLnR5cGUgIT09ICdmb3JrJykge1xuICAgICAgICBhY3Rpb24uZm9yayA9IGZvcmtGcm9tO1xuICAgICAgICBhZGRUb0pvdXJuYWwocGFnZUVsZW1lbnQuZmluZCgnLmpvdXJuYWwnKSwge1xuICAgICAgICAgIHR5cGU6ICdmb3JrJyxcbiAgICAgICAgICBzaXRlOiBmb3JrRnJvbSxcbiAgICAgICAgICBkYXRlOiBhY3Rpb24uZGF0ZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHdpa2kudXNlTG9jYWxTdG9yYWdlKCkgfHwgcGFnZVB1dEluZm8uc2l0ZSA9PT0gJ2xvY2FsJykge1xuICAgICAgcHVzaFRvTG9jYWwocGFnZUVsZW1lbnQsIHBhZ2VQdXRJbmZvLCBhY3Rpb24pO1xuICAgICAgcmV0dXJuIHBhZ2VFbGVtZW50LmFkZENsYXNzKFwibG9jYWxcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBwdXNoVG9TZXJ2ZXIocGFnZUVsZW1lbnQsIHBhZ2VQdXRJbmZvLCBhY3Rpb24pO1xuICAgIH1cbiAgfTtcblxufSkuY2FsbCh0aGlzKTtcbiIsIihmdW5jdGlvbigpIHtcbiAgdmFyIGFkZFRvSm91cm5hbCwgYnVpbGRQYWdlSGVhZGVyLCBjcmVhdGVGYWN0b3J5LCBlbWl0SGVhZGVyLCBlbWl0VHdpbnMsIGhhbmRsZURyYWdnaW5nLCBpbml0QWRkQnV0dG9uLCBpbml0RHJhZ2dpbmcsIG5laWdoYm9yaG9vZCwgcGFnZUhhbmRsZXIsIHBsdWdpbiwgcmVmcmVzaCwgcmVuZGVyUGFnZUludG9QYWdlRWxlbWVudCwgc3RhdGUsIHV0aWwsIHdpa2ksIF87XG5cbiAgXyA9IHJlcXVpcmUoJ3VuZGVyc2NvcmUnKTtcblxuICB1dGlsID0gcmVxdWlyZSgnLi91dGlsJyk7XG5cbiAgcGFnZUhhbmRsZXIgPSByZXF1aXJlKCcuL3BhZ2VIYW5kbGVyJyk7XG5cbiAgcGx1Z2luID0gcmVxdWlyZSgnLi9wbHVnaW4nKTtcblxuICBzdGF0ZSA9IHJlcXVpcmUoJy4vc3RhdGUnKTtcblxuICBuZWlnaGJvcmhvb2QgPSByZXF1aXJlKCcuL25laWdoYm9yaG9vZCcpO1xuXG4gIGFkZFRvSm91cm5hbCA9IHJlcXVpcmUoJy4vYWRkVG9Kb3VybmFsJyk7XG5cbiAgd2lraSA9IHJlcXVpcmUoJy4vd2lraScpO1xuXG4gIGhhbmRsZURyYWdnaW5nID0gZnVuY3Rpb24oZXZ0LCB1aSkge1xuICAgIHZhciBhY3Rpb24sIGJlZm9yZSwgYmVmb3JlRWxlbWVudCwgZGVzdGluYXRpb25QYWdlRWxlbWVudCwgZXF1YWxzLCBpdGVtLCBpdGVtRWxlbWVudCwgbW92ZUZyb21QYWdlLCBtb3ZlVG9QYWdlLCBtb3ZlV2l0aGluUGFnZSwgb3JkZXIsIHNvdXJjZVBhZ2VFbGVtZW50LCBzb3VyY2VTaXRlLCB0aGlzUGFnZUVsZW1lbnQ7XG4gICAgaXRlbUVsZW1lbnQgPSB1aS5pdGVtO1xuICAgIGl0ZW0gPSB3aWtpLmdldEl0ZW0oaXRlbUVsZW1lbnQpO1xuICAgIHRoaXNQYWdlRWxlbWVudCA9ICQodGhpcykucGFyZW50cygnLnBhZ2U6Zmlyc3QnKTtcbiAgICBzb3VyY2VQYWdlRWxlbWVudCA9IGl0ZW1FbGVtZW50LmRhdGEoJ3BhZ2VFbGVtZW50Jyk7XG4gICAgc291cmNlU2l0ZSA9IHNvdXJjZVBhZ2VFbGVtZW50LmRhdGEoJ3NpdGUnKTtcbiAgICBkZXN0aW5hdGlvblBhZ2VFbGVtZW50ID0gaXRlbUVsZW1lbnQucGFyZW50cygnLnBhZ2U6Zmlyc3QnKTtcbiAgICBlcXVhbHMgPSBmdW5jdGlvbihhLCBiKSB7XG4gICAgICByZXR1cm4gYSAmJiBiICYmIGEuZ2V0KDApID09PSBiLmdldCgwKTtcbiAgICB9O1xuICAgIG1vdmVXaXRoaW5QYWdlID0gIXNvdXJjZVBhZ2VFbGVtZW50IHx8IGVxdWFscyhzb3VyY2VQYWdlRWxlbWVudCwgZGVzdGluYXRpb25QYWdlRWxlbWVudCk7XG4gICAgbW92ZUZyb21QYWdlID0gIW1vdmVXaXRoaW5QYWdlICYmIGVxdWFscyh0aGlzUGFnZUVsZW1lbnQsIHNvdXJjZVBhZ2VFbGVtZW50KTtcbiAgICBtb3ZlVG9QYWdlID0gIW1vdmVXaXRoaW5QYWdlICYmIGVxdWFscyh0aGlzUGFnZUVsZW1lbnQsIGRlc3RpbmF0aW9uUGFnZUVsZW1lbnQpO1xuICAgIGlmIChtb3ZlRnJvbVBhZ2UpIHtcbiAgICAgIGlmIChzb3VyY2VQYWdlRWxlbWVudC5oYXNDbGFzcygnZ2hvc3QnKSB8fCBzb3VyY2VQYWdlRWxlbWVudC5hdHRyKCdpZCcpID09PSBkZXN0aW5hdGlvblBhZ2VFbGVtZW50LmF0dHIoJ2lkJykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICBhY3Rpb24gPSBtb3ZlV2l0aGluUGFnZSA/IChvcmRlciA9ICQodGhpcykuY2hpbGRyZW4oKS5tYXAoZnVuY3Rpb24oXywgdmFsdWUpIHtcbiAgICAgIHJldHVybiAkKHZhbHVlKS5hdHRyKCdkYXRhLWlkJyk7XG4gICAgfSkuZ2V0KCksIHtcbiAgICAgIHR5cGU6ICdtb3ZlJyxcbiAgICAgIG9yZGVyOiBvcmRlclxuICAgIH0pIDogbW92ZUZyb21QYWdlID8gKHdpa2kubG9nKCdkcmFnIGZyb20nLCBzb3VyY2VQYWdlRWxlbWVudC5maW5kKCdoMScpLnRleHQoKSksIHtcbiAgICAgIHR5cGU6ICdyZW1vdmUnXG4gICAgfSkgOiBtb3ZlVG9QYWdlID8gKGl0ZW1FbGVtZW50LmRhdGEoJ3BhZ2VFbGVtZW50JywgdGhpc1BhZ2VFbGVtZW50KSwgYmVmb3JlRWxlbWVudCA9IGl0ZW1FbGVtZW50LnByZXYoJy5pdGVtJyksIGJlZm9yZSA9IHdpa2kuZ2V0SXRlbShiZWZvcmVFbGVtZW50KSwge1xuICAgICAgdHlwZTogJ2FkZCcsXG4gICAgICBpdGVtOiBpdGVtLFxuICAgICAgYWZ0ZXI6IGJlZm9yZSAhPSBudWxsID8gYmVmb3JlLmlkIDogdm9pZCAwXG4gICAgfSkgOiB2b2lkIDA7XG4gICAgYWN0aW9uLmlkID0gaXRlbS5pZDtcbiAgICByZXR1cm4gcGFnZUhhbmRsZXIucHV0KHRoaXNQYWdlRWxlbWVudCwgYWN0aW9uKTtcbiAgfTtcblxuICBpbml0RHJhZ2dpbmcgPSBmdW5jdGlvbigkcGFnZSkge1xuICAgIHZhciAkc3Rvcnk7XG4gICAgJHN0b3J5ID0gJHBhZ2UuZmluZCgnLnN0b3J5Jyk7XG4gICAgcmV0dXJuICRzdG9yeS5zb3J0YWJsZSh7XG4gICAgICBjb25uZWN0V2l0aDogJy5wYWdlIC5zdG9yeSdcbiAgICB9KS5vbihcInNvcnR1cGRhdGVcIiwgaGFuZGxlRHJhZ2dpbmcpO1xuICB9O1xuXG4gIGluaXRBZGRCdXR0b24gPSBmdW5jdGlvbigkcGFnZSkge1xuICAgIHJldHVybiAkcGFnZS5maW5kKFwiLmFkZC1mYWN0b3J5XCIpLmxpdmUoXCJjbGlja1wiLCBmdW5jdGlvbihldnQpIHtcbiAgICAgIGlmICgkcGFnZS5oYXNDbGFzcygnZ2hvc3QnKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBldnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIHJldHVybiBjcmVhdGVGYWN0b3J5KCRwYWdlKTtcbiAgICB9KTtcbiAgfTtcblxuICBjcmVhdGVGYWN0b3J5ID0gZnVuY3Rpb24oJHBhZ2UpIHtcbiAgICB2YXIgYmVmb3JlLCBiZWZvcmVFbGVtZW50LCBpdGVtLCBpdGVtRWxlbWVudDtcbiAgICBpdGVtID0ge1xuICAgICAgdHlwZTogXCJmYWN0b3J5XCIsXG4gICAgICBpZDogdXRpbC5yYW5kb21CeXRlcyg4KVxuICAgIH07XG4gICAgaXRlbUVsZW1lbnQgPSAkKFwiPGRpdiAvPlwiLCB7XG4gICAgICBcImNsYXNzXCI6IFwiaXRlbSBmYWN0b3J5XCJcbiAgICB9KS5kYXRhKCdpdGVtJywgaXRlbSkuYXR0cignZGF0YS1pZCcsIGl0ZW0uaWQpO1xuICAgIGl0ZW1FbGVtZW50LmRhdGEoJ3BhZ2VFbGVtZW50JywgJHBhZ2UpO1xuICAgICRwYWdlLmZpbmQoXCIuc3RvcnlcIikuYXBwZW5kKGl0ZW1FbGVtZW50KTtcbiAgICBwbHVnaW5bXCJkb1wiXShpdGVtRWxlbWVudCwgaXRlbSk7XG4gICAgYmVmb3JlRWxlbWVudCA9IGl0ZW1FbGVtZW50LnByZXYoJy5pdGVtJyk7XG4gICAgYmVmb3JlID0gd2lraS5nZXRJdGVtKGJlZm9yZUVsZW1lbnQpO1xuICAgIHJldHVybiBwYWdlSGFuZGxlci5wdXQoJHBhZ2UsIHtcbiAgICAgIGl0ZW06IGl0ZW0sXG4gICAgICBpZDogaXRlbS5pZCxcbiAgICAgIHR5cGU6IFwiYWRkXCIsXG4gICAgICBhZnRlcjogYmVmb3JlICE9IG51bGwgPyBiZWZvcmUuaWQgOiB2b2lkIDBcbiAgICB9KTtcbiAgfTtcblxuICBidWlsZFBhZ2VIZWFkZXIgPSBmdW5jdGlvbihfYXJnKSB7XG4gICAgdmFyIGZhdmljb25fc3JjLCBoZWFkZXJfaHJlZiwgcGFnZSwgdG9vbHRpcDtcbiAgICBwYWdlID0gX2FyZy5wYWdlLCB0b29sdGlwID0gX2FyZy50b29sdGlwLCBoZWFkZXJfaHJlZiA9IF9hcmcuaGVhZGVyX2hyZWYsIGZhdmljb25fc3JjID0gX2FyZy5mYXZpY29uX3NyYztcbiAgICBpZiAocGFnZS5wbHVnaW4pIHtcbiAgICAgIHRvb2x0aXAgKz0gXCJcXG5cIiArIHBhZ2UucGx1Z2luICsgXCIgcGx1Z2luXCI7XG4gICAgfVxuICAgIHJldHVybiBcIjxoMSB0aXRsZT1cXFwiXCIgKyB0b29sdGlwICsgXCJcXFwiPjxhIGhyZWY9XFxcIlwiICsgaGVhZGVyX2hyZWYgKyBcIlxcXCI+PGltZyBzcmM9XFxcIlwiICsgZmF2aWNvbl9zcmMgKyBcIlxcXCIgaGVpZ2h0PVxcXCIzMnB4XFxcIiBjbGFzcz1cXFwiZmF2aWNvblxcXCI+PC9hPiBcIiArIHBhZ2UudGl0bGUgKyBcIjwvaDE+XCI7XG4gIH07XG5cbiAgZW1pdEhlYWRlciA9IGZ1bmN0aW9uKCRoZWFkZXIsICRwYWdlLCBwYWdlT2JqZWN0KSB7XG4gICAgdmFyIGRhdGUsIGhlYWRlciwgaXNSZW1vdGVQYWdlLCBwYWdlLCBwYWdlSGVhZGVyLCByZXYsIHZpZXdIZXJlO1xuICAgIHBhZ2UgPSBwYWdlT2JqZWN0LmdldFJhd1BhZ2UoKTtcbiAgICBpc1JlbW90ZVBhZ2UgPSBwYWdlT2JqZWN0LmlzUmVtb3RlKCk7XG4gICAgaGVhZGVyID0gJyc7XG4gICAgdmlld0hlcmUgPSB3aWtpLmFzU2x1ZyhwYWdlLnRpdGxlKSA9PT0gJ3dlbGNvbWUtdmlzaXRvcnMnID8gXCJcIiA6IFwiL3ZpZXcvXCIgKyAocGFnZU9iamVjdC5nZXRTbHVnKCkpO1xuICAgIHBhZ2VIZWFkZXIgPSBpc1JlbW90ZVBhZ2UgPyBidWlsZFBhZ2VIZWFkZXIoe1xuICAgICAgdG9vbHRpcDogcGFnZU9iamVjdC5nZXRSZW1vdGVTaXRlKCksXG4gICAgICBoZWFkZXJfaHJlZjogXCIvL1wiICsgKHBhZ2VPYmplY3QuZ2V0UmVtb3RlU2l0ZSgpKSArIFwiL3ZpZXcvd2VsY29tZS12aXNpdG9yc1wiICsgdmlld0hlcmUsXG4gICAgICBmYXZpY29uX3NyYzogXCJodHRwOi8vXCIgKyAocGFnZU9iamVjdC5nZXRSZW1vdGVTaXRlKCkpICsgXCIvZmF2aWNvbi5wbmdcIixcbiAgICAgIHBhZ2U6IHBhZ2VcbiAgICB9KSA6IGJ1aWxkUGFnZUhlYWRlcih7XG4gICAgICB0b29sdGlwOiBsb2NhdGlvbi5ob3N0LFxuICAgICAgaGVhZGVyX2hyZWY6IFwiL3ZpZXcvd2VsY29tZS12aXNpdG9yc1wiICsgdmlld0hlcmUsXG4gICAgICBmYXZpY29uX3NyYzogXCIvZmF2aWNvbi5wbmdcIixcbiAgICAgIHBhZ2U6IHBhZ2VcbiAgICB9KTtcbiAgICAkaGVhZGVyLmFwcGVuZChwYWdlSGVhZGVyKTtcbiAgICBpZiAoIWlzUmVtb3RlUGFnZSkge1xuICAgICAgJCgnaW1nLmZhdmljb24nLCAkcGFnZSkuZXJyb3IoZnVuY3Rpb24oZSkge1xuICAgICAgICByZXR1cm4gcGx1Z2luLmdldCgnZmF2aWNvbicsIGZ1bmN0aW9uKGZhdmljb24pIHtcbiAgICAgICAgICByZXR1cm4gZmF2aWNvbi5jcmVhdGUoKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgaWYgKCRwYWdlLmF0dHIoJ2lkJykubWF0Y2goL19yZXYvKSkge1xuICAgICAgcmV2ID0gcGFnZS5qb3VybmFsLmxlbmd0aCAtIDE7XG4gICAgICBkYXRlID0gcGFnZS5qb3VybmFsW3Jldl0uZGF0ZTtcbiAgICAgICRwYWdlLmFkZENsYXNzKCdnaG9zdCcpLmRhdGEoJ3JldicsIHJldik7XG4gICAgICByZXR1cm4gJGhlYWRlci5hcHBlbmQoJChcIjxoMiBjbGFzcz1cXFwicmV2aXNpb25cXFwiPlxcbiAgPHNwYW4+XFxuICAgIFwiICsgKGRhdGUgIT0gbnVsbCA/IHV0aWwuZm9ybWF0RGF0ZShkYXRlKSA6IFwiUmV2aXNpb24gXCIgKyByZXYpICsgXCJcXG4gIDwvc3Bhbj5cXG48L2gyPlwiKSk7XG4gICAgfVxuICB9O1xuXG4gIGVtaXRUd2lucyA9IHdpa2kuZW1pdFR3aW5zID0gZnVuY3Rpb24oJHBhZ2UpIHtcbiAgICB2YXIgYWN0aW9ucywgYmluLCBiaW5zLCBmbGFncywgaSwgaW5mbywgaXRlbSwgbGVnZW5kLCBwYWdlLCByZW1vdGVTaXRlLCBzaXRlLCBzbHVnLCB0d2lucywgdmlld2luZywgX2ksIF9sZW4sIF9yZWYsIF9yZWYxLCBfcmVmMiwgX3JlZjM7XG4gICAgcGFnZSA9ICRwYWdlLmRhdGEoJ2RhdGEnKTtcbiAgICBzaXRlID0gJHBhZ2UuZGF0YSgnc2l0ZScpIHx8IHdpbmRvdy5sb2NhdGlvbi5ob3N0O1xuICAgIGlmIChzaXRlID09PSAndmlldycgfHwgc2l0ZSA9PT0gJ29yaWdpbicpIHtcbiAgICAgIHNpdGUgPSB3aW5kb3cubG9jYXRpb24uaG9zdDtcbiAgICB9XG4gICAgc2x1ZyA9IHdpa2kuYXNTbHVnKHBhZ2UudGl0bGUpO1xuICAgIGlmICgoKGFjdGlvbnMgPSAoX3JlZiA9IHBhZ2Uuam91cm5hbCkgIT0gbnVsbCA/IF9yZWYubGVuZ3RoIDogdm9pZCAwKSAhPSBudWxsKSAmJiAoKHZpZXdpbmcgPSAoX3JlZjEgPSBwYWdlLmpvdXJuYWxbYWN0aW9ucyAtIDFdKSAhPSBudWxsID8gX3JlZjEuZGF0ZSA6IHZvaWQgMCkgIT0gbnVsbCkpIHtcbiAgICAgIHZpZXdpbmcgPSBNYXRoLmZsb29yKHZpZXdpbmcgLyAxMDAwKSAqIDEwMDA7XG4gICAgICBiaW5zID0ge1xuICAgICAgICBuZXdlcjogW10sXG4gICAgICAgIHNhbWU6IFtdLFxuICAgICAgICBvbGRlcjogW11cbiAgICAgIH07XG4gICAgICBfcmVmMiA9IHdpa2kubmVpZ2hib3Job29kO1xuICAgICAgZm9yIChyZW1vdGVTaXRlIGluIF9yZWYyKSB7XG4gICAgICAgIGluZm8gPSBfcmVmMltyZW1vdGVTaXRlXTtcbiAgICAgICAgaWYgKHJlbW90ZVNpdGUgIT09IHNpdGUgJiYgKGluZm8uc2l0ZW1hcCAhPSBudWxsKSkge1xuICAgICAgICAgIF9yZWYzID0gaW5mby5zaXRlbWFwO1xuICAgICAgICAgIGZvciAoX2kgPSAwLCBfbGVuID0gX3JlZjMubGVuZ3RoOyBfaSA8IF9sZW47IF9pKyspIHtcbiAgICAgICAgICAgIGl0ZW0gPSBfcmVmM1tfaV07XG4gICAgICAgICAgICBpZiAoaXRlbS5zbHVnID09PSBzbHVnKSB7XG4gICAgICAgICAgICAgIGJpbiA9IGl0ZW0uZGF0ZSA+IHZpZXdpbmcgPyBiaW5zLm5ld2VyIDogaXRlbS5kYXRlIDwgdmlld2luZyA/IGJpbnMub2xkZXIgOiBiaW5zLnNhbWU7XG4gICAgICAgICAgICAgIGJpbi5wdXNoKHtcbiAgICAgICAgICAgICAgICByZW1vdGVTaXRlOiByZW1vdGVTaXRlLFxuICAgICAgICAgICAgICAgIGl0ZW06IGl0ZW1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0d2lucyA9IFtdO1xuICAgICAgZm9yIChsZWdlbmQgaW4gYmlucykge1xuICAgICAgICBiaW4gPSBiaW5zW2xlZ2VuZF07XG4gICAgICAgIGlmICghYmluLmxlbmd0aCkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGJpbi5zb3J0KGZ1bmN0aW9uKGEsIGIpIHtcbiAgICAgICAgICByZXR1cm4gYS5pdGVtLmRhdGUgPCBiLml0ZW0uZGF0ZTtcbiAgICAgICAgfSk7XG4gICAgICAgIGZsYWdzID0gKGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHZhciBfaiwgX2xlbjEsIF9yZWY0LCBfcmVzdWx0cztcbiAgICAgICAgICBfcmVzdWx0cyA9IFtdO1xuICAgICAgICAgIGZvciAoaSA9IF9qID0gMCwgX2xlbjEgPSBiaW4ubGVuZ3RoOyBfaiA8IF9sZW4xOyBpID0gKytfaikge1xuICAgICAgICAgICAgX3JlZjQgPSBiaW5baV0sIHJlbW90ZVNpdGUgPSBfcmVmNC5yZW1vdGVTaXRlLCBpdGVtID0gX3JlZjQuaXRlbTtcbiAgICAgICAgICAgIGlmIChpID49IDgpIHtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfcmVzdWx0cy5wdXNoKFwiPGltZyBjbGFzcz1cXFwicmVtb3RlXFxcIlxcbnNyYz1cXFwiaHR0cDovL1wiICsgcmVtb3RlU2l0ZSArIFwiL2Zhdmljb24ucG5nXFxcIlxcbmRhdGEtc2x1Zz1cXFwiXCIgKyBzbHVnICsgXCJcXFwiXFxuZGF0YS1zaXRlPVxcXCJcIiArIHJlbW90ZVNpdGUgKyBcIlxcXCJcXG50aXRsZT1cXFwiXCIgKyByZW1vdGVTaXRlICsgXCJcXFwiPlwiKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIF9yZXN1bHRzO1xuICAgICAgICB9KSgpO1xuICAgICAgICB0d2lucy5wdXNoKFwiXCIgKyAoZmxhZ3Muam9pbignJm5ic3A7JykpICsgXCIgXCIgKyBsZWdlbmQpO1xuICAgICAgfVxuICAgICAgaWYgKHR3aW5zKSB7XG4gICAgICAgIHJldHVybiAkcGFnZS5maW5kKCcudHdpbnMnKS5odG1sKFwiPHA+XCIgKyAodHdpbnMuam9pbihcIiwgXCIpKSArIFwiPC9wPlwiKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgcmVuZGVyUGFnZUludG9QYWdlRWxlbWVudCA9IGZ1bmN0aW9uKHBhZ2VPYmplY3QsICRwYWdlKSB7XG4gICAgdmFyICRmb290ZXIsICRoZWFkZXIsICRqb3VybmFsLCAkc3RvcnksICR0d2lucywgaG9zdCwgc2x1ZywgX3JlZjtcbiAgICAkcGFnZS5kYXRhKFwiZGF0YVwiLCBwYWdlT2JqZWN0LmdldFJhd1BhZ2UoKSk7XG4gICAgaWYgKHBhZ2VPYmplY3QuaXNSZW1vdGUoKSkge1xuICAgICAgJHBhZ2UuZGF0YShcInNpdGVcIiwgcGFnZU9iamVjdC5nZXRSZW1vdGVTaXRlKCkpO1xuICAgIH1cbiAgICBzbHVnID0gJHBhZ2UuYXR0cignaWQnKTtcbiAgICB3aWtpLnJlc29sdXRpb25Db250ZXh0ID0gcGFnZU9iamVjdC5nZXRDb250ZXh0KCk7XG4gICAgJHBhZ2UuZW1wdHkoKTtcbiAgICBfcmVmID0gWyd0d2lucycsICdoZWFkZXInLCAnc3RvcnknLCAnam91cm5hbCcsICdmb290ZXInXS5tYXAoZnVuY3Rpb24oY2xhc3NOYW1lKSB7XG4gICAgICByZXR1cm4gJChcIjxkaXYgLz5cIikuYWRkQ2xhc3MoY2xhc3NOYW1lKS5hcHBlbmRUbygkcGFnZSk7XG4gICAgfSksICR0d2lucyA9IF9yZWZbMF0sICRoZWFkZXIgPSBfcmVmWzFdLCAkc3RvcnkgPSBfcmVmWzJdLCAkam91cm5hbCA9IF9yZWZbM10sICRmb290ZXIgPSBfcmVmWzRdO1xuICAgIGVtaXRIZWFkZXIoJGhlYWRlciwgJHBhZ2UsIHBhZ2VPYmplY3QpO1xuICAgIHBhZ2VPYmplY3Quc2VxSXRlbXMoZnVuY3Rpb24oaXRlbSwgZG9uZSkge1xuICAgICAgdmFyICRpdGVtO1xuICAgICAgaWYgKChpdGVtICE9IG51bGwgPyBpdGVtLnR5cGUgOiB2b2lkIDApICYmIChpdGVtICE9IG51bGwgPyBpdGVtLmlkIDogdm9pZCAwKSkge1xuICAgICAgICAkaXRlbSA9ICQoXCI8ZGl2IGNsYXNzPVxcXCJpdGVtIFwiICsgaXRlbS50eXBlICsgXCJcXFwiIGRhdGEtaWQ9XFxcIlwiICsgaXRlbS5pZCArIFwiXFxcIj5cIik7XG4gICAgICAgICRzdG9yeS5hcHBlbmQoJGl0ZW0pO1xuICAgICAgICByZXR1cm4gcGx1Z2luW1wiZG9cIl0oJGl0ZW0sIGl0ZW0sIGRvbmUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgJHN0b3J5LmFwcGVuZCgkKFwiPGRpdj48cCBjbGFzcz1cXFwiZXJyb3JcXFwiPkNhbid0IG1ha2Ugc2Vuc2Ugb2Ygc3RvcnlbXCIgKyBpICsgXCJdPC9wPjwvZGl2PlwiKSk7XG4gICAgICAgIHJldHVybiBkb25lKCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcGFnZU9iamVjdC5zZXFBY3Rpb25zKGZ1bmN0aW9uKGVhY2gsIGRvbmUpIHtcbiAgICAgIGlmIChlYWNoLnNlcGFyYXRvcikge1xuICAgICAgICBhZGRUb0pvdXJuYWwoJGpvdXJuYWwsIGVhY2guc2VwYXJhdG9yKTtcbiAgICAgIH1cbiAgICAgIGFkZFRvSm91cm5hbCgkam91cm5hbCwgZWFjaC5hY3Rpb24pO1xuICAgICAgcmV0dXJuIGRvbmUoKTtcbiAgICB9KTtcbiAgICBlbWl0VHdpbnMoJHBhZ2UpO1xuICAgICRqb3VybmFsLmFwcGVuZChcIjxkaXYgY2xhc3M9XFxcImNvbnRyb2wtYnV0dG9uc1xcXCI+XFxuICA8YSBocmVmPVxcXCIjXFxcIiBjbGFzcz1cXFwiYnV0dG9uIGZvcmstcGFnZVxcXCIgdGl0bGU9XFxcImZvcmsgdGhpcyBwYWdlXFxcIj5cIiArIHV0aWwuc3ltYm9sc1snZm9yayddICsgXCI8L2E+XFxuICA8YSBocmVmPVxcXCIjXFxcIiBjbGFzcz1cXFwiYnV0dG9uIGFkZC1mYWN0b3J5XFxcIiB0aXRsZT1cXFwiYWRkIHBhcmFncmFwaFxcXCI+XCIgKyB1dGlsLnN5bWJvbHNbJ2FkZCddICsgXCI8L2E+XFxuPC9kaXY+XCIpO1xuICAgIGhvc3QgPSBwYWdlT2JqZWN0LmdldFJlbW90ZVNpdGUoKSB8fCBsb2NhdGlvbi5ob3N0O1xuICAgIHJldHVybiAkZm9vdGVyLmFwcGVuZChcIjxhIGlkPVxcXCJsaWNlbnNlXFxcIiBocmVmPVxcXCJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8zLjAvXFxcIj5DQyBCWS1TQSAzLjA8L2E+IC5cXG48YSBjbGFzcz1cXFwic2hvdy1wYWdlLXNvdXJjZVxcXCIgaHJlZj1cXFwiL1wiICsgc2x1ZyArIFwiLmpzb24/cmFuZG9tPVwiICsgKHV0aWwucmFuZG9tQnl0ZXMoNCkpICsgXCJcXFwiIHRpdGxlPVxcXCJzb3VyY2VcXFwiPkpTT048L2E+IC5cXG48YSBocmVmPSBcXFwiLy9cIiArIGhvc3QgKyBcIi9cIiArIHNsdWcgKyBcIi5odG1sXFxcIj5cIiArIGhvc3QgKyBcIjwvYT5cIik7XG4gIH07XG5cbiAgd2lraS5idWlsZFBhZ2UgPSBmdW5jdGlvbihwYWdlT2JqZWN0LCAkcGFnZSkge1xuICAgIGlmIChwYWdlT2JqZWN0LmlzTG9jYWwoKSkge1xuICAgICAgJHBhZ2UuYWRkQ2xhc3MoJ2xvY2FsJyk7XG4gICAgfVxuICAgIGlmIChwYWdlT2JqZWN0LmlzUmVtb3RlKCkpIHtcbiAgICAgICRwYWdlLmFkZENsYXNzKCdyZW1vdGUnKTtcbiAgICB9XG4gICAgaWYgKHBhZ2VPYmplY3QuaXNQbHVnaW4oKSkge1xuICAgICAgJHBhZ2UuYWRkQ2xhc3MoJ3BsdWdpbicpO1xuICAgIH1cbiAgICByZW5kZXJQYWdlSW50b1BhZ2VFbGVtZW50KHBhZ2VPYmplY3QsICRwYWdlKTtcbiAgICBzdGF0ZS5zZXRVcmwoKTtcbiAgICBpbml0RHJhZ2dpbmcoJHBhZ2UpO1xuICAgIGluaXRBZGRCdXR0b24oJHBhZ2UpO1xuICAgIHJldHVybiAkcGFnZTtcbiAgfTtcblxuICBtb2R1bGUuZXhwb3J0cyA9IHJlZnJlc2ggPSB3aWtpLnJlZnJlc2ggPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgJHBhZ2UsIGNyZWF0ZUdob3N0UGFnZSwgZW1wdHlQYWdlLCBwYWdlSW5mb3JtYXRpb24sIHJldiwgc2x1Zywgd2hlbkdvdHRlbiwgX3JlZjtcbiAgICAkcGFnZSA9ICQodGhpcyk7XG4gICAgX3JlZiA9ICRwYWdlLmF0dHIoJ2lkJykuc3BsaXQoJ19yZXYnKSwgc2x1ZyA9IF9yZWZbMF0sIHJldiA9IF9yZWZbMV07XG4gICAgcGFnZUluZm9ybWF0aW9uID0ge1xuICAgICAgc2x1Zzogc2x1ZyxcbiAgICAgIHJldjogcmV2LFxuICAgICAgc2l0ZTogJHBhZ2UuZGF0YSgnc2l0ZScpXG4gICAgfTtcbiAgICBlbXB0eVBhZ2UgPSByZXF1aXJlKCcuL3BhZ2UnKS5lbXB0eVBhZ2U7XG4gICAgY3JlYXRlR2hvc3RQYWdlID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgaGl0LCBoaXRzLCBpbmZvLCBwYWdlT2JqZWN0LCByZXN1bHQsIHNpdGUsIHRpdGxlLCBfaSwgX2xlbiwgX3JlZjE7XG4gICAgICB0aXRsZSA9ICQoXCJhW2hyZWY9XFxcIi9cIiArIHNsdWcgKyBcIi5odG1sXFxcIl06bGFzdFwiKS50ZXh0KCkgfHwgc2x1ZztcbiAgICAgIHBhZ2VPYmplY3QgPSBlbXB0eVBhZ2UoKTtcbiAgICAgIHBhZ2VPYmplY3Quc2V0VGl0bGUodGl0bGUpO1xuICAgICAgaGl0cyA9IFtdO1xuICAgICAgX3JlZjEgPSB3aWtpLm5laWdoYm9yaG9vZDtcbiAgICAgIGZvciAoc2l0ZSBpbiBfcmVmMSkge1xuICAgICAgICBpbmZvID0gX3JlZjFbc2l0ZV07XG4gICAgICAgIGlmIChpbmZvLnNpdGVtYXAgIT0gbnVsbCkge1xuICAgICAgICAgIHJlc3VsdCA9IF8uZmluZChpbmZvLnNpdGVtYXAsIGZ1bmN0aW9uKGVhY2gpIHtcbiAgICAgICAgICAgIHJldHVybiBlYWNoLnNsdWcgPT09IHNsdWc7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHJlc3VsdCAhPSBudWxsKSB7XG4gICAgICAgICAgICBoaXRzLnB1c2goe1xuICAgICAgICAgICAgICBcInR5cGVcIjogXCJyZWZlcmVuY2VcIixcbiAgICAgICAgICAgICAgXCJzaXRlXCI6IHNpdGUsXG4gICAgICAgICAgICAgIFwic2x1Z1wiOiBzbHVnLFxuICAgICAgICAgICAgICBcInRpdGxlXCI6IHJlc3VsdC50aXRsZSB8fCBzbHVnLFxuICAgICAgICAgICAgICBcInRleHRcIjogcmVzdWx0LnN5bm9wc2lzIHx8ICcnXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChoaXRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcGFnZU9iamVjdC5hZGRJdGVtKHtcbiAgICAgICAgICAndHlwZSc6ICdmdXR1cmUnLFxuICAgICAgICAgICd0ZXh0JzogJ1dlIGNvdWxkIG5vdCBmaW5kIHRoaXMgcGFnZSBpbiB0aGUgZXhwZWN0ZWQgY29udGV4dC4nLFxuICAgICAgICAgICd0aXRsZSc6IHRpdGxlXG4gICAgICAgIH0pO1xuICAgICAgICBwYWdlT2JqZWN0LmFkZEl0ZW0oe1xuICAgICAgICAgICd0eXBlJzogJ3BhcmFncmFwaCcsXG4gICAgICAgICAgJ3RleHQnOiBcIldlIGRpZCBmaW5kIHRoZSBwYWdlIGluIHlvdXIgY3VycmVudCBuZWlnaGJvcmhvb2QuXCJcbiAgICAgICAgfSk7XG4gICAgICAgIGZvciAoX2kgPSAwLCBfbGVuID0gaGl0cy5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgICAgIGhpdCA9IGhpdHNbX2ldO1xuICAgICAgICAgIHBhZ2VPYmplY3QuYWRkSXRlbShoaXQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwYWdlT2JqZWN0LmFkZEl0ZW0oe1xuICAgICAgICAgICd0eXBlJzogJ2Z1dHVyZScsXG4gICAgICAgICAgJ3RleHQnOiAnV2UgY291bGQgbm90IGZpbmQgdGhpcyBwYWdlLicsXG4gICAgICAgICAgJ3RpdGxlJzogdGl0bGVcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gd2lraS5idWlsZFBhZ2UocGFnZU9iamVjdCwgJHBhZ2UpLmFkZENsYXNzKCdnaG9zdCcpO1xuICAgIH07XG4gICAgd2hlbkdvdHRlbiA9IGZ1bmN0aW9uKHBhZ2VPYmplY3QpIHtcbiAgICAgIHZhciBzaXRlLCBfaSwgX2xlbiwgX3JlZjEsIF9yZXN1bHRzO1xuICAgICAgd2lraS5idWlsZFBhZ2UocGFnZU9iamVjdCwgJHBhZ2UpO1xuICAgICAgX3JlZjEgPSBwYWdlT2JqZWN0LmdldE5laWdoYm9ycyhsb2NhdGlvbi5ob3N0KTtcbiAgICAgIF9yZXN1bHRzID0gW107XG4gICAgICBmb3IgKF9pID0gMCwgX2xlbiA9IF9yZWYxLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICAgIHNpdGUgPSBfcmVmMVtfaV07XG4gICAgICAgIF9yZXN1bHRzLnB1c2gobmVpZ2hib3Job29kLnJlZ2lzdGVyTmVpZ2hib3Ioc2l0ZSkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIF9yZXN1bHRzO1xuICAgIH07XG4gICAgcmV0dXJuIHBhZ2VIYW5kbGVyLmdldCh7XG4gICAgICB3aGVuR290dGVuOiB3aGVuR290dGVuLFxuICAgICAgd2hlbk5vdEdvdHRlbjogY3JlYXRlR2hvc3RQYWdlLFxuICAgICAgcGFnZUluZm9ybWF0aW9uOiBwYWdlSW5mb3JtYXRpb25cbiAgICB9KTtcbiAgfTtcblxufSkuY2FsbCh0aGlzKTtcbiIsIihmdW5jdGlvbigpIHtcbiAgdmFyIGFzU2x1ZywgZW1wdHlQYWdlLCBuZXdQYWdlLCBub3dTZWN0aW9ucywgdXRpbCwgXztcblxuICB1dGlsID0gcmVxdWlyZSgnLi91dGlsJyk7XG5cbiAgXyA9IHJlcXVpcmUoJ3VuZGVyc2NvcmUnKTtcblxuICBhc1NsdWcgPSBmdW5jdGlvbihuYW1lKSB7XG4gICAgcmV0dXJuIG5hbWUucmVwbGFjZSgvXFxzL2csICctJykucmVwbGFjZSgvW15BLVphLXowLTktXS9nLCAnJykudG9Mb3dlckNhc2UoKTtcbiAgfTtcblxuICBlbXB0eVBhZ2UgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gbmV3UGFnZSh7fSwgbnVsbCk7XG4gIH07XG5cbiAgbm93U2VjdGlvbnMgPSBmdW5jdGlvbihub3cpIHtcbiAgICByZXR1cm4gW1xuICAgICAge1xuICAgICAgICBzeW1ib2w6ICfinYQnLFxuICAgICAgICBkYXRlOiBub3cgLSAxMDAwICogNjAgKiA2MCAqIDI0ICogMzY2LFxuICAgICAgICBwZXJpb2Q6ICdhIFllYXInXG4gICAgICB9LCB7XG4gICAgICAgIHN5bWJvbDogJ+KamCcsXG4gICAgICAgIGRhdGU6IG5vdyAtIDEwMDAgKiA2MCAqIDYwICogMjQgKiAzMSAqIDMsXG4gICAgICAgIHBlcmlvZDogJ2EgU2Vhc29uJ1xuICAgICAgfSwge1xuICAgICAgICBzeW1ib2w6ICfimqonLFxuICAgICAgICBkYXRlOiBub3cgLSAxMDAwICogNjAgKiA2MCAqIDI0ICogMzEsXG4gICAgICAgIHBlcmlvZDogJ2EgTW9udGgnXG4gICAgICB9LCB7XG4gICAgICAgIHN5bWJvbDogJ+KYvScsXG4gICAgICAgIGRhdGU6IG5vdyAtIDEwMDAgKiA2MCAqIDYwICogMjQgKiA3LFxuICAgICAgICBwZXJpb2Q6ICdhIFdlZWsnXG4gICAgICB9LCB7XG4gICAgICAgIHN5bWJvbDogJ+KYgCcsXG4gICAgICAgIGRhdGU6IG5vdyAtIDEwMDAgKiA2MCAqIDYwICogMjQsXG4gICAgICAgIHBlcmlvZDogJ2EgRGF5J1xuICAgICAgfSwge1xuICAgICAgICBzeW1ib2w6ICfijJonLFxuICAgICAgICBkYXRlOiBub3cgLSAxMDAwICogNjAgKiA2MCxcbiAgICAgICAgcGVyaW9kOiAnYW4gSG91cidcbiAgICAgIH1cbiAgICBdO1xuICB9O1xuXG4gIG5ld1BhZ2UgPSBmdW5jdGlvbihqc29uLCBzaXRlKSB7XG4gICAgdmFyIGFkZEl0ZW0sIGFkZFBhcmFncmFwaCwgZ2V0Q29udGV4dCwgZ2V0TmVpZ2hib3JzLCBnZXRSYXdQYWdlLCBnZXRSZW1vdGVTaXRlLCBnZXRTbHVnLCBpc0xvY2FsLCBpc1BsdWdpbiwgaXNSZW1vdGUsIHBhZ2UsIHNlcUFjdGlvbnMsIHNlcUl0ZW1zLCBzZXRUaXRsZTtcbiAgICBwYWdlID0gXy5leHRlbmQoe30sIHV0aWwuZW1wdHlQYWdlKCksIGpzb24pO1xuICAgIHBhZ2Uuc3RvcnkgfHwgKHBhZ2Uuc3RvcnkgPSBbXSk7XG4gICAgcGFnZS5qb3VybmFsIHx8IChwYWdlLmpvdXJuYWwgPSBbXSk7XG4gICAgZ2V0UmF3UGFnZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHBhZ2U7XG4gICAgfTtcbiAgICBnZXRDb250ZXh0ID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgYWN0aW9uLCBhZGRDb250ZXh0LCBjb250ZXh0LCBfaSwgX2xlbiwgX3JlZjtcbiAgICAgIGNvbnRleHQgPSBbJ3ZpZXcnXTtcbiAgICAgIGlmIChpc1JlbW90ZSgpKSB7XG4gICAgICAgIGNvbnRleHQucHVzaChzaXRlKTtcbiAgICAgIH1cbiAgICAgIGFkZENvbnRleHQgPSBmdW5jdGlvbihzaXRlKSB7XG4gICAgICAgIGlmICgoc2l0ZSAhPSBudWxsKSAmJiAhXy5pbmNsdWRlKGNvbnRleHQsIHNpdGUpKSB7XG4gICAgICAgICAgcmV0dXJuIGNvbnRleHQucHVzaChzaXRlKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIF9yZWYgPSBwYWdlLmpvdXJuYWwuc2xpY2UoMCkucmV2ZXJzZSgpO1xuICAgICAgZm9yIChfaSA9IDAsIF9sZW4gPSBfcmVmLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgICAgIGFjdGlvbiA9IF9yZWZbX2ldO1xuICAgICAgICBhZGRDb250ZXh0KGFjdGlvbi5zaXRlKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjb250ZXh0O1xuICAgIH07XG4gICAgaXNQbHVnaW4gPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBwYWdlLnBsdWdpbiAhPSBudWxsO1xuICAgIH07XG4gICAgaXNSZW1vdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiAhKHNpdGUgPT09ICh2b2lkIDApIHx8IHNpdGUgPT09IG51bGwgfHwgc2l0ZSA9PT0gJ3ZpZXcnIHx8IHNpdGUgPT09ICdvcmlnaW4nIHx8IHNpdGUgPT09ICdsb2NhbCcpO1xuICAgIH07XG4gICAgaXNMb2NhbCA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHNpdGUgPT09ICdsb2NhbCc7XG4gICAgfTtcbiAgICBnZXRSZW1vdGVTaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoaXNSZW1vdGUoKSkge1xuICAgICAgICByZXR1cm4gc2l0ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG4gICAgZ2V0U2x1ZyA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIGFzU2x1ZyhwYWdlLnRpdGxlKTtcbiAgICB9O1xuICAgIGdldE5laWdoYm9ycyA9IGZ1bmN0aW9uKGhvc3QpIHtcbiAgICAgIHZhciBhY3Rpb24sIGl0ZW0sIG5laWdoYm9ycywgX2ksIF9qLCBfbGVuLCBfbGVuMSwgX3JlZiwgX3JlZjE7XG4gICAgICBuZWlnaGJvcnMgPSBbXTtcbiAgICAgIGlmIChpc1JlbW90ZSgpKSB7XG4gICAgICAgIG5laWdoYm9ycy5wdXNoKHNpdGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGhvc3QgIT0gbnVsbCkge1xuICAgICAgICAgIG5laWdoYm9ycy5wdXNoKGhvc3QpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBfcmVmID0gcGFnZS5zdG9yeTtcbiAgICAgIGZvciAoX2kgPSAwLCBfbGVuID0gX3JlZi5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgICBpdGVtID0gX3JlZltfaV07XG4gICAgICAgIGlmIChpdGVtLnNpdGUgIT0gbnVsbCkge1xuICAgICAgICAgIG5laWdoYm9ycy5wdXNoKGl0ZW0uc2l0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIF9yZWYxID0gcGFnZS5qb3VybmFsO1xuICAgICAgZm9yIChfaiA9IDAsIF9sZW4xID0gX3JlZjEubGVuZ3RoOyBfaiA8IF9sZW4xOyBfaisrKSB7XG4gICAgICAgIGFjdGlvbiA9IF9yZWYxW19qXTtcbiAgICAgICAgaWYgKGFjdGlvbi5zaXRlICE9IG51bGwpIHtcbiAgICAgICAgICBuZWlnaGJvcnMucHVzaChhY3Rpb24uc2l0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBfLnVuaXEobmVpZ2hib3JzKTtcbiAgICB9O1xuICAgIHNldFRpdGxlID0gZnVuY3Rpb24odGl0bGUpIHtcbiAgICAgIHJldHVybiBwYWdlLnRpdGxlID0gdGl0bGU7XG4gICAgfTtcbiAgICBhZGRJdGVtID0gZnVuY3Rpb24oaXRlbSkge1xuICAgICAgaXRlbSA9IF8uZXh0ZW5kKHt9LCB7XG4gICAgICAgIGlkOiB1dGlsLnJhbmRvbUJ5dGVzKDgpXG4gICAgICB9LCBpdGVtKTtcbiAgICAgIHJldHVybiBwYWdlLnN0b3J5LnB1c2goaXRlbSk7XG4gICAgfTtcbiAgICBzZXFJdGVtcyA9IGZ1bmN0aW9uKGVhY2gpIHtcbiAgICAgIHZhciBlbWl0SXRlbTtcbiAgICAgIGVtaXRJdGVtID0gZnVuY3Rpb24oaSkge1xuICAgICAgICBpZiAoaSA+PSBwYWdlLnN0b3J5Lmxlbmd0aCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZWFjaChwYWdlLnN0b3J5W2ldLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gZW1pdEl0ZW0oaSArIDEpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgICByZXR1cm4gZW1pdEl0ZW0oMCk7XG4gICAgfTtcbiAgICBhZGRQYXJhZ3JhcGggPSBmdW5jdGlvbih0ZXh0KSB7XG4gICAgICB2YXIgdHlwZTtcbiAgICAgIHR5cGUgPSBcInBhcmFncmFwaFwiO1xuICAgICAgcmV0dXJuIGFkZEl0ZW0oe1xuICAgICAgICB0eXBlOiB0eXBlLFxuICAgICAgICB0ZXh0OiB0ZXh0XG4gICAgICB9KTtcbiAgICB9O1xuICAgIHNlcUFjdGlvbnMgPSBmdW5jdGlvbihlYWNoKSB7XG4gICAgICB2YXIgZW1pdEFjdGlvbiwgc2VjdGlvbnMsIHNtYWxsZXI7XG4gICAgICBzbWFsbGVyID0gMDtcbiAgICAgIHNlY3Rpb25zID0gbm93U2VjdGlvbnMoKG5ldyBEYXRlKS5nZXRUaW1lKCkpO1xuICAgICAgZW1pdEFjdGlvbiA9IGZ1bmN0aW9uKGkpIHtcbiAgICAgICAgdmFyIGFjdGlvbiwgYmlnZ2VyLCBzZWN0aW9uLCBzZXBhcmF0b3IsIF9pLCBfbGVuO1xuICAgICAgICBpZiAoaSA+PSBwYWdlLmpvdXJuYWwubGVuZ3RoKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGFjdGlvbiA9IHBhZ2Uuam91cm5hbFtpXTtcbiAgICAgICAgYmlnZ2VyID0gYWN0aW9uLmRhdGUgfHwgMDtcbiAgICAgICAgc2VwYXJhdG9yID0gbnVsbDtcbiAgICAgICAgZm9yIChfaSA9IDAsIF9sZW4gPSBzZWN0aW9ucy5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgICAgIHNlY3Rpb24gPSBzZWN0aW9uc1tfaV07XG4gICAgICAgICAgaWYgKHNlY3Rpb24uZGF0ZSA+IHNtYWxsZXIgJiYgc2VjdGlvbi5kYXRlIDwgYmlnZ2VyKSB7XG4gICAgICAgICAgICBzZXBhcmF0b3IgPSBzZWN0aW9uO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBzbWFsbGVyID0gYmlnZ2VyO1xuICAgICAgICByZXR1cm4gZWFjaCh7XG4gICAgICAgICAgYWN0aW9uOiBhY3Rpb24sXG4gICAgICAgICAgc2VwYXJhdG9yOiBzZXBhcmF0b3JcbiAgICAgICAgfSwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIGVtaXRBY3Rpb24oaSArIDEpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgICByZXR1cm4gZW1pdEFjdGlvbigwKTtcbiAgICB9O1xuICAgIHJldHVybiB7XG4gICAgICBnZXRSYXdQYWdlOiBnZXRSYXdQYWdlLFxuICAgICAgZ2V0Q29udGV4dDogZ2V0Q29udGV4dCxcbiAgICAgIGlzUGx1Z2luOiBpc1BsdWdpbixcbiAgICAgIGlzUmVtb3RlOiBpc1JlbW90ZSxcbiAgICAgIGlzTG9jYWw6IGlzTG9jYWwsXG4gICAgICBnZXRSZW1vdGVTaXRlOiBnZXRSZW1vdGVTaXRlLFxuICAgICAgZ2V0U2x1ZzogZ2V0U2x1ZyxcbiAgICAgIGdldE5laWdoYm9yczogZ2V0TmVpZ2hib3JzLFxuICAgICAgc2V0VGl0bGU6IHNldFRpdGxlLFxuICAgICAgYWRkSXRlbTogYWRkSXRlbSxcbiAgICAgIGFkZFBhcmFncmFwaDogYWRkUGFyYWdyYXBoLFxuICAgICAgc2VxSXRlbXM6IHNlcUl0ZW1zLFxuICAgICAgc2VxQWN0aW9uczogc2VxQWN0aW9uc1xuICAgIH07XG4gIH07XG5cbiAgbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgbmV3UGFnZTogbmV3UGFnZSxcbiAgICBlbXB0eVBhZ2U6IGVtcHR5UGFnZVxuICB9O1xuXG59KS5jYWxsKHRoaXMpO1xuIiwiKGZ1bmN0aW9uKCl7Ly8gICAgIFVuZGVyc2NvcmUuanMgMS41LjJcbi8vICAgICBodHRwOi8vdW5kZXJzY29yZWpzLm9yZ1xuLy8gICAgIChjKSAyMDA5LTIwMTMgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbi8vICAgICBVbmRlcnNjb3JlIG1heSBiZSBmcmVlbHkgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuXG4oZnVuY3Rpb24oKSB7XG5cbiAgLy8gQmFzZWxpbmUgc2V0dXBcbiAgLy8gLS0tLS0tLS0tLS0tLS1cblxuICAvLyBFc3RhYmxpc2ggdGhlIHJvb3Qgb2JqZWN0LCBgd2luZG93YCBpbiB0aGUgYnJvd3Nlciwgb3IgYGV4cG9ydHNgIG9uIHRoZSBzZXJ2ZXIuXG4gIHZhciByb290ID0gdGhpcztcblxuICAvLyBTYXZlIHRoZSBwcmV2aW91cyB2YWx1ZSBvZiB0aGUgYF9gIHZhcmlhYmxlLlxuICB2YXIgcHJldmlvdXNVbmRlcnNjb3JlID0gcm9vdC5fO1xuXG4gIC8vIEVzdGFibGlzaCB0aGUgb2JqZWN0IHRoYXQgZ2V0cyByZXR1cm5lZCB0byBicmVhayBvdXQgb2YgYSBsb29wIGl0ZXJhdGlvbi5cbiAgdmFyIGJyZWFrZXIgPSB7fTtcblxuICAvLyBTYXZlIGJ5dGVzIGluIHRoZSBtaW5pZmllZCAoYnV0IG5vdCBnemlwcGVkKSB2ZXJzaW9uOlxuICB2YXIgQXJyYXlQcm90byA9IEFycmF5LnByb3RvdHlwZSwgT2JqUHJvdG8gPSBPYmplY3QucHJvdG90eXBlLCBGdW5jUHJvdG8gPSBGdW5jdGlvbi5wcm90b3R5cGU7XG5cbiAgLy8gQ3JlYXRlIHF1aWNrIHJlZmVyZW5jZSB2YXJpYWJsZXMgZm9yIHNwZWVkIGFjY2VzcyB0byBjb3JlIHByb3RvdHlwZXMuXG4gIHZhclxuICAgIHB1c2ggICAgICAgICAgICAgPSBBcnJheVByb3RvLnB1c2gsXG4gICAgc2xpY2UgICAgICAgICAgICA9IEFycmF5UHJvdG8uc2xpY2UsXG4gICAgY29uY2F0ICAgICAgICAgICA9IEFycmF5UHJvdG8uY29uY2F0LFxuICAgIHRvU3RyaW5nICAgICAgICAgPSBPYmpQcm90by50b1N0cmluZyxcbiAgICBoYXNPd25Qcm9wZXJ0eSAgID0gT2JqUHJvdG8uaGFzT3duUHJvcGVydHk7XG5cbiAgLy8gQWxsICoqRUNNQVNjcmlwdCA1KiogbmF0aXZlIGZ1bmN0aW9uIGltcGxlbWVudGF0aW9ucyB0aGF0IHdlIGhvcGUgdG8gdXNlXG4gIC8vIGFyZSBkZWNsYXJlZCBoZXJlLlxuICB2YXJcbiAgICBuYXRpdmVGb3JFYWNoICAgICAgPSBBcnJheVByb3RvLmZvckVhY2gsXG4gICAgbmF0aXZlTWFwICAgICAgICAgID0gQXJyYXlQcm90by5tYXAsXG4gICAgbmF0aXZlUmVkdWNlICAgICAgID0gQXJyYXlQcm90by5yZWR1Y2UsXG4gICAgbmF0aXZlUmVkdWNlUmlnaHQgID0gQXJyYXlQcm90by5yZWR1Y2VSaWdodCxcbiAgICBuYXRpdmVGaWx0ZXIgICAgICAgPSBBcnJheVByb3RvLmZpbHRlcixcbiAgICBuYXRpdmVFdmVyeSAgICAgICAgPSBBcnJheVByb3RvLmV2ZXJ5LFxuICAgIG5hdGl2ZVNvbWUgICAgICAgICA9IEFycmF5UHJvdG8uc29tZSxcbiAgICBuYXRpdmVJbmRleE9mICAgICAgPSBBcnJheVByb3RvLmluZGV4T2YsXG4gICAgbmF0aXZlTGFzdEluZGV4T2YgID0gQXJyYXlQcm90by5sYXN0SW5kZXhPZixcbiAgICBuYXRpdmVJc0FycmF5ICAgICAgPSBBcnJheS5pc0FycmF5LFxuICAgIG5hdGl2ZUtleXMgICAgICAgICA9IE9iamVjdC5rZXlzLFxuICAgIG5hdGl2ZUJpbmQgICAgICAgICA9IEZ1bmNQcm90by5iaW5kO1xuXG4gIC8vIENyZWF0ZSBhIHNhZmUgcmVmZXJlbmNlIHRvIHRoZSBVbmRlcnNjb3JlIG9iamVjdCBmb3IgdXNlIGJlbG93LlxuICB2YXIgXyA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmIChvYmogaW5zdGFuY2VvZiBfKSByZXR1cm4gb2JqO1xuICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBfKSkgcmV0dXJuIG5ldyBfKG9iaik7XG4gICAgdGhpcy5fd3JhcHBlZCA9IG9iajtcbiAgfTtcblxuICAvLyBFeHBvcnQgdGhlIFVuZGVyc2NvcmUgb2JqZWN0IGZvciAqKk5vZGUuanMqKiwgd2l0aFxuICAvLyBiYWNrd2FyZHMtY29tcGF0aWJpbGl0eSBmb3IgdGhlIG9sZCBgcmVxdWlyZSgpYCBBUEkuIElmIHdlJ3JlIGluXG4gIC8vIHRoZSBicm93c2VyLCBhZGQgYF9gIGFzIGEgZ2xvYmFsIG9iamVjdCB2aWEgYSBzdHJpbmcgaWRlbnRpZmllcixcbiAgLy8gZm9yIENsb3N1cmUgQ29tcGlsZXIgXCJhZHZhbmNlZFwiIG1vZGUuXG4gIGlmICh0eXBlb2YgZXhwb3J0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAodHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgJiYgbW9kdWxlLmV4cG9ydHMpIHtcbiAgICAgIGV4cG9ydHMgPSBtb2R1bGUuZXhwb3J0cyA9IF87XG4gICAgfVxuICAgIGV4cG9ydHMuXyA9IF87XG4gIH0gZWxzZSB7XG4gICAgcm9vdC5fID0gXztcbiAgfVxuXG4gIC8vIEN1cnJlbnQgdmVyc2lvbi5cbiAgXy5WRVJTSU9OID0gJzEuNS4yJztcblxuICAvLyBDb2xsZWN0aW9uIEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIFRoZSBjb3JuZXJzdG9uZSwgYW4gYGVhY2hgIGltcGxlbWVudGF0aW9uLCBha2EgYGZvckVhY2hgLlxuICAvLyBIYW5kbGVzIG9iamVjdHMgd2l0aCB0aGUgYnVpbHQtaW4gYGZvckVhY2hgLCBhcnJheXMsIGFuZCByYXcgb2JqZWN0cy5cbiAgLy8gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYGZvckVhY2hgIGlmIGF2YWlsYWJsZS5cbiAgdmFyIGVhY2ggPSBfLmVhY2ggPSBfLmZvckVhY2ggPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm47XG4gICAgaWYgKG5hdGl2ZUZvckVhY2ggJiYgb2JqLmZvckVhY2ggPT09IG5hdGl2ZUZvckVhY2gpIHtcbiAgICAgIG9iai5mb3JFYWNoKGl0ZXJhdG9yLCBjb250ZXh0KTtcbiAgICB9IGVsc2UgaWYgKG9iai5sZW5ndGggPT09ICtvYmoubGVuZ3RoKSB7XG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0gb2JqLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChpdGVyYXRvci5jYWxsKGNvbnRleHQsIG9ialtpXSwgaSwgb2JqKSA9PT0gYnJlYWtlcikgcmV0dXJuO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIga2V5cyA9IF8ua2V5cyhvYmopO1xuICAgICAgZm9yICh2YXIgaSA9IDAsIGxlbmd0aCA9IGtleXMubGVuZ3RoOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKGl0ZXJhdG9yLmNhbGwoY29udGV4dCwgb2JqW2tleXNbaV1dLCBrZXlzW2ldLCBvYmopID09PSBicmVha2VyKSByZXR1cm47XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIC8vIFJldHVybiB0aGUgcmVzdWx0cyBvZiBhcHBseWluZyB0aGUgaXRlcmF0b3IgdG8gZWFjaCBlbGVtZW50LlxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgbWFwYCBpZiBhdmFpbGFibGUuXG4gIF8ubWFwID0gXy5jb2xsZWN0ID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIHZhciByZXN1bHRzID0gW107XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm4gcmVzdWx0cztcbiAgICBpZiAobmF0aXZlTWFwICYmIG9iai5tYXAgPT09IG5hdGl2ZU1hcCkgcmV0dXJuIG9iai5tYXAoaXRlcmF0b3IsIGNvbnRleHQpO1xuICAgIGVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgIHJlc3VsdHMucHVzaChpdGVyYXRvci5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCwgbGlzdCkpO1xuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9O1xuXG4gIHZhciByZWR1Y2VFcnJvciA9ICdSZWR1Y2Ugb2YgZW1wdHkgYXJyYXkgd2l0aCBubyBpbml0aWFsIHZhbHVlJztcblxuICAvLyAqKlJlZHVjZSoqIGJ1aWxkcyB1cCBhIHNpbmdsZSByZXN1bHQgZnJvbSBhIGxpc3Qgb2YgdmFsdWVzLCBha2EgYGluamVjdGAsXG4gIC8vIG9yIGBmb2xkbGAuIERlbGVnYXRlcyB0byAqKkVDTUFTY3JpcHQgNSoqJ3MgbmF0aXZlIGByZWR1Y2VgIGlmIGF2YWlsYWJsZS5cbiAgXy5yZWR1Y2UgPSBfLmZvbGRsID0gXy5pbmplY3QgPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBtZW1vLCBjb250ZXh0KSB7XG4gICAgdmFyIGluaXRpYWwgPSBhcmd1bWVudHMubGVuZ3RoID4gMjtcbiAgICBpZiAob2JqID09IG51bGwpIG9iaiA9IFtdO1xuICAgIGlmIChuYXRpdmVSZWR1Y2UgJiYgb2JqLnJlZHVjZSA9PT0gbmF0aXZlUmVkdWNlKSB7XG4gICAgICBpZiAoY29udGV4dCkgaXRlcmF0b3IgPSBfLmJpbmQoaXRlcmF0b3IsIGNvbnRleHQpO1xuICAgICAgcmV0dXJuIGluaXRpYWwgPyBvYmoucmVkdWNlKGl0ZXJhdG9yLCBtZW1vKSA6IG9iai5yZWR1Y2UoaXRlcmF0b3IpO1xuICAgIH1cbiAgICBlYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICBpZiAoIWluaXRpYWwpIHtcbiAgICAgICAgbWVtbyA9IHZhbHVlO1xuICAgICAgICBpbml0aWFsID0gdHJ1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG1lbW8gPSBpdGVyYXRvci5jYWxsKGNvbnRleHQsIG1lbW8sIHZhbHVlLCBpbmRleCwgbGlzdCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYgKCFpbml0aWFsKSB0aHJvdyBuZXcgVHlwZUVycm9yKHJlZHVjZUVycm9yKTtcbiAgICByZXR1cm4gbWVtbztcbiAgfTtcblxuICAvLyBUaGUgcmlnaHQtYXNzb2NpYXRpdmUgdmVyc2lvbiBvZiByZWR1Y2UsIGFsc28ga25vd24gYXMgYGZvbGRyYC5cbiAgLy8gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYHJlZHVjZVJpZ2h0YCBpZiBhdmFpbGFibGUuXG4gIF8ucmVkdWNlUmlnaHQgPSBfLmZvbGRyID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRvciwgbWVtbywgY29udGV4dCkge1xuICAgIHZhciBpbml0aWFsID0gYXJndW1lbnRzLmxlbmd0aCA+IDI7XG4gICAgaWYgKG9iaiA9PSBudWxsKSBvYmogPSBbXTtcbiAgICBpZiAobmF0aXZlUmVkdWNlUmlnaHQgJiYgb2JqLnJlZHVjZVJpZ2h0ID09PSBuYXRpdmVSZWR1Y2VSaWdodCkge1xuICAgICAgaWYgKGNvbnRleHQpIGl0ZXJhdG9yID0gXy5iaW5kKGl0ZXJhdG9yLCBjb250ZXh0KTtcbiAgICAgIHJldHVybiBpbml0aWFsID8gb2JqLnJlZHVjZVJpZ2h0KGl0ZXJhdG9yLCBtZW1vKSA6IG9iai5yZWR1Y2VSaWdodChpdGVyYXRvcik7XG4gICAgfVxuICAgIHZhciBsZW5ndGggPSBvYmoubGVuZ3RoO1xuICAgIGlmIChsZW5ndGggIT09ICtsZW5ndGgpIHtcbiAgICAgIHZhciBrZXlzID0gXy5rZXlzKG9iaik7XG4gICAgICBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgICB9XG4gICAgZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgaW5kZXggPSBrZXlzID8ga2V5c1stLWxlbmd0aF0gOiAtLWxlbmd0aDtcbiAgICAgIGlmICghaW5pdGlhbCkge1xuICAgICAgICBtZW1vID0gb2JqW2luZGV4XTtcbiAgICAgICAgaW5pdGlhbCA9IHRydWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtZW1vID0gaXRlcmF0b3IuY2FsbChjb250ZXh0LCBtZW1vLCBvYmpbaW5kZXhdLCBpbmRleCwgbGlzdCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYgKCFpbml0aWFsKSB0aHJvdyBuZXcgVHlwZUVycm9yKHJlZHVjZUVycm9yKTtcbiAgICByZXR1cm4gbWVtbztcbiAgfTtcblxuICAvLyBSZXR1cm4gdGhlIGZpcnN0IHZhbHVlIHdoaWNoIHBhc3NlcyBhIHRydXRoIHRlc3QuIEFsaWFzZWQgYXMgYGRldGVjdGAuXG4gIF8uZmluZCA9IF8uZGV0ZWN0ID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIHZhciByZXN1bHQ7XG4gICAgYW55KG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICBpZiAoaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpKSB7XG4gICAgICAgIHJlc3VsdCA9IHZhbHVlO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIC8vIFJldHVybiBhbGwgdGhlIGVsZW1lbnRzIHRoYXQgcGFzcyBhIHRydXRoIHRlc3QuXG4gIC8vIERlbGVnYXRlcyB0byAqKkVDTUFTY3JpcHQgNSoqJ3MgbmF0aXZlIGBmaWx0ZXJgIGlmIGF2YWlsYWJsZS5cbiAgLy8gQWxpYXNlZCBhcyBgc2VsZWN0YC5cbiAgXy5maWx0ZXIgPSBfLnNlbGVjdCA9IGZ1bmN0aW9uKG9iaiwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICB2YXIgcmVzdWx0cyA9IFtdO1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIHJlc3VsdHM7XG4gICAgaWYgKG5hdGl2ZUZpbHRlciAmJiBvYmouZmlsdGVyID09PSBuYXRpdmVGaWx0ZXIpIHJldHVybiBvYmouZmlsdGVyKGl0ZXJhdG9yLCBjb250ZXh0KTtcbiAgICBlYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICBpZiAoaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpKSByZXN1bHRzLnB1c2godmFsdWUpO1xuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9O1xuXG4gIC8vIFJldHVybiBhbGwgdGhlIGVsZW1lbnRzIGZvciB3aGljaCBhIHRydXRoIHRlc3QgZmFpbHMuXG4gIF8ucmVqZWN0ID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIHJldHVybiBfLmZpbHRlcihvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgcmV0dXJuICFpdGVyYXRvci5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCwgbGlzdCk7XG4gICAgfSwgY29udGV4dCk7XG4gIH07XG5cbiAgLy8gRGV0ZXJtaW5lIHdoZXRoZXIgYWxsIG9mIHRoZSBlbGVtZW50cyBtYXRjaCBhIHRydXRoIHRlc3QuXG4gIC8vIERlbGVnYXRlcyB0byAqKkVDTUFTY3JpcHQgNSoqJ3MgbmF0aXZlIGBldmVyeWAgaWYgYXZhaWxhYmxlLlxuICAvLyBBbGlhc2VkIGFzIGBhbGxgLlxuICBfLmV2ZXJ5ID0gXy5hbGwgPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaXRlcmF0b3IgfHwgKGl0ZXJhdG9yID0gXy5pZGVudGl0eSk7XG4gICAgdmFyIHJlc3VsdCA9IHRydWU7XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm4gcmVzdWx0O1xuICAgIGlmIChuYXRpdmVFdmVyeSAmJiBvYmouZXZlcnkgPT09IG5hdGl2ZUV2ZXJ5KSByZXR1cm4gb2JqLmV2ZXJ5KGl0ZXJhdG9yLCBjb250ZXh0KTtcbiAgICBlYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICBpZiAoIShyZXN1bHQgPSByZXN1bHQgJiYgaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpKSkgcmV0dXJuIGJyZWFrZXI7XG4gICAgfSk7XG4gICAgcmV0dXJuICEhcmVzdWx0O1xuICB9O1xuXG4gIC8vIERldGVybWluZSBpZiBhdCBsZWFzdCBvbmUgZWxlbWVudCBpbiB0aGUgb2JqZWN0IG1hdGNoZXMgYSB0cnV0aCB0ZXN0LlxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgc29tZWAgaWYgYXZhaWxhYmxlLlxuICAvLyBBbGlhc2VkIGFzIGBhbnlgLlxuICB2YXIgYW55ID0gXy5zb21lID0gXy5hbnkgPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaXRlcmF0b3IgfHwgKGl0ZXJhdG9yID0gXy5pZGVudGl0eSk7XG4gICAgdmFyIHJlc3VsdCA9IGZhbHNlO1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIHJlc3VsdDtcbiAgICBpZiAobmF0aXZlU29tZSAmJiBvYmouc29tZSA9PT0gbmF0aXZlU29tZSkgcmV0dXJuIG9iai5zb21lKGl0ZXJhdG9yLCBjb250ZXh0KTtcbiAgICBlYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICBpZiAocmVzdWx0IHx8IChyZXN1bHQgPSBpdGVyYXRvci5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCwgbGlzdCkpKSByZXR1cm4gYnJlYWtlcjtcbiAgICB9KTtcbiAgICByZXR1cm4gISFyZXN1bHQ7XG4gIH07XG5cbiAgLy8gRGV0ZXJtaW5lIGlmIHRoZSBhcnJheSBvciBvYmplY3QgY29udGFpbnMgYSBnaXZlbiB2YWx1ZSAodXNpbmcgYD09PWApLlxuICAvLyBBbGlhc2VkIGFzIGBpbmNsdWRlYC5cbiAgXy5jb250YWlucyA9IF8uaW5jbHVkZSA9IGZ1bmN0aW9uKG9iaiwgdGFyZ2V0KSB7XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKG5hdGl2ZUluZGV4T2YgJiYgb2JqLmluZGV4T2YgPT09IG5hdGl2ZUluZGV4T2YpIHJldHVybiBvYmouaW5kZXhPZih0YXJnZXQpICE9IC0xO1xuICAgIHJldHVybiBhbnkob2JqLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgcmV0dXJuIHZhbHVlID09PSB0YXJnZXQ7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gSW52b2tlIGEgbWV0aG9kICh3aXRoIGFyZ3VtZW50cykgb24gZXZlcnkgaXRlbSBpbiBhIGNvbGxlY3Rpb24uXG4gIF8uaW52b2tlID0gZnVuY3Rpb24ob2JqLCBtZXRob2QpIHtcbiAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAyKTtcbiAgICB2YXIgaXNGdW5jID0gXy5pc0Z1bmN0aW9uKG1ldGhvZCk7XG4gICAgcmV0dXJuIF8ubWFwKG9iaiwgZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgIHJldHVybiAoaXNGdW5jID8gbWV0aG9kIDogdmFsdWVbbWV0aG9kXSkuYXBwbHkodmFsdWUsIGFyZ3MpO1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIENvbnZlbmllbmNlIHZlcnNpb24gb2YgYSBjb21tb24gdXNlIGNhc2Ugb2YgYG1hcGA6IGZldGNoaW5nIGEgcHJvcGVydHkuXG4gIF8ucGx1Y2sgPSBmdW5jdGlvbihvYmosIGtleSkge1xuICAgIHJldHVybiBfLm1hcChvYmosIGZ1bmN0aW9uKHZhbHVlKXsgcmV0dXJuIHZhbHVlW2tleV07IH0pO1xuICB9O1xuXG4gIC8vIENvbnZlbmllbmNlIHZlcnNpb24gb2YgYSBjb21tb24gdXNlIGNhc2Ugb2YgYGZpbHRlcmA6IHNlbGVjdGluZyBvbmx5IG9iamVjdHNcbiAgLy8gY29udGFpbmluZyBzcGVjaWZpYyBga2V5OnZhbHVlYCBwYWlycy5cbiAgXy53aGVyZSA9IGZ1bmN0aW9uKG9iaiwgYXR0cnMsIGZpcnN0KSB7XG4gICAgaWYgKF8uaXNFbXB0eShhdHRycykpIHJldHVybiBmaXJzdCA/IHZvaWQgMCA6IFtdO1xuICAgIHJldHVybiBfW2ZpcnN0ID8gJ2ZpbmQnIDogJ2ZpbHRlciddKG9iaiwgZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgIGZvciAodmFyIGtleSBpbiBhdHRycykge1xuICAgICAgICBpZiAoYXR0cnNba2V5XSAhPT0gdmFsdWVba2V5XSkgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gQ29udmVuaWVuY2UgdmVyc2lvbiBvZiBhIGNvbW1vbiB1c2UgY2FzZSBvZiBgZmluZGA6IGdldHRpbmcgdGhlIGZpcnN0IG9iamVjdFxuICAvLyBjb250YWluaW5nIHNwZWNpZmljIGBrZXk6dmFsdWVgIHBhaXJzLlxuICBfLmZpbmRXaGVyZSA9IGZ1bmN0aW9uKG9iaiwgYXR0cnMpIHtcbiAgICByZXR1cm4gXy53aGVyZShvYmosIGF0dHJzLCB0cnVlKTtcbiAgfTtcblxuICAvLyBSZXR1cm4gdGhlIG1heGltdW0gZWxlbWVudCBvciAoZWxlbWVudC1iYXNlZCBjb21wdXRhdGlvbikuXG4gIC8vIENhbid0IG9wdGltaXplIGFycmF5cyBvZiBpbnRlZ2VycyBsb25nZXIgdGhhbiA2NSw1MzUgZWxlbWVudHMuXG4gIC8vIFNlZSBbV2ViS2l0IEJ1ZyA4MDc5N10oaHR0cHM6Ly9idWdzLndlYmtpdC5vcmcvc2hvd19idWcuY2dpP2lkPTgwNzk3KVxuICBfLm1heCA9IGZ1bmN0aW9uKG9iaiwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICBpZiAoIWl0ZXJhdG9yICYmIF8uaXNBcnJheShvYmopICYmIG9ialswXSA9PT0gK29ialswXSAmJiBvYmoubGVuZ3RoIDwgNjU1MzUpIHtcbiAgICAgIHJldHVybiBNYXRoLm1heC5hcHBseShNYXRoLCBvYmopO1xuICAgIH1cbiAgICBpZiAoIWl0ZXJhdG9yICYmIF8uaXNFbXB0eShvYmopKSByZXR1cm4gLUluZmluaXR5O1xuICAgIHZhciByZXN1bHQgPSB7Y29tcHV0ZWQgOiAtSW5maW5pdHksIHZhbHVlOiAtSW5maW5pdHl9O1xuICAgIGVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgIHZhciBjb21wdXRlZCA9IGl0ZXJhdG9yID8gaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpIDogdmFsdWU7XG4gICAgICBjb21wdXRlZCA+IHJlc3VsdC5jb21wdXRlZCAmJiAocmVzdWx0ID0ge3ZhbHVlIDogdmFsdWUsIGNvbXB1dGVkIDogY29tcHV0ZWR9KTtcbiAgICB9KTtcbiAgICByZXR1cm4gcmVzdWx0LnZhbHVlO1xuICB9O1xuXG4gIC8vIFJldHVybiB0aGUgbWluaW11bSBlbGVtZW50IChvciBlbGVtZW50LWJhc2VkIGNvbXB1dGF0aW9uKS5cbiAgXy5taW4gPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaWYgKCFpdGVyYXRvciAmJiBfLmlzQXJyYXkob2JqKSAmJiBvYmpbMF0gPT09ICtvYmpbMF0gJiYgb2JqLmxlbmd0aCA8IDY1NTM1KSB7XG4gICAgICByZXR1cm4gTWF0aC5taW4uYXBwbHkoTWF0aCwgb2JqKTtcbiAgICB9XG4gICAgaWYgKCFpdGVyYXRvciAmJiBfLmlzRW1wdHkob2JqKSkgcmV0dXJuIEluZmluaXR5O1xuICAgIHZhciByZXN1bHQgPSB7Y29tcHV0ZWQgOiBJbmZpbml0eSwgdmFsdWU6IEluZmluaXR5fTtcbiAgICBlYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICB2YXIgY29tcHV0ZWQgPSBpdGVyYXRvciA/IGl0ZXJhdG9yLmNhbGwoY29udGV4dCwgdmFsdWUsIGluZGV4LCBsaXN0KSA6IHZhbHVlO1xuICAgICAgY29tcHV0ZWQgPCByZXN1bHQuY29tcHV0ZWQgJiYgKHJlc3VsdCA9IHt2YWx1ZSA6IHZhbHVlLCBjb21wdXRlZCA6IGNvbXB1dGVkfSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3VsdC52YWx1ZTtcbiAgfTtcblxuICAvLyBTaHVmZmxlIGFuIGFycmF5LCB1c2luZyB0aGUgbW9kZXJuIHZlcnNpb24gb2YgdGhlIFxuICAvLyBbRmlzaGVyLVlhdGVzIHNodWZmbGVdKGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRmlzaGVy4oCTWWF0ZXNfc2h1ZmZsZSkuXG4gIF8uc2h1ZmZsZSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciByYW5kO1xuICAgIHZhciBpbmRleCA9IDA7XG4gICAgdmFyIHNodWZmbGVkID0gW107XG4gICAgZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICByYW5kID0gXy5yYW5kb20oaW5kZXgrKyk7XG4gICAgICBzaHVmZmxlZFtpbmRleCAtIDFdID0gc2h1ZmZsZWRbcmFuZF07XG4gICAgICBzaHVmZmxlZFtyYW5kXSA9IHZhbHVlO1xuICAgIH0pO1xuICAgIHJldHVybiBzaHVmZmxlZDtcbiAgfTtcblxuICAvLyBTYW1wbGUgKipuKiogcmFuZG9tIHZhbHVlcyBmcm9tIGFuIGFycmF5LlxuICAvLyBJZiAqKm4qKiBpcyBub3Qgc3BlY2lmaWVkLCByZXR1cm5zIGEgc2luZ2xlIHJhbmRvbSBlbGVtZW50IGZyb20gdGhlIGFycmF5LlxuICAvLyBUaGUgaW50ZXJuYWwgYGd1YXJkYCBhcmd1bWVudCBhbGxvd3MgaXQgdG8gd29yayB3aXRoIGBtYXBgLlxuICBfLnNhbXBsZSA9IGZ1bmN0aW9uKG9iaiwgbiwgZ3VhcmQpIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA8IDIgfHwgZ3VhcmQpIHtcbiAgICAgIHJldHVybiBvYmpbXy5yYW5kb20ob2JqLmxlbmd0aCAtIDEpXTtcbiAgICB9XG4gICAgcmV0dXJuIF8uc2h1ZmZsZShvYmopLnNsaWNlKDAsIE1hdGgubWF4KDAsIG4pKTtcbiAgfTtcblxuICAvLyBBbiBpbnRlcm5hbCBmdW5jdGlvbiB0byBnZW5lcmF0ZSBsb29rdXAgaXRlcmF0b3JzLlxuICB2YXIgbG9va3VwSXRlcmF0b3IgPSBmdW5jdGlvbih2YWx1ZSkge1xuICAgIHJldHVybiBfLmlzRnVuY3Rpb24odmFsdWUpID8gdmFsdWUgOiBmdW5jdGlvbihvYmopeyByZXR1cm4gb2JqW3ZhbHVlXTsgfTtcbiAgfTtcblxuICAvLyBTb3J0IHRoZSBvYmplY3QncyB2YWx1ZXMgYnkgYSBjcml0ZXJpb24gcHJvZHVjZWQgYnkgYW4gaXRlcmF0b3IuXG4gIF8uc29ydEJ5ID0gZnVuY3Rpb24ob2JqLCB2YWx1ZSwgY29udGV4dCkge1xuICAgIHZhciBpdGVyYXRvciA9IGxvb2t1cEl0ZXJhdG9yKHZhbHVlKTtcbiAgICByZXR1cm4gXy5wbHVjayhfLm1hcChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsdWU6IHZhbHVlLFxuICAgICAgICBpbmRleDogaW5kZXgsXG4gICAgICAgIGNyaXRlcmlhOiBpdGVyYXRvci5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCwgbGlzdClcbiAgICAgIH07XG4gICAgfSkuc29ydChmdW5jdGlvbihsZWZ0LCByaWdodCkge1xuICAgICAgdmFyIGEgPSBsZWZ0LmNyaXRlcmlhO1xuICAgICAgdmFyIGIgPSByaWdodC5jcml0ZXJpYTtcbiAgICAgIGlmIChhICE9PSBiKSB7XG4gICAgICAgIGlmIChhID4gYiB8fCBhID09PSB2b2lkIDApIHJldHVybiAxO1xuICAgICAgICBpZiAoYSA8IGIgfHwgYiA9PT0gdm9pZCAwKSByZXR1cm4gLTE7XG4gICAgICB9XG4gICAgICByZXR1cm4gbGVmdC5pbmRleCAtIHJpZ2h0LmluZGV4O1xuICAgIH0pLCAndmFsdWUnKTtcbiAgfTtcblxuICAvLyBBbiBpbnRlcm5hbCBmdW5jdGlvbiB1c2VkIGZvciBhZ2dyZWdhdGUgXCJncm91cCBieVwiIG9wZXJhdGlvbnMuXG4gIHZhciBncm91cCA9IGZ1bmN0aW9uKGJlaGF2aW9yKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKG9iaiwgdmFsdWUsIGNvbnRleHQpIHtcbiAgICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICAgIHZhciBpdGVyYXRvciA9IHZhbHVlID09IG51bGwgPyBfLmlkZW50aXR5IDogbG9va3VwSXRlcmF0b3IodmFsdWUpO1xuICAgICAgZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCkge1xuICAgICAgICB2YXIga2V5ID0gaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIG9iaik7XG4gICAgICAgIGJlaGF2aW9yKHJlc3VsdCwga2V5LCB2YWx1ZSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgfTtcblxuICAvLyBHcm91cHMgdGhlIG9iamVjdCdzIHZhbHVlcyBieSBhIGNyaXRlcmlvbi4gUGFzcyBlaXRoZXIgYSBzdHJpbmcgYXR0cmlidXRlXG4gIC8vIHRvIGdyb3VwIGJ5LCBvciBhIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyB0aGUgY3JpdGVyaW9uLlxuICBfLmdyb3VwQnkgPSBncm91cChmdW5jdGlvbihyZXN1bHQsIGtleSwgdmFsdWUpIHtcbiAgICAoXy5oYXMocmVzdWx0LCBrZXkpID8gcmVzdWx0W2tleV0gOiAocmVzdWx0W2tleV0gPSBbXSkpLnB1c2godmFsdWUpO1xuICB9KTtcblxuICAvLyBJbmRleGVzIHRoZSBvYmplY3QncyB2YWx1ZXMgYnkgYSBjcml0ZXJpb24sIHNpbWlsYXIgdG8gYGdyb3VwQnlgLCBidXQgZm9yXG4gIC8vIHdoZW4geW91IGtub3cgdGhhdCB5b3VyIGluZGV4IHZhbHVlcyB3aWxsIGJlIHVuaXF1ZS5cbiAgXy5pbmRleEJ5ID0gZ3JvdXAoZnVuY3Rpb24ocmVzdWx0LCBrZXksIHZhbHVlKSB7XG4gICAgcmVzdWx0W2tleV0gPSB2YWx1ZTtcbiAgfSk7XG5cbiAgLy8gQ291bnRzIGluc3RhbmNlcyBvZiBhbiBvYmplY3QgdGhhdCBncm91cCBieSBhIGNlcnRhaW4gY3JpdGVyaW9uLiBQYXNzXG4gIC8vIGVpdGhlciBhIHN0cmluZyBhdHRyaWJ1dGUgdG8gY291bnQgYnksIG9yIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZVxuICAvLyBjcml0ZXJpb24uXG4gIF8uY291bnRCeSA9IGdyb3VwKGZ1bmN0aW9uKHJlc3VsdCwga2V5KSB7XG4gICAgXy5oYXMocmVzdWx0LCBrZXkpID8gcmVzdWx0W2tleV0rKyA6IHJlc3VsdFtrZXldID0gMTtcbiAgfSk7XG5cbiAgLy8gVXNlIGEgY29tcGFyYXRvciBmdW5jdGlvbiB0byBmaWd1cmUgb3V0IHRoZSBzbWFsbGVzdCBpbmRleCBhdCB3aGljaFxuICAvLyBhbiBvYmplY3Qgc2hvdWxkIGJlIGluc2VydGVkIHNvIGFzIHRvIG1haW50YWluIG9yZGVyLiBVc2VzIGJpbmFyeSBzZWFyY2guXG4gIF8uc29ydGVkSW5kZXggPSBmdW5jdGlvbihhcnJheSwgb2JqLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIGl0ZXJhdG9yID0gaXRlcmF0b3IgPT0gbnVsbCA/IF8uaWRlbnRpdHkgOiBsb29rdXBJdGVyYXRvcihpdGVyYXRvcik7XG4gICAgdmFyIHZhbHVlID0gaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmopO1xuICAgIHZhciBsb3cgPSAwLCBoaWdoID0gYXJyYXkubGVuZ3RoO1xuICAgIHdoaWxlIChsb3cgPCBoaWdoKSB7XG4gICAgICB2YXIgbWlkID0gKGxvdyArIGhpZ2gpID4+PiAxO1xuICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBhcnJheVttaWRdKSA8IHZhbHVlID8gbG93ID0gbWlkICsgMSA6IGhpZ2ggPSBtaWQ7XG4gICAgfVxuICAgIHJldHVybiBsb3c7XG4gIH07XG5cbiAgLy8gU2FmZWx5IGNyZWF0ZSBhIHJlYWwsIGxpdmUgYXJyYXkgZnJvbSBhbnl0aGluZyBpdGVyYWJsZS5cbiAgXy50b0FycmF5ID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKCFvYmopIHJldHVybiBbXTtcbiAgICBpZiAoXy5pc0FycmF5KG9iaikpIHJldHVybiBzbGljZS5jYWxsKG9iaik7XG4gICAgaWYgKG9iai5sZW5ndGggPT09ICtvYmoubGVuZ3RoKSByZXR1cm4gXy5tYXAob2JqLCBfLmlkZW50aXR5KTtcbiAgICByZXR1cm4gXy52YWx1ZXMob2JqKTtcbiAgfTtcblxuICAvLyBSZXR1cm4gdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiBhbiBvYmplY3QuXG4gIF8uc2l6ZSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIDA7XG4gICAgcmV0dXJuIChvYmoubGVuZ3RoID09PSArb2JqLmxlbmd0aCkgPyBvYmoubGVuZ3RoIDogXy5rZXlzKG9iaikubGVuZ3RoO1xuICB9O1xuXG4gIC8vIEFycmF5IEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS1cblxuICAvLyBHZXQgdGhlIGZpcnN0IGVsZW1lbnQgb2YgYW4gYXJyYXkuIFBhc3NpbmcgKipuKiogd2lsbCByZXR1cm4gdGhlIGZpcnN0IE5cbiAgLy8gdmFsdWVzIGluIHRoZSBhcnJheS4gQWxpYXNlZCBhcyBgaGVhZGAgYW5kIGB0YWtlYC4gVGhlICoqZ3VhcmQqKiBjaGVja1xuICAvLyBhbGxvd3MgaXQgdG8gd29yayB3aXRoIGBfLm1hcGAuXG4gIF8uZmlyc3QgPSBfLmhlYWQgPSBfLnRha2UgPSBmdW5jdGlvbihhcnJheSwgbiwgZ3VhcmQpIHtcbiAgICBpZiAoYXJyYXkgPT0gbnVsbCkgcmV0dXJuIHZvaWQgMDtcbiAgICByZXR1cm4gKG4gPT0gbnVsbCkgfHwgZ3VhcmQgPyBhcnJheVswXSA6IHNsaWNlLmNhbGwoYXJyYXksIDAsIG4pO1xuICB9O1xuXG4gIC8vIFJldHVybnMgZXZlcnl0aGluZyBidXQgdGhlIGxhc3QgZW50cnkgb2YgdGhlIGFycmF5LiBFc3BlY2lhbGx5IHVzZWZ1bCBvblxuICAvLyB0aGUgYXJndW1lbnRzIG9iamVjdC4gUGFzc2luZyAqKm4qKiB3aWxsIHJldHVybiBhbGwgdGhlIHZhbHVlcyBpblxuICAvLyB0aGUgYXJyYXksIGV4Y2x1ZGluZyB0aGUgbGFzdCBOLiBUaGUgKipndWFyZCoqIGNoZWNrIGFsbG93cyBpdCB0byB3b3JrIHdpdGhcbiAgLy8gYF8ubWFwYC5cbiAgXy5pbml0aWFsID0gZnVuY3Rpb24oYXJyYXksIG4sIGd1YXJkKSB7XG4gICAgcmV0dXJuIHNsaWNlLmNhbGwoYXJyYXksIDAsIGFycmF5Lmxlbmd0aCAtICgobiA9PSBudWxsKSB8fCBndWFyZCA/IDEgOiBuKSk7XG4gIH07XG5cbiAgLy8gR2V0IHRoZSBsYXN0IGVsZW1lbnQgb2YgYW4gYXJyYXkuIFBhc3NpbmcgKipuKiogd2lsbCByZXR1cm4gdGhlIGxhc3QgTlxuICAvLyB2YWx1ZXMgaW4gdGhlIGFycmF5LiBUaGUgKipndWFyZCoqIGNoZWNrIGFsbG93cyBpdCB0byB3b3JrIHdpdGggYF8ubWFwYC5cbiAgXy5sYXN0ID0gZnVuY3Rpb24oYXJyYXksIG4sIGd1YXJkKSB7XG4gICAgaWYgKGFycmF5ID09IG51bGwpIHJldHVybiB2b2lkIDA7XG4gICAgaWYgKChuID09IG51bGwpIHx8IGd1YXJkKSB7XG4gICAgICByZXR1cm4gYXJyYXlbYXJyYXkubGVuZ3RoIC0gMV07XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBzbGljZS5jYWxsKGFycmF5LCBNYXRoLm1heChhcnJheS5sZW5ndGggLSBuLCAwKSk7XG4gICAgfVxuICB9O1xuXG4gIC8vIFJldHVybnMgZXZlcnl0aGluZyBidXQgdGhlIGZpcnN0IGVudHJ5IG9mIHRoZSBhcnJheS4gQWxpYXNlZCBhcyBgdGFpbGAgYW5kIGBkcm9wYC5cbiAgLy8gRXNwZWNpYWxseSB1c2VmdWwgb24gdGhlIGFyZ3VtZW50cyBvYmplY3QuIFBhc3NpbmcgYW4gKipuKiogd2lsbCByZXR1cm5cbiAgLy8gdGhlIHJlc3QgTiB2YWx1ZXMgaW4gdGhlIGFycmF5LiBUaGUgKipndWFyZCoqXG4gIC8vIGNoZWNrIGFsbG93cyBpdCB0byB3b3JrIHdpdGggYF8ubWFwYC5cbiAgXy5yZXN0ID0gXy50YWlsID0gXy5kcm9wID0gZnVuY3Rpb24oYXJyYXksIG4sIGd1YXJkKSB7XG4gICAgcmV0dXJuIHNsaWNlLmNhbGwoYXJyYXksIChuID09IG51bGwpIHx8IGd1YXJkID8gMSA6IG4pO1xuICB9O1xuXG4gIC8vIFRyaW0gb3V0IGFsbCBmYWxzeSB2YWx1ZXMgZnJvbSBhbiBhcnJheS5cbiAgXy5jb21wYWN0ID0gZnVuY3Rpb24oYXJyYXkpIHtcbiAgICByZXR1cm4gXy5maWx0ZXIoYXJyYXksIF8uaWRlbnRpdHkpO1xuICB9O1xuXG4gIC8vIEludGVybmFsIGltcGxlbWVudGF0aW9uIG9mIGEgcmVjdXJzaXZlIGBmbGF0dGVuYCBmdW5jdGlvbi5cbiAgdmFyIGZsYXR0ZW4gPSBmdW5jdGlvbihpbnB1dCwgc2hhbGxvdywgb3V0cHV0KSB7XG4gICAgaWYgKHNoYWxsb3cgJiYgXy5ldmVyeShpbnB1dCwgXy5pc0FycmF5KSkge1xuICAgICAgcmV0dXJuIGNvbmNhdC5hcHBseShvdXRwdXQsIGlucHV0KTtcbiAgICB9XG4gICAgZWFjaChpbnB1dCwgZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgIGlmIChfLmlzQXJyYXkodmFsdWUpIHx8IF8uaXNBcmd1bWVudHModmFsdWUpKSB7XG4gICAgICAgIHNoYWxsb3cgPyBwdXNoLmFwcGx5KG91dHB1dCwgdmFsdWUpIDogZmxhdHRlbih2YWx1ZSwgc2hhbGxvdywgb3V0cHV0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG91dHB1dC5wdXNoKHZhbHVlKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gb3V0cHV0O1xuICB9O1xuXG4gIC8vIEZsYXR0ZW4gb3V0IGFuIGFycmF5LCBlaXRoZXIgcmVjdXJzaXZlbHkgKGJ5IGRlZmF1bHQpLCBvciBqdXN0IG9uZSBsZXZlbC5cbiAgXy5mbGF0dGVuID0gZnVuY3Rpb24oYXJyYXksIHNoYWxsb3cpIHtcbiAgICByZXR1cm4gZmxhdHRlbihhcnJheSwgc2hhbGxvdywgW10pO1xuICB9O1xuXG4gIC8vIFJldHVybiBhIHZlcnNpb24gb2YgdGhlIGFycmF5IHRoYXQgZG9lcyBub3QgY29udGFpbiB0aGUgc3BlY2lmaWVkIHZhbHVlKHMpLlxuICBfLndpdGhvdXQgPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHJldHVybiBfLmRpZmZlcmVuY2UoYXJyYXksIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gIH07XG5cbiAgLy8gUHJvZHVjZSBhIGR1cGxpY2F0ZS1mcmVlIHZlcnNpb24gb2YgdGhlIGFycmF5LiBJZiB0aGUgYXJyYXkgaGFzIGFscmVhZHlcbiAgLy8gYmVlbiBzb3J0ZWQsIHlvdSBoYXZlIHRoZSBvcHRpb24gb2YgdXNpbmcgYSBmYXN0ZXIgYWxnb3JpdGhtLlxuICAvLyBBbGlhc2VkIGFzIGB1bmlxdWVgLlxuICBfLnVuaXEgPSBfLnVuaXF1ZSA9IGZ1bmN0aW9uKGFycmF5LCBpc1NvcnRlZCwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICBpZiAoXy5pc0Z1bmN0aW9uKGlzU29ydGVkKSkge1xuICAgICAgY29udGV4dCA9IGl0ZXJhdG9yO1xuICAgICAgaXRlcmF0b3IgPSBpc1NvcnRlZDtcbiAgICAgIGlzU29ydGVkID0gZmFsc2U7XG4gICAgfVxuICAgIHZhciBpbml0aWFsID0gaXRlcmF0b3IgPyBfLm1hcChhcnJheSwgaXRlcmF0b3IsIGNvbnRleHQpIDogYXJyYXk7XG4gICAgdmFyIHJlc3VsdHMgPSBbXTtcbiAgICB2YXIgc2VlbiA9IFtdO1xuICAgIGVhY2goaW5pdGlhbCwgZnVuY3Rpb24odmFsdWUsIGluZGV4KSB7XG4gICAgICBpZiAoaXNTb3J0ZWQgPyAoIWluZGV4IHx8IHNlZW5bc2Vlbi5sZW5ndGggLSAxXSAhPT0gdmFsdWUpIDogIV8uY29udGFpbnMoc2VlbiwgdmFsdWUpKSB7XG4gICAgICAgIHNlZW4ucHVzaCh2YWx1ZSk7XG4gICAgICAgIHJlc3VsdHMucHVzaChhcnJheVtpbmRleF0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9O1xuXG4gIC8vIFByb2R1Y2UgYW4gYXJyYXkgdGhhdCBjb250YWlucyB0aGUgdW5pb246IGVhY2ggZGlzdGluY3QgZWxlbWVudCBmcm9tIGFsbCBvZlxuICAvLyB0aGUgcGFzc2VkLWluIGFycmF5cy5cbiAgXy51bmlvbiA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBfLnVuaXEoXy5mbGF0dGVuKGFyZ3VtZW50cywgdHJ1ZSkpO1xuICB9O1xuXG4gIC8vIFByb2R1Y2UgYW4gYXJyYXkgdGhhdCBjb250YWlucyBldmVyeSBpdGVtIHNoYXJlZCBiZXR3ZWVuIGFsbCB0aGVcbiAgLy8gcGFzc2VkLWluIGFycmF5cy5cbiAgXy5pbnRlcnNlY3Rpb24gPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHZhciByZXN0ID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHJldHVybiBfLmZpbHRlcihfLnVuaXEoYXJyYXkpLCBmdW5jdGlvbihpdGVtKSB7XG4gICAgICByZXR1cm4gXy5ldmVyeShyZXN0LCBmdW5jdGlvbihvdGhlcikge1xuICAgICAgICByZXR1cm4gXy5pbmRleE9mKG90aGVyLCBpdGVtKSA+PSAwO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gVGFrZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG9uZSBhcnJheSBhbmQgYSBudW1iZXIgb2Ygb3RoZXIgYXJyYXlzLlxuICAvLyBPbmx5IHRoZSBlbGVtZW50cyBwcmVzZW50IGluIGp1c3QgdGhlIGZpcnN0IGFycmF5IHdpbGwgcmVtYWluLlxuICBfLmRpZmZlcmVuY2UgPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHZhciByZXN0ID0gY29uY2F0LmFwcGx5KEFycmF5UHJvdG8sIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gICAgcmV0dXJuIF8uZmlsdGVyKGFycmF5LCBmdW5jdGlvbih2YWx1ZSl7IHJldHVybiAhXy5jb250YWlucyhyZXN0LCB2YWx1ZSk7IH0pO1xuICB9O1xuXG4gIC8vIFppcCB0b2dldGhlciBtdWx0aXBsZSBsaXN0cyBpbnRvIGEgc2luZ2xlIGFycmF5IC0tIGVsZW1lbnRzIHRoYXQgc2hhcmVcbiAgLy8gYW4gaW5kZXggZ28gdG9nZXRoZXIuXG4gIF8uemlwID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGxlbmd0aCA9IF8ubWF4KF8ucGx1Y2soYXJndW1lbnRzLCBcImxlbmd0aFwiKS5jb25jYXQoMCkpO1xuICAgIHZhciByZXN1bHRzID0gbmV3IEFycmF5KGxlbmd0aCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgcmVzdWx0c1tpXSA9IF8ucGx1Y2soYXJndW1lbnRzLCAnJyArIGkpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfTtcblxuICAvLyBDb252ZXJ0cyBsaXN0cyBpbnRvIG9iamVjdHMuIFBhc3MgZWl0aGVyIGEgc2luZ2xlIGFycmF5IG9mIGBba2V5LCB2YWx1ZV1gXG4gIC8vIHBhaXJzLCBvciB0d28gcGFyYWxsZWwgYXJyYXlzIG9mIHRoZSBzYW1lIGxlbmd0aCAtLSBvbmUgb2Yga2V5cywgYW5kIG9uZSBvZlxuICAvLyB0aGUgY29ycmVzcG9uZGluZyB2YWx1ZXMuXG4gIF8ub2JqZWN0ID0gZnVuY3Rpb24obGlzdCwgdmFsdWVzKSB7XG4gICAgaWYgKGxpc3QgPT0gbnVsbCkgcmV0dXJuIHt9O1xuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0gbGlzdC5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHZhbHVlcykge1xuICAgICAgICByZXN1bHRbbGlzdFtpXV0gPSB2YWx1ZXNbaV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHRbbGlzdFtpXVswXV0gPSBsaXN0W2ldWzFdO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIC8vIElmIHRoZSBicm93c2VyIGRvZXNuJ3Qgc3VwcGx5IHVzIHdpdGggaW5kZXhPZiAoSSdtIGxvb2tpbmcgYXQgeW91LCAqKk1TSUUqKiksXG4gIC8vIHdlIG5lZWQgdGhpcyBmdW5jdGlvbi4gUmV0dXJuIHRoZSBwb3NpdGlvbiBvZiB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiBhblxuICAvLyBpdGVtIGluIGFuIGFycmF5LCBvciAtMSBpZiB0aGUgaXRlbSBpcyBub3QgaW5jbHVkZWQgaW4gdGhlIGFycmF5LlxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgaW5kZXhPZmAgaWYgYXZhaWxhYmxlLlxuICAvLyBJZiB0aGUgYXJyYXkgaXMgbGFyZ2UgYW5kIGFscmVhZHkgaW4gc29ydCBvcmRlciwgcGFzcyBgdHJ1ZWBcbiAgLy8gZm9yICoqaXNTb3J0ZWQqKiB0byB1c2UgYmluYXJ5IHNlYXJjaC5cbiAgXy5pbmRleE9mID0gZnVuY3Rpb24oYXJyYXksIGl0ZW0sIGlzU29ydGVkKSB7XG4gICAgaWYgKGFycmF5ID09IG51bGwpIHJldHVybiAtMTtcbiAgICB2YXIgaSA9IDAsIGxlbmd0aCA9IGFycmF5Lmxlbmd0aDtcbiAgICBpZiAoaXNTb3J0ZWQpIHtcbiAgICAgIGlmICh0eXBlb2YgaXNTb3J0ZWQgPT0gJ251bWJlcicpIHtcbiAgICAgICAgaSA9IChpc1NvcnRlZCA8IDAgPyBNYXRoLm1heCgwLCBsZW5ndGggKyBpc1NvcnRlZCkgOiBpc1NvcnRlZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpID0gXy5zb3J0ZWRJbmRleChhcnJheSwgaXRlbSk7XG4gICAgICAgIHJldHVybiBhcnJheVtpXSA9PT0gaXRlbSA/IGkgOiAtMTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKG5hdGl2ZUluZGV4T2YgJiYgYXJyYXkuaW5kZXhPZiA9PT0gbmF0aXZlSW5kZXhPZikgcmV0dXJuIGFycmF5LmluZGV4T2YoaXRlbSwgaXNTb3J0ZWQpO1xuICAgIGZvciAoOyBpIDwgbGVuZ3RoOyBpKyspIGlmIChhcnJheVtpXSA9PT0gaXRlbSkgcmV0dXJuIGk7XG4gICAgcmV0dXJuIC0xO1xuICB9O1xuXG4gIC8vIERlbGVnYXRlcyB0byAqKkVDTUFTY3JpcHQgNSoqJ3MgbmF0aXZlIGBsYXN0SW5kZXhPZmAgaWYgYXZhaWxhYmxlLlxuICBfLmxhc3RJbmRleE9mID0gZnVuY3Rpb24oYXJyYXksIGl0ZW0sIGZyb20pIHtcbiAgICBpZiAoYXJyYXkgPT0gbnVsbCkgcmV0dXJuIC0xO1xuICAgIHZhciBoYXNJbmRleCA9IGZyb20gIT0gbnVsbDtcbiAgICBpZiAobmF0aXZlTGFzdEluZGV4T2YgJiYgYXJyYXkubGFzdEluZGV4T2YgPT09IG5hdGl2ZUxhc3RJbmRleE9mKSB7XG4gICAgICByZXR1cm4gaGFzSW5kZXggPyBhcnJheS5sYXN0SW5kZXhPZihpdGVtLCBmcm9tKSA6IGFycmF5Lmxhc3RJbmRleE9mKGl0ZW0pO1xuICAgIH1cbiAgICB2YXIgaSA9IChoYXNJbmRleCA/IGZyb20gOiBhcnJheS5sZW5ndGgpO1xuICAgIHdoaWxlIChpLS0pIGlmIChhcnJheVtpXSA9PT0gaXRlbSkgcmV0dXJuIGk7XG4gICAgcmV0dXJuIC0xO1xuICB9O1xuXG4gIC8vIEdlbmVyYXRlIGFuIGludGVnZXIgQXJyYXkgY29udGFpbmluZyBhbiBhcml0aG1ldGljIHByb2dyZXNzaW9uLiBBIHBvcnQgb2ZcbiAgLy8gdGhlIG5hdGl2ZSBQeXRob24gYHJhbmdlKClgIGZ1bmN0aW9uLiBTZWVcbiAgLy8gW3RoZSBQeXRob24gZG9jdW1lbnRhdGlvbl0oaHR0cDovL2RvY3MucHl0aG9uLm9yZy9saWJyYXJ5L2Z1bmN0aW9ucy5odG1sI3JhbmdlKS5cbiAgXy5yYW5nZSA9IGZ1bmN0aW9uKHN0YXJ0LCBzdG9wLCBzdGVwKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPD0gMSkge1xuICAgICAgc3RvcCA9IHN0YXJ0IHx8IDA7XG4gICAgICBzdGFydCA9IDA7XG4gICAgfVxuICAgIHN0ZXAgPSBhcmd1bWVudHNbMl0gfHwgMTtcblxuICAgIHZhciBsZW5ndGggPSBNYXRoLm1heChNYXRoLmNlaWwoKHN0b3AgLSBzdGFydCkgLyBzdGVwKSwgMCk7XG4gICAgdmFyIGlkeCA9IDA7XG4gICAgdmFyIHJhbmdlID0gbmV3IEFycmF5KGxlbmd0aCk7XG5cbiAgICB3aGlsZShpZHggPCBsZW5ndGgpIHtcbiAgICAgIHJhbmdlW2lkeCsrXSA9IHN0YXJ0O1xuICAgICAgc3RhcnQgKz0gc3RlcDtcbiAgICB9XG5cbiAgICByZXR1cm4gcmFuZ2U7XG4gIH07XG5cbiAgLy8gRnVuY3Rpb24gKGFoZW0pIEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBSZXVzYWJsZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmb3IgcHJvdG90eXBlIHNldHRpbmcuXG4gIHZhciBjdG9yID0gZnVuY3Rpb24oKXt9O1xuXG4gIC8vIENyZWF0ZSBhIGZ1bmN0aW9uIGJvdW5kIHRvIGEgZ2l2ZW4gb2JqZWN0IChhc3NpZ25pbmcgYHRoaXNgLCBhbmQgYXJndW1lbnRzLFxuICAvLyBvcHRpb25hbGx5KS4gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYEZ1bmN0aW9uLmJpbmRgIGlmXG4gIC8vIGF2YWlsYWJsZS5cbiAgXy5iaW5kID0gZnVuY3Rpb24oZnVuYywgY29udGV4dCkge1xuICAgIHZhciBhcmdzLCBib3VuZDtcbiAgICBpZiAobmF0aXZlQmluZCAmJiBmdW5jLmJpbmQgPT09IG5hdGl2ZUJpbmQpIHJldHVybiBuYXRpdmVCaW5kLmFwcGx5KGZ1bmMsIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gICAgaWYgKCFfLmlzRnVuY3Rpb24oZnVuYykpIHRocm93IG5ldyBUeXBlRXJyb3I7XG4gICAgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAyKTtcbiAgICByZXR1cm4gYm91bmQgPSBmdW5jdGlvbigpIHtcbiAgICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBib3VuZCkpIHJldHVybiBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MuY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgY3Rvci5wcm90b3R5cGUgPSBmdW5jLnByb3RvdHlwZTtcbiAgICAgIHZhciBzZWxmID0gbmV3IGN0b3I7XG4gICAgICBjdG9yLnByb3RvdHlwZSA9IG51bGw7XG4gICAgICB2YXIgcmVzdWx0ID0gZnVuYy5hcHBseShzZWxmLCBhcmdzLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgIGlmIChPYmplY3QocmVzdWx0KSA9PT0gcmVzdWx0KSByZXR1cm4gcmVzdWx0O1xuICAgICAgcmV0dXJuIHNlbGY7XG4gICAgfTtcbiAgfTtcblxuICAvLyBQYXJ0aWFsbHkgYXBwbHkgYSBmdW5jdGlvbiBieSBjcmVhdGluZyBhIHZlcnNpb24gdGhhdCBoYXMgaGFkIHNvbWUgb2YgaXRzXG4gIC8vIGFyZ3VtZW50cyBwcmUtZmlsbGVkLCB3aXRob3V0IGNoYW5naW5nIGl0cyBkeW5hbWljIGB0aGlzYCBjb250ZXh0LlxuICBfLnBhcnRpYWwgPSBmdW5jdGlvbihmdW5jKSB7XG4gICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpcywgYXJncy5jb25jYXQoc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgfTtcbiAgfTtcblxuICAvLyBCaW5kIGFsbCBvZiBhbiBvYmplY3QncyBtZXRob2RzIHRvIHRoYXQgb2JqZWN0LiBVc2VmdWwgZm9yIGVuc3VyaW5nIHRoYXRcbiAgLy8gYWxsIGNhbGxiYWNrcyBkZWZpbmVkIG9uIGFuIG9iamVjdCBiZWxvbmcgdG8gaXQuXG4gIF8uYmluZEFsbCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciBmdW5jcyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICBpZiAoZnVuY3MubGVuZ3RoID09PSAwKSB0aHJvdyBuZXcgRXJyb3IoXCJiaW5kQWxsIG11c3QgYmUgcGFzc2VkIGZ1bmN0aW9uIG5hbWVzXCIpO1xuICAgIGVhY2goZnVuY3MsIGZ1bmN0aW9uKGYpIHsgb2JqW2ZdID0gXy5iaW5kKG9ialtmXSwgb2JqKTsgfSk7XG4gICAgcmV0dXJuIG9iajtcbiAgfTtcblxuICAvLyBNZW1vaXplIGFuIGV4cGVuc2l2ZSBmdW5jdGlvbiBieSBzdG9yaW5nIGl0cyByZXN1bHRzLlxuICBfLm1lbW9pemUgPSBmdW5jdGlvbihmdW5jLCBoYXNoZXIpIHtcbiAgICB2YXIgbWVtbyA9IHt9O1xuICAgIGhhc2hlciB8fCAoaGFzaGVyID0gXy5pZGVudGl0eSk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGtleSA9IGhhc2hlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgcmV0dXJuIF8uaGFzKG1lbW8sIGtleSkgPyBtZW1vW2tleV0gOiAobWVtb1trZXldID0gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpKTtcbiAgICB9O1xuICB9O1xuXG4gIC8vIERlbGF5cyBhIGZ1bmN0aW9uIGZvciB0aGUgZ2l2ZW4gbnVtYmVyIG9mIG1pbGxpc2Vjb25kcywgYW5kIHRoZW4gY2FsbHNcbiAgLy8gaXQgd2l0aCB0aGUgYXJndW1lbnRzIHN1cHBsaWVkLlxuICBfLmRlbGF5ID0gZnVuY3Rpb24oZnVuYywgd2FpdCkge1xuICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7IHJldHVybiBmdW5jLmFwcGx5KG51bGwsIGFyZ3MpOyB9LCB3YWl0KTtcbiAgfTtcblxuICAvLyBEZWZlcnMgYSBmdW5jdGlvbiwgc2NoZWR1bGluZyBpdCB0byBydW4gYWZ0ZXIgdGhlIGN1cnJlbnQgY2FsbCBzdGFjayBoYXNcbiAgLy8gY2xlYXJlZC5cbiAgXy5kZWZlciA9IGZ1bmN0aW9uKGZ1bmMpIHtcbiAgICByZXR1cm4gXy5kZWxheS5hcHBseShfLCBbZnVuYywgMV0uY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSkpO1xuICB9O1xuXG4gIC8vIFJldHVybnMgYSBmdW5jdGlvbiwgdGhhdCwgd2hlbiBpbnZva2VkLCB3aWxsIG9ubHkgYmUgdHJpZ2dlcmVkIGF0IG1vc3Qgb25jZVxuICAvLyBkdXJpbmcgYSBnaXZlbiB3aW5kb3cgb2YgdGltZS4gTm9ybWFsbHksIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gd2lsbCBydW5cbiAgLy8gYXMgbXVjaCBhcyBpdCBjYW4sIHdpdGhvdXQgZXZlciBnb2luZyBtb3JlIHRoYW4gb25jZSBwZXIgYHdhaXRgIGR1cmF0aW9uO1xuICAvLyBidXQgaWYgeW91J2QgbGlrZSB0byBkaXNhYmxlIHRoZSBleGVjdXRpb24gb24gdGhlIGxlYWRpbmcgZWRnZSwgcGFzc1xuICAvLyBge2xlYWRpbmc6IGZhbHNlfWAuIFRvIGRpc2FibGUgZXhlY3V0aW9uIG9uIHRoZSB0cmFpbGluZyBlZGdlLCBkaXR0by5cbiAgXy50aHJvdHRsZSA9IGZ1bmN0aW9uKGZ1bmMsIHdhaXQsIG9wdGlvbnMpIHtcbiAgICB2YXIgY29udGV4dCwgYXJncywgcmVzdWx0O1xuICAgIHZhciB0aW1lb3V0ID0gbnVsbDtcbiAgICB2YXIgcHJldmlvdXMgPSAwO1xuICAgIG9wdGlvbnMgfHwgKG9wdGlvbnMgPSB7fSk7XG4gICAgdmFyIGxhdGVyID0gZnVuY3Rpb24oKSB7XG4gICAgICBwcmV2aW91cyA9IG9wdGlvbnMubGVhZGluZyA9PT0gZmFsc2UgPyAwIDogbmV3IERhdGU7XG4gICAgICB0aW1lb3V0ID0gbnVsbDtcbiAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgfTtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgbm93ID0gbmV3IERhdGU7XG4gICAgICBpZiAoIXByZXZpb3VzICYmIG9wdGlvbnMubGVhZGluZyA9PT0gZmFsc2UpIHByZXZpb3VzID0gbm93O1xuICAgICAgdmFyIHJlbWFpbmluZyA9IHdhaXQgLSAobm93IC0gcHJldmlvdXMpO1xuICAgICAgY29udGV4dCA9IHRoaXM7XG4gICAgICBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgaWYgKHJlbWFpbmluZyA8PSAwKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgIHByZXZpb3VzID0gbm93O1xuICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgfSBlbHNlIGlmICghdGltZW91dCAmJiBvcHRpb25zLnRyYWlsaW5nICE9PSBmYWxzZSkge1xuICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgcmVtYWluaW5nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIGEgZnVuY3Rpb24sIHRoYXQsIGFzIGxvbmcgYXMgaXQgY29udGludWVzIHRvIGJlIGludm9rZWQsIHdpbGwgbm90XG4gIC8vIGJlIHRyaWdnZXJlZC4gVGhlIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIGFmdGVyIGl0IHN0b3BzIGJlaW5nIGNhbGxlZCBmb3JcbiAgLy8gTiBtaWxsaXNlY29uZHMuIElmIGBpbW1lZGlhdGVgIGlzIHBhc3NlZCwgdHJpZ2dlciB0aGUgZnVuY3Rpb24gb24gdGhlXG4gIC8vIGxlYWRpbmcgZWRnZSwgaW5zdGVhZCBvZiB0aGUgdHJhaWxpbmcuXG4gIF8uZGVib3VuY2UgPSBmdW5jdGlvbihmdW5jLCB3YWl0LCBpbW1lZGlhdGUpIHtcbiAgICB2YXIgdGltZW91dCwgYXJncywgY29udGV4dCwgdGltZXN0YW1wLCByZXN1bHQ7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgY29udGV4dCA9IHRoaXM7XG4gICAgICBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgdGltZXN0YW1wID0gbmV3IERhdGUoKTtcbiAgICAgIHZhciBsYXRlciA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgbGFzdCA9IChuZXcgRGF0ZSgpKSAtIHRpbWVzdGFtcDtcbiAgICAgICAgaWYgKGxhc3QgPCB3YWl0KSB7XG4gICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQgLSBsYXN0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aW1lb3V0ID0gbnVsbDtcbiAgICAgICAgICBpZiAoIWltbWVkaWF0ZSkgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICAgIHZhciBjYWxsTm93ID0gaW1tZWRpYXRlICYmICF0aW1lb3V0O1xuICAgICAgaWYgKCF0aW1lb3V0KSB7XG4gICAgICAgIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGxhdGVyLCB3YWl0KTtcbiAgICAgIH1cbiAgICAgIGlmIChjYWxsTm93KSByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICB9O1xuXG4gIC8vIFJldHVybnMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgZXhlY3V0ZWQgYXQgbW9zdCBvbmUgdGltZSwgbm8gbWF0dGVyIGhvd1xuICAvLyBvZnRlbiB5b3UgY2FsbCBpdC4gVXNlZnVsIGZvciBsYXp5IGluaXRpYWxpemF0aW9uLlxuICBfLm9uY2UgPSBmdW5jdGlvbihmdW5jKSB7XG4gICAgdmFyIHJhbiA9IGZhbHNlLCBtZW1vO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIGlmIChyYW4pIHJldHVybiBtZW1vO1xuICAgICAgcmFuID0gdHJ1ZTtcbiAgICAgIG1lbW8gPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICBmdW5jID0gbnVsbDtcbiAgICAgIHJldHVybiBtZW1vO1xuICAgIH07XG4gIH07XG5cbiAgLy8gUmV0dXJucyB0aGUgZmlyc3QgZnVuY3Rpb24gcGFzc2VkIGFzIGFuIGFyZ3VtZW50IHRvIHRoZSBzZWNvbmQsXG4gIC8vIGFsbG93aW5nIHlvdSB0byBhZGp1c3QgYXJndW1lbnRzLCBydW4gY29kZSBiZWZvcmUgYW5kIGFmdGVyLCBhbmRcbiAgLy8gY29uZGl0aW9uYWxseSBleGVjdXRlIHRoZSBvcmlnaW5hbCBmdW5jdGlvbi5cbiAgXy53cmFwID0gZnVuY3Rpb24oZnVuYywgd3JhcHBlcikge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBhcmdzID0gW2Z1bmNdO1xuICAgICAgcHVzaC5hcHBseShhcmdzLCBhcmd1bWVudHMpO1xuICAgICAgcmV0dXJuIHdyYXBwZXIuYXBwbHkodGhpcywgYXJncyk7XG4gICAgfTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCBpcyB0aGUgY29tcG9zaXRpb24gb2YgYSBsaXN0IG9mIGZ1bmN0aW9ucywgZWFjaFxuICAvLyBjb25zdW1pbmcgdGhlIHJldHVybiB2YWx1ZSBvZiB0aGUgZnVuY3Rpb24gdGhhdCBmb2xsb3dzLlxuICBfLmNvbXBvc2UgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgZnVuY3MgPSBhcmd1bWVudHM7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICBmb3IgKHZhciBpID0gZnVuY3MubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgYXJncyA9IFtmdW5jc1tpXS5hcHBseSh0aGlzLCBhcmdzKV07XG4gICAgICB9XG4gICAgICByZXR1cm4gYXJnc1swXTtcbiAgICB9O1xuICB9O1xuXG4gIC8vIFJldHVybnMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgb25seSBiZSBleGVjdXRlZCBhZnRlciBiZWluZyBjYWxsZWQgTiB0aW1lcy5cbiAgXy5hZnRlciA9IGZ1bmN0aW9uKHRpbWVzLCBmdW5jKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKC0tdGltZXMgPCAxKSB7XG4gICAgICAgIHJldHVybiBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICB9XG4gICAgfTtcbiAgfTtcblxuICAvLyBPYmplY3QgRnVuY3Rpb25zXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBSZXRyaWV2ZSB0aGUgbmFtZXMgb2YgYW4gb2JqZWN0J3MgcHJvcGVydGllcy5cbiAgLy8gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYE9iamVjdC5rZXlzYFxuICBfLmtleXMgPSBuYXRpdmVLZXlzIHx8IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmIChvYmogIT09IE9iamVjdChvYmopKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIG9iamVjdCcpO1xuICAgIHZhciBrZXlzID0gW107XG4gICAgZm9yICh2YXIga2V5IGluIG9iaikgaWYgKF8uaGFzKG9iaiwga2V5KSkga2V5cy5wdXNoKGtleSk7XG4gICAgcmV0dXJuIGtleXM7XG4gIH07XG5cbiAgLy8gUmV0cmlldmUgdGhlIHZhbHVlcyBvZiBhbiBvYmplY3QncyBwcm9wZXJ0aWVzLlxuICBfLnZhbHVlcyA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciBrZXlzID0gXy5rZXlzKG9iaik7XG4gICAgdmFyIGxlbmd0aCA9IGtleXMubGVuZ3RoO1xuICAgIHZhciB2YWx1ZXMgPSBuZXcgQXJyYXkobGVuZ3RoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB2YWx1ZXNbaV0gPSBvYmpba2V5c1tpXV07XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZXM7XG4gIH07XG5cbiAgLy8gQ29udmVydCBhbiBvYmplY3QgaW50byBhIGxpc3Qgb2YgYFtrZXksIHZhbHVlXWAgcGFpcnMuXG4gIF8ucGFpcnMgPSBmdW5jdGlvbihvYmopIHtcbiAgICB2YXIga2V5cyA9IF8ua2V5cyhvYmopO1xuICAgIHZhciBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgICB2YXIgcGFpcnMgPSBuZXcgQXJyYXkobGVuZ3RoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICBwYWlyc1tpXSA9IFtrZXlzW2ldLCBvYmpba2V5c1tpXV1dO1xuICAgIH1cbiAgICByZXR1cm4gcGFpcnM7XG4gIH07XG5cbiAgLy8gSW52ZXJ0IHRoZSBrZXlzIGFuZCB2YWx1ZXMgb2YgYW4gb2JqZWN0LiBUaGUgdmFsdWVzIG11c3QgYmUgc2VyaWFsaXphYmxlLlxuICBfLmludmVydCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICB2YXIga2V5cyA9IF8ua2V5cyhvYmopO1xuICAgIGZvciAodmFyIGkgPSAwLCBsZW5ndGggPSBrZXlzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICByZXN1bHRbb2JqW2tleXNbaV1dXSA9IGtleXNbaV07XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gUmV0dXJuIGEgc29ydGVkIGxpc3Qgb2YgdGhlIGZ1bmN0aW9uIG5hbWVzIGF2YWlsYWJsZSBvbiB0aGUgb2JqZWN0LlxuICAvLyBBbGlhc2VkIGFzIGBtZXRob2RzYFxuICBfLmZ1bmN0aW9ucyA9IF8ubWV0aG9kcyA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciBuYW1lcyA9IFtdO1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIHtcbiAgICAgIGlmIChfLmlzRnVuY3Rpb24ob2JqW2tleV0pKSBuYW1lcy5wdXNoKGtleSk7XG4gICAgfVxuICAgIHJldHVybiBuYW1lcy5zb3J0KCk7XG4gIH07XG5cbiAgLy8gRXh0ZW5kIGEgZ2l2ZW4gb2JqZWN0IHdpdGggYWxsIHRoZSBwcm9wZXJ0aWVzIGluIHBhc3NlZC1pbiBvYmplY3QocykuXG4gIF8uZXh0ZW5kID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgZWFjaChzbGljZS5jYWxsKGFyZ3VtZW50cywgMSksIGZ1bmN0aW9uKHNvdXJjZSkge1xuICAgICAgaWYgKHNvdXJjZSkge1xuICAgICAgICBmb3IgKHZhciBwcm9wIGluIHNvdXJjZSkge1xuICAgICAgICAgIG9ialtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBvYmo7XG4gIH07XG5cbiAgLy8gUmV0dXJuIGEgY29weSBvZiB0aGUgb2JqZWN0IG9ubHkgY29udGFpbmluZyB0aGUgd2hpdGVsaXN0ZWQgcHJvcGVydGllcy5cbiAgXy5waWNrID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgdmFyIGNvcHkgPSB7fTtcbiAgICB2YXIga2V5cyA9IGNvbmNhdC5hcHBseShBcnJheVByb3RvLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpO1xuICAgIGVhY2goa2V5cywgZnVuY3Rpb24oa2V5KSB7XG4gICAgICBpZiAoa2V5IGluIG9iaikgY29weVtrZXldID0gb2JqW2tleV07XG4gICAgfSk7XG4gICAgcmV0dXJuIGNvcHk7XG4gIH07XG5cbiAgIC8vIFJldHVybiBhIGNvcHkgb2YgdGhlIG9iamVjdCB3aXRob3V0IHRoZSBibGFja2xpc3RlZCBwcm9wZXJ0aWVzLlxuICBfLm9taXQgPSBmdW5jdGlvbihvYmopIHtcbiAgICB2YXIgY29weSA9IHt9O1xuICAgIHZhciBrZXlzID0gY29uY2F0LmFwcGx5KEFycmF5UHJvdG8sIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gICAgZm9yICh2YXIga2V5IGluIG9iaikge1xuICAgICAgaWYgKCFfLmNvbnRhaW5zKGtleXMsIGtleSkpIGNvcHlba2V5XSA9IG9ialtrZXldO1xuICAgIH1cbiAgICByZXR1cm4gY29weTtcbiAgfTtcblxuICAvLyBGaWxsIGluIGEgZ2l2ZW4gb2JqZWN0IHdpdGggZGVmYXVsdCBwcm9wZXJ0aWVzLlxuICBfLmRlZmF1bHRzID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgZWFjaChzbGljZS5jYWxsKGFyZ3VtZW50cywgMSksIGZ1bmN0aW9uKHNvdXJjZSkge1xuICAgICAgaWYgKHNvdXJjZSkge1xuICAgICAgICBmb3IgKHZhciBwcm9wIGluIHNvdXJjZSkge1xuICAgICAgICAgIGlmIChvYmpbcHJvcF0gPT09IHZvaWQgMCkgb2JqW3Byb3BdID0gc291cmNlW3Byb3BdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIG9iajtcbiAgfTtcblxuICAvLyBDcmVhdGUgYSAoc2hhbGxvdy1jbG9uZWQpIGR1cGxpY2F0ZSBvZiBhbiBvYmplY3QuXG4gIF8uY2xvbmUgPSBmdW5jdGlvbihvYmopIHtcbiAgICBpZiAoIV8uaXNPYmplY3Qob2JqKSkgcmV0dXJuIG9iajtcbiAgICByZXR1cm4gXy5pc0FycmF5KG9iaikgPyBvYmouc2xpY2UoKSA6IF8uZXh0ZW5kKHt9LCBvYmopO1xuICB9O1xuXG4gIC8vIEludm9rZXMgaW50ZXJjZXB0b3Igd2l0aCB0aGUgb2JqLCBhbmQgdGhlbiByZXR1cm5zIG9iai5cbiAgLy8gVGhlIHByaW1hcnkgcHVycG9zZSBvZiB0aGlzIG1ldGhvZCBpcyB0byBcInRhcCBpbnRvXCIgYSBtZXRob2QgY2hhaW4sIGluXG4gIC8vIG9yZGVyIHRvIHBlcmZvcm0gb3BlcmF0aW9ucyBvbiBpbnRlcm1lZGlhdGUgcmVzdWx0cyB3aXRoaW4gdGhlIGNoYWluLlxuICBfLnRhcCA9IGZ1bmN0aW9uKG9iaiwgaW50ZXJjZXB0b3IpIHtcbiAgICBpbnRlcmNlcHRvcihvYmopO1xuICAgIHJldHVybiBvYmo7XG4gIH07XG5cbiAgLy8gSW50ZXJuYWwgcmVjdXJzaXZlIGNvbXBhcmlzb24gZnVuY3Rpb24gZm9yIGBpc0VxdWFsYC5cbiAgdmFyIGVxID0gZnVuY3Rpb24oYSwgYiwgYVN0YWNrLCBiU3RhY2spIHtcbiAgICAvLyBJZGVudGljYWwgb2JqZWN0cyBhcmUgZXF1YWwuIGAwID09PSAtMGAsIGJ1dCB0aGV5IGFyZW4ndCBpZGVudGljYWwuXG4gICAgLy8gU2VlIHRoZSBbSGFybW9ueSBgZWdhbGAgcHJvcG9zYWxdKGh0dHA6Ly93aWtpLmVjbWFzY3JpcHQub3JnL2Rva3UucGhwP2lkPWhhcm1vbnk6ZWdhbCkuXG4gICAgaWYgKGEgPT09IGIpIHJldHVybiBhICE9PSAwIHx8IDEgLyBhID09IDEgLyBiO1xuICAgIC8vIEEgc3RyaWN0IGNvbXBhcmlzb24gaXMgbmVjZXNzYXJ5IGJlY2F1c2UgYG51bGwgPT0gdW5kZWZpbmVkYC5cbiAgICBpZiAoYSA9PSBudWxsIHx8IGIgPT0gbnVsbCkgcmV0dXJuIGEgPT09IGI7XG4gICAgLy8gVW53cmFwIGFueSB3cmFwcGVkIG9iamVjdHMuXG4gICAgaWYgKGEgaW5zdGFuY2VvZiBfKSBhID0gYS5fd3JhcHBlZDtcbiAgICBpZiAoYiBpbnN0YW5jZW9mIF8pIGIgPSBiLl93cmFwcGVkO1xuICAgIC8vIENvbXBhcmUgYFtbQ2xhc3NdXWAgbmFtZXMuXG4gICAgdmFyIGNsYXNzTmFtZSA9IHRvU3RyaW5nLmNhbGwoYSk7XG4gICAgaWYgKGNsYXNzTmFtZSAhPSB0b1N0cmluZy5jYWxsKGIpKSByZXR1cm4gZmFsc2U7XG4gICAgc3dpdGNoIChjbGFzc05hbWUpIHtcbiAgICAgIC8vIFN0cmluZ3MsIG51bWJlcnMsIGRhdGVzLCBhbmQgYm9vbGVhbnMgYXJlIGNvbXBhcmVkIGJ5IHZhbHVlLlxuICAgICAgY2FzZSAnW29iamVjdCBTdHJpbmddJzpcbiAgICAgICAgLy8gUHJpbWl0aXZlcyBhbmQgdGhlaXIgY29ycmVzcG9uZGluZyBvYmplY3Qgd3JhcHBlcnMgYXJlIGVxdWl2YWxlbnQ7IHRodXMsIGBcIjVcImAgaXNcbiAgICAgICAgLy8gZXF1aXZhbGVudCB0byBgbmV3IFN0cmluZyhcIjVcIilgLlxuICAgICAgICByZXR1cm4gYSA9PSBTdHJpbmcoYik7XG4gICAgICBjYXNlICdbb2JqZWN0IE51bWJlcl0nOlxuICAgICAgICAvLyBgTmFOYHMgYXJlIGVxdWl2YWxlbnQsIGJ1dCBub24tcmVmbGV4aXZlLiBBbiBgZWdhbGAgY29tcGFyaXNvbiBpcyBwZXJmb3JtZWQgZm9yXG4gICAgICAgIC8vIG90aGVyIG51bWVyaWMgdmFsdWVzLlxuICAgICAgICByZXR1cm4gYSAhPSArYSA/IGIgIT0gK2IgOiAoYSA9PSAwID8gMSAvIGEgPT0gMSAvIGIgOiBhID09ICtiKTtcbiAgICAgIGNhc2UgJ1tvYmplY3QgRGF0ZV0nOlxuICAgICAgY2FzZSAnW29iamVjdCBCb29sZWFuXSc6XG4gICAgICAgIC8vIENvZXJjZSBkYXRlcyBhbmQgYm9vbGVhbnMgdG8gbnVtZXJpYyBwcmltaXRpdmUgdmFsdWVzLiBEYXRlcyBhcmUgY29tcGFyZWQgYnkgdGhlaXJcbiAgICAgICAgLy8gbWlsbGlzZWNvbmQgcmVwcmVzZW50YXRpb25zLiBOb3RlIHRoYXQgaW52YWxpZCBkYXRlcyB3aXRoIG1pbGxpc2Vjb25kIHJlcHJlc2VudGF0aW9uc1xuICAgICAgICAvLyBvZiBgTmFOYCBhcmUgbm90IGVxdWl2YWxlbnQuXG4gICAgICAgIHJldHVybiArYSA9PSArYjtcbiAgICAgIC8vIFJlZ0V4cHMgYXJlIGNvbXBhcmVkIGJ5IHRoZWlyIHNvdXJjZSBwYXR0ZXJucyBhbmQgZmxhZ3MuXG4gICAgICBjYXNlICdbb2JqZWN0IFJlZ0V4cF0nOlxuICAgICAgICByZXR1cm4gYS5zb3VyY2UgPT0gYi5zb3VyY2UgJiZcbiAgICAgICAgICAgICAgIGEuZ2xvYmFsID09IGIuZ2xvYmFsICYmXG4gICAgICAgICAgICAgICBhLm11bHRpbGluZSA9PSBiLm11bHRpbGluZSAmJlxuICAgICAgICAgICAgICAgYS5pZ25vcmVDYXNlID09IGIuaWdub3JlQ2FzZTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBhICE9ICdvYmplY3QnIHx8IHR5cGVvZiBiICE9ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG4gICAgLy8gQXNzdW1lIGVxdWFsaXR5IGZvciBjeWNsaWMgc3RydWN0dXJlcy4gVGhlIGFsZ29yaXRobSBmb3IgZGV0ZWN0aW5nIGN5Y2xpY1xuICAgIC8vIHN0cnVjdHVyZXMgaXMgYWRhcHRlZCBmcm9tIEVTIDUuMSBzZWN0aW9uIDE1LjEyLjMsIGFic3RyYWN0IG9wZXJhdGlvbiBgSk9gLlxuICAgIHZhciBsZW5ndGggPSBhU3RhY2subGVuZ3RoO1xuICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgLy8gTGluZWFyIHNlYXJjaC4gUGVyZm9ybWFuY2UgaXMgaW52ZXJzZWx5IHByb3BvcnRpb25hbCB0byB0aGUgbnVtYmVyIG9mXG4gICAgICAvLyB1bmlxdWUgbmVzdGVkIHN0cnVjdHVyZXMuXG4gICAgICBpZiAoYVN0YWNrW2xlbmd0aF0gPT0gYSkgcmV0dXJuIGJTdGFja1tsZW5ndGhdID09IGI7XG4gICAgfVxuICAgIC8vIE9iamVjdHMgd2l0aCBkaWZmZXJlbnQgY29uc3RydWN0b3JzIGFyZSBub3QgZXF1aXZhbGVudCwgYnV0IGBPYmplY3Rgc1xuICAgIC8vIGZyb20gZGlmZmVyZW50IGZyYW1lcyBhcmUuXG4gICAgdmFyIGFDdG9yID0gYS5jb25zdHJ1Y3RvciwgYkN0b3IgPSBiLmNvbnN0cnVjdG9yO1xuICAgIGlmIChhQ3RvciAhPT0gYkN0b3IgJiYgIShfLmlzRnVuY3Rpb24oYUN0b3IpICYmIChhQ3RvciBpbnN0YW5jZW9mIGFDdG9yKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBfLmlzRnVuY3Rpb24oYkN0b3IpICYmIChiQ3RvciBpbnN0YW5jZW9mIGJDdG9yKSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gQWRkIHRoZSBmaXJzdCBvYmplY3QgdG8gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzLlxuICAgIGFTdGFjay5wdXNoKGEpO1xuICAgIGJTdGFjay5wdXNoKGIpO1xuICAgIHZhciBzaXplID0gMCwgcmVzdWx0ID0gdHJ1ZTtcbiAgICAvLyBSZWN1cnNpdmVseSBjb21wYXJlIG9iamVjdHMgYW5kIGFycmF5cy5cbiAgICBpZiAoY2xhc3NOYW1lID09ICdbb2JqZWN0IEFycmF5XScpIHtcbiAgICAgIC8vIENvbXBhcmUgYXJyYXkgbGVuZ3RocyB0byBkZXRlcm1pbmUgaWYgYSBkZWVwIGNvbXBhcmlzb24gaXMgbmVjZXNzYXJ5LlxuICAgICAgc2l6ZSA9IGEubGVuZ3RoO1xuICAgICAgcmVzdWx0ID0gc2l6ZSA9PSBiLmxlbmd0aDtcbiAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgLy8gRGVlcCBjb21wYXJlIHRoZSBjb250ZW50cywgaWdub3Jpbmcgbm9uLW51bWVyaWMgcHJvcGVydGllcy5cbiAgICAgICAgd2hpbGUgKHNpemUtLSkge1xuICAgICAgICAgIGlmICghKHJlc3VsdCA9IGVxKGFbc2l6ZV0sIGJbc2l6ZV0sIGFTdGFjaywgYlN0YWNrKSkpIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIERlZXAgY29tcGFyZSBvYmplY3RzLlxuICAgICAgZm9yICh2YXIga2V5IGluIGEpIHtcbiAgICAgICAgaWYgKF8uaGFzKGEsIGtleSkpIHtcbiAgICAgICAgICAvLyBDb3VudCB0aGUgZXhwZWN0ZWQgbnVtYmVyIG9mIHByb3BlcnRpZXMuXG4gICAgICAgICAgc2l6ZSsrO1xuICAgICAgICAgIC8vIERlZXAgY29tcGFyZSBlYWNoIG1lbWJlci5cbiAgICAgICAgICBpZiAoIShyZXN1bHQgPSBfLmhhcyhiLCBrZXkpICYmIGVxKGFba2V5XSwgYltrZXldLCBhU3RhY2ssIGJTdGFjaykpKSBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gRW5zdXJlIHRoYXQgYm90aCBvYmplY3RzIGNvbnRhaW4gdGhlIHNhbWUgbnVtYmVyIG9mIHByb3BlcnRpZXMuXG4gICAgICBpZiAocmVzdWx0KSB7XG4gICAgICAgIGZvciAoa2V5IGluIGIpIHtcbiAgICAgICAgICBpZiAoXy5oYXMoYiwga2V5KSAmJiAhKHNpemUtLSkpIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdCA9ICFzaXplO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBSZW1vdmUgdGhlIGZpcnN0IG9iamVjdCBmcm9tIHRoZSBzdGFjayBvZiB0cmF2ZXJzZWQgb2JqZWN0cy5cbiAgICBhU3RhY2sucG9wKCk7XG4gICAgYlN0YWNrLnBvcCgpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gUGVyZm9ybSBhIGRlZXAgY29tcGFyaXNvbiB0byBjaGVjayBpZiB0d28gb2JqZWN0cyBhcmUgZXF1YWwuXG4gIF8uaXNFcXVhbCA9IGZ1bmN0aW9uKGEsIGIpIHtcbiAgICByZXR1cm4gZXEoYSwgYiwgW10sIFtdKTtcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIGFycmF5LCBzdHJpbmcsIG9yIG9iamVjdCBlbXB0eT9cbiAgLy8gQW4gXCJlbXB0eVwiIG9iamVjdCBoYXMgbm8gZW51bWVyYWJsZSBvd24tcHJvcGVydGllcy5cbiAgXy5pc0VtcHR5ID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAoXy5pc0FycmF5KG9iaikgfHwgXy5pc1N0cmluZyhvYmopKSByZXR1cm4gb2JqLmxlbmd0aCA9PT0gMDtcbiAgICBmb3IgKHZhciBrZXkgaW4gb2JqKSBpZiAoXy5oYXMob2JqLCBrZXkpKSByZXR1cm4gZmFsc2U7XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gSXMgYSBnaXZlbiB2YWx1ZSBhIERPTSBlbGVtZW50P1xuICBfLmlzRWxlbWVudCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiAhIShvYmogJiYgb2JqLm5vZGVUeXBlID09PSAxKTtcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIHZhbHVlIGFuIGFycmF5P1xuICAvLyBEZWxlZ2F0ZXMgdG8gRUNNQTUncyBuYXRpdmUgQXJyYXkuaXNBcnJheVxuICBfLmlzQXJyYXkgPSBuYXRpdmVJc0FycmF5IHx8IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiB0b1N0cmluZy5jYWxsKG9iaikgPT0gJ1tvYmplY3QgQXJyYXldJztcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIHZhcmlhYmxlIGFuIG9iamVjdD9cbiAgXy5pc09iamVjdCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBvYmogPT09IE9iamVjdChvYmopO1xuICB9O1xuXG4gIC8vIEFkZCBzb21lIGlzVHlwZSBtZXRob2RzOiBpc0FyZ3VtZW50cywgaXNGdW5jdGlvbiwgaXNTdHJpbmcsIGlzTnVtYmVyLCBpc0RhdGUsIGlzUmVnRXhwLlxuICBlYWNoKFsnQXJndW1lbnRzJywgJ0Z1bmN0aW9uJywgJ1N0cmluZycsICdOdW1iZXInLCAnRGF0ZScsICdSZWdFeHAnXSwgZnVuY3Rpb24obmFtZSkge1xuICAgIF9bJ2lzJyArIG5hbWVdID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgICByZXR1cm4gdG9TdHJpbmcuY2FsbChvYmopID09ICdbb2JqZWN0ICcgKyBuYW1lICsgJ10nO1xuICAgIH07XG4gIH0pO1xuXG4gIC8vIERlZmluZSBhIGZhbGxiYWNrIHZlcnNpb24gb2YgdGhlIG1ldGhvZCBpbiBicm93c2VycyAoYWhlbSwgSUUpLCB3aGVyZVxuICAvLyB0aGVyZSBpc24ndCBhbnkgaW5zcGVjdGFibGUgXCJBcmd1bWVudHNcIiB0eXBlLlxuICBpZiAoIV8uaXNBcmd1bWVudHMoYXJndW1lbnRzKSkge1xuICAgIF8uaXNBcmd1bWVudHMgPSBmdW5jdGlvbihvYmopIHtcbiAgICAgIHJldHVybiAhIShvYmogJiYgXy5oYXMob2JqLCAnY2FsbGVlJykpO1xuICAgIH07XG4gIH1cblxuICAvLyBPcHRpbWl6ZSBgaXNGdW5jdGlvbmAgaWYgYXBwcm9wcmlhdGUuXG4gIGlmICh0eXBlb2YgKC8uLykgIT09ICdmdW5jdGlvbicpIHtcbiAgICBfLmlzRnVuY3Rpb24gPSBmdW5jdGlvbihvYmopIHtcbiAgICAgIHJldHVybiB0eXBlb2Ygb2JqID09PSAnZnVuY3Rpb24nO1xuICAgIH07XG4gIH1cblxuICAvLyBJcyBhIGdpdmVuIG9iamVjdCBhIGZpbml0ZSBudW1iZXI/XG4gIF8uaXNGaW5pdGUgPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gaXNGaW5pdGUob2JqKSAmJiAhaXNOYU4ocGFyc2VGbG9hdChvYmopKTtcbiAgfTtcblxuICAvLyBJcyB0aGUgZ2l2ZW4gdmFsdWUgYE5hTmA/IChOYU4gaXMgdGhlIG9ubHkgbnVtYmVyIHdoaWNoIGRvZXMgbm90IGVxdWFsIGl0c2VsZikuXG4gIF8uaXNOYU4gPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gXy5pc051bWJlcihvYmopICYmIG9iaiAhPSArb2JqO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFsdWUgYSBib29sZWFuP1xuICBfLmlzQm9vbGVhbiA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBvYmogPT09IHRydWUgfHwgb2JqID09PSBmYWxzZSB8fCB0b1N0cmluZy5jYWxsKG9iaikgPT0gJ1tvYmplY3QgQm9vbGVhbl0nO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFsdWUgZXF1YWwgdG8gbnVsbD9cbiAgXy5pc051bGwgPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gb2JqID09PSBudWxsO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFyaWFibGUgdW5kZWZpbmVkP1xuICBfLmlzVW5kZWZpbmVkID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgcmV0dXJuIG9iaiA9PT0gdm9pZCAwO1xuICB9O1xuXG4gIC8vIFNob3J0Y3V0IGZ1bmN0aW9uIGZvciBjaGVja2luZyBpZiBhbiBvYmplY3QgaGFzIGEgZ2l2ZW4gcHJvcGVydHkgZGlyZWN0bHlcbiAgLy8gb24gaXRzZWxmIChpbiBvdGhlciB3b3Jkcywgbm90IG9uIGEgcHJvdG90eXBlKS5cbiAgXy5oYXMgPSBmdW5jdGlvbihvYmosIGtleSkge1xuICAgIHJldHVybiBoYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KTtcbiAgfTtcblxuICAvLyBVdGlsaXR5IEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIFJ1biBVbmRlcnNjb3JlLmpzIGluICpub0NvbmZsaWN0KiBtb2RlLCByZXR1cm5pbmcgdGhlIGBfYCB2YXJpYWJsZSB0byBpdHNcbiAgLy8gcHJldmlvdXMgb3duZXIuIFJldHVybnMgYSByZWZlcmVuY2UgdG8gdGhlIFVuZGVyc2NvcmUgb2JqZWN0LlxuICBfLm5vQ29uZmxpY3QgPSBmdW5jdGlvbigpIHtcbiAgICByb290Ll8gPSBwcmV2aW91c1VuZGVyc2NvcmU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgLy8gS2VlcCB0aGUgaWRlbnRpdHkgZnVuY3Rpb24gYXJvdW5kIGZvciBkZWZhdWx0IGl0ZXJhdG9ycy5cbiAgXy5pZGVudGl0eSA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9O1xuXG4gIC8vIFJ1biBhIGZ1bmN0aW9uICoqbioqIHRpbWVzLlxuICBfLnRpbWVzID0gZnVuY3Rpb24obiwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICB2YXIgYWNjdW0gPSBBcnJheShNYXRoLm1heCgwLCBuKSk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpKyspIGFjY3VtW2ldID0gaXRlcmF0b3IuY2FsbChjb250ZXh0LCBpKTtcbiAgICByZXR1cm4gYWNjdW07XG4gIH07XG5cbiAgLy8gUmV0dXJuIGEgcmFuZG9tIGludGVnZXIgYmV0d2VlbiBtaW4gYW5kIG1heCAoaW5jbHVzaXZlKS5cbiAgXy5yYW5kb20gPSBmdW5jdGlvbihtaW4sIG1heCkge1xuICAgIGlmIChtYXggPT0gbnVsbCkge1xuICAgICAgbWF4ID0gbWluO1xuICAgICAgbWluID0gMDtcbiAgICB9XG4gICAgcmV0dXJuIG1pbiArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIChtYXggLSBtaW4gKyAxKSk7XG4gIH07XG5cbiAgLy8gTGlzdCBvZiBIVE1MIGVudGl0aWVzIGZvciBlc2NhcGluZy5cbiAgdmFyIGVudGl0eU1hcCA9IHtcbiAgICBlc2NhcGU6IHtcbiAgICAgICcmJzogJyZhbXA7JyxcbiAgICAgICc8JzogJyZsdDsnLFxuICAgICAgJz4nOiAnJmd0OycsXG4gICAgICAnXCInOiAnJnF1b3Q7JyxcbiAgICAgIFwiJ1wiOiAnJiN4Mjc7J1xuICAgIH1cbiAgfTtcbiAgZW50aXR5TWFwLnVuZXNjYXBlID0gXy5pbnZlcnQoZW50aXR5TWFwLmVzY2FwZSk7XG5cbiAgLy8gUmVnZXhlcyBjb250YWluaW5nIHRoZSBrZXlzIGFuZCB2YWx1ZXMgbGlzdGVkIGltbWVkaWF0ZWx5IGFib3ZlLlxuICB2YXIgZW50aXR5UmVnZXhlcyA9IHtcbiAgICBlc2NhcGU6ICAgbmV3IFJlZ0V4cCgnWycgKyBfLmtleXMoZW50aXR5TWFwLmVzY2FwZSkuam9pbignJykgKyAnXScsICdnJyksXG4gICAgdW5lc2NhcGU6IG5ldyBSZWdFeHAoJygnICsgXy5rZXlzKGVudGl0eU1hcC51bmVzY2FwZSkuam9pbignfCcpICsgJyknLCAnZycpXG4gIH07XG5cbiAgLy8gRnVuY3Rpb25zIGZvciBlc2NhcGluZyBhbmQgdW5lc2NhcGluZyBzdHJpbmdzIHRvL2Zyb20gSFRNTCBpbnRlcnBvbGF0aW9uLlxuICBfLmVhY2goWydlc2NhcGUnLCAndW5lc2NhcGUnXSwgZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgX1ttZXRob2RdID0gZnVuY3Rpb24oc3RyaW5nKSB7XG4gICAgICBpZiAoc3RyaW5nID09IG51bGwpIHJldHVybiAnJztcbiAgICAgIHJldHVybiAoJycgKyBzdHJpbmcpLnJlcGxhY2UoZW50aXR5UmVnZXhlc1ttZXRob2RdLCBmdW5jdGlvbihtYXRjaCkge1xuICAgICAgICByZXR1cm4gZW50aXR5TWFwW21ldGhvZF1bbWF0Y2hdO1xuICAgICAgfSk7XG4gICAgfTtcbiAgfSk7XG5cbiAgLy8gSWYgdGhlIHZhbHVlIG9mIHRoZSBuYW1lZCBgcHJvcGVydHlgIGlzIGEgZnVuY3Rpb24gdGhlbiBpbnZva2UgaXQgd2l0aCB0aGVcbiAgLy8gYG9iamVjdGAgYXMgY29udGV4dDsgb3RoZXJ3aXNlLCByZXR1cm4gaXQuXG4gIF8ucmVzdWx0ID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkge1xuICAgIGlmIChvYmplY3QgPT0gbnVsbCkgcmV0dXJuIHZvaWQgMDtcbiAgICB2YXIgdmFsdWUgPSBvYmplY3RbcHJvcGVydHldO1xuICAgIHJldHVybiBfLmlzRnVuY3Rpb24odmFsdWUpID8gdmFsdWUuY2FsbChvYmplY3QpIDogdmFsdWU7XG4gIH07XG5cbiAgLy8gQWRkIHlvdXIgb3duIGN1c3RvbSBmdW5jdGlvbnMgdG8gdGhlIFVuZGVyc2NvcmUgb2JqZWN0LlxuICBfLm1peGluID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgZWFjaChfLmZ1bmN0aW9ucyhvYmopLCBmdW5jdGlvbihuYW1lKSB7XG4gICAgICB2YXIgZnVuYyA9IF9bbmFtZV0gPSBvYmpbbmFtZV07XG4gICAgICBfLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgYXJncyA9IFt0aGlzLl93cmFwcGVkXTtcbiAgICAgICAgcHVzaC5hcHBseShhcmdzLCBhcmd1bWVudHMpO1xuICAgICAgICByZXR1cm4gcmVzdWx0LmNhbGwodGhpcywgZnVuYy5hcHBseShfLCBhcmdzKSk7XG4gICAgICB9O1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIEdlbmVyYXRlIGEgdW5pcXVlIGludGVnZXIgaWQgKHVuaXF1ZSB3aXRoaW4gdGhlIGVudGlyZSBjbGllbnQgc2Vzc2lvbikuXG4gIC8vIFVzZWZ1bCBmb3IgdGVtcG9yYXJ5IERPTSBpZHMuXG4gIHZhciBpZENvdW50ZXIgPSAwO1xuICBfLnVuaXF1ZUlkID0gZnVuY3Rpb24ocHJlZml4KSB7XG4gICAgdmFyIGlkID0gKytpZENvdW50ZXIgKyAnJztcbiAgICByZXR1cm4gcHJlZml4ID8gcHJlZml4ICsgaWQgOiBpZDtcbiAgfTtcblxuICAvLyBCeSBkZWZhdWx0LCBVbmRlcnNjb3JlIHVzZXMgRVJCLXN0eWxlIHRlbXBsYXRlIGRlbGltaXRlcnMsIGNoYW5nZSB0aGVcbiAgLy8gZm9sbG93aW5nIHRlbXBsYXRlIHNldHRpbmdzIHRvIHVzZSBhbHRlcm5hdGl2ZSBkZWxpbWl0ZXJzLlxuICBfLnRlbXBsYXRlU2V0dGluZ3MgPSB7XG4gICAgZXZhbHVhdGUgICAgOiAvPCUoW1xcc1xcU10rPyklPi9nLFxuICAgIGludGVycG9sYXRlIDogLzwlPShbXFxzXFxTXSs/KSU+L2csXG4gICAgZXNjYXBlICAgICAgOiAvPCUtKFtcXHNcXFNdKz8pJT4vZ1xuICB9O1xuXG4gIC8vIFdoZW4gY3VzdG9taXppbmcgYHRlbXBsYXRlU2V0dGluZ3NgLCBpZiB5b3UgZG9uJ3Qgd2FudCB0byBkZWZpbmUgYW5cbiAgLy8gaW50ZXJwb2xhdGlvbiwgZXZhbHVhdGlvbiBvciBlc2NhcGluZyByZWdleCwgd2UgbmVlZCBvbmUgdGhhdCBpc1xuICAvLyBndWFyYW50ZWVkIG5vdCB0byBtYXRjaC5cbiAgdmFyIG5vTWF0Y2ggPSAvKC4pXi87XG5cbiAgLy8gQ2VydGFpbiBjaGFyYWN0ZXJzIG5lZWQgdG8gYmUgZXNjYXBlZCBzbyB0aGF0IHRoZXkgY2FuIGJlIHB1dCBpbnRvIGFcbiAgLy8gc3RyaW5nIGxpdGVyYWwuXG4gIHZhciBlc2NhcGVzID0ge1xuICAgIFwiJ1wiOiAgICAgIFwiJ1wiLFxuICAgICdcXFxcJzogICAgICdcXFxcJyxcbiAgICAnXFxyJzogICAgICdyJyxcbiAgICAnXFxuJzogICAgICduJyxcbiAgICAnXFx0JzogICAgICd0JyxcbiAgICAnXFx1MjAyOCc6ICd1MjAyOCcsXG4gICAgJ1xcdTIwMjknOiAndTIwMjknXG4gIH07XG5cbiAgdmFyIGVzY2FwZXIgPSAvXFxcXHwnfFxccnxcXG58XFx0fFxcdTIwMjh8XFx1MjAyOS9nO1xuXG4gIC8vIEphdmFTY3JpcHQgbWljcm8tdGVtcGxhdGluZywgc2ltaWxhciB0byBKb2huIFJlc2lnJ3MgaW1wbGVtZW50YXRpb24uXG4gIC8vIFVuZGVyc2NvcmUgdGVtcGxhdGluZyBoYW5kbGVzIGFyYml0cmFyeSBkZWxpbWl0ZXJzLCBwcmVzZXJ2ZXMgd2hpdGVzcGFjZSxcbiAgLy8gYW5kIGNvcnJlY3RseSBlc2NhcGVzIHF1b3RlcyB3aXRoaW4gaW50ZXJwb2xhdGVkIGNvZGUuXG4gIF8udGVtcGxhdGUgPSBmdW5jdGlvbih0ZXh0LCBkYXRhLCBzZXR0aW5ncykge1xuICAgIHZhciByZW5kZXI7XG4gICAgc2V0dGluZ3MgPSBfLmRlZmF1bHRzKHt9LCBzZXR0aW5ncywgXy50ZW1wbGF0ZVNldHRpbmdzKTtcblxuICAgIC8vIENvbWJpbmUgZGVsaW1pdGVycyBpbnRvIG9uZSByZWd1bGFyIGV4cHJlc3Npb24gdmlhIGFsdGVybmF0aW9uLlxuICAgIHZhciBtYXRjaGVyID0gbmV3IFJlZ0V4cChbXG4gICAgICAoc2V0dGluZ3MuZXNjYXBlIHx8IG5vTWF0Y2gpLnNvdXJjZSxcbiAgICAgIChzZXR0aW5ncy5pbnRlcnBvbGF0ZSB8fCBub01hdGNoKS5zb3VyY2UsXG4gICAgICAoc2V0dGluZ3MuZXZhbHVhdGUgfHwgbm9NYXRjaCkuc291cmNlXG4gICAgXS5qb2luKCd8JykgKyAnfCQnLCAnZycpO1xuXG4gICAgLy8gQ29tcGlsZSB0aGUgdGVtcGxhdGUgc291cmNlLCBlc2NhcGluZyBzdHJpbmcgbGl0ZXJhbHMgYXBwcm9wcmlhdGVseS5cbiAgICB2YXIgaW5kZXggPSAwO1xuICAgIHZhciBzb3VyY2UgPSBcIl9fcCs9J1wiO1xuICAgIHRleHQucmVwbGFjZShtYXRjaGVyLCBmdW5jdGlvbihtYXRjaCwgZXNjYXBlLCBpbnRlcnBvbGF0ZSwgZXZhbHVhdGUsIG9mZnNldCkge1xuICAgICAgc291cmNlICs9IHRleHQuc2xpY2UoaW5kZXgsIG9mZnNldClcbiAgICAgICAgLnJlcGxhY2UoZXNjYXBlciwgZnVuY3Rpb24obWF0Y2gpIHsgcmV0dXJuICdcXFxcJyArIGVzY2FwZXNbbWF0Y2hdOyB9KTtcblxuICAgICAgaWYgKGVzY2FwZSkge1xuICAgICAgICBzb3VyY2UgKz0gXCInK1xcbigoX190PShcIiArIGVzY2FwZSArIFwiKSk9PW51bGw/Jyc6Xy5lc2NhcGUoX190KSkrXFxuJ1wiO1xuICAgICAgfVxuICAgICAgaWYgKGludGVycG9sYXRlKSB7XG4gICAgICAgIHNvdXJjZSArPSBcIicrXFxuKChfX3Q9KFwiICsgaW50ZXJwb2xhdGUgKyBcIikpPT1udWxsPycnOl9fdCkrXFxuJ1wiO1xuICAgICAgfVxuICAgICAgaWYgKGV2YWx1YXRlKSB7XG4gICAgICAgIHNvdXJjZSArPSBcIic7XFxuXCIgKyBldmFsdWF0ZSArIFwiXFxuX19wKz0nXCI7XG4gICAgICB9XG4gICAgICBpbmRleCA9IG9mZnNldCArIG1hdGNoLmxlbmd0aDtcbiAgICAgIHJldHVybiBtYXRjaDtcbiAgICB9KTtcbiAgICBzb3VyY2UgKz0gXCInO1xcblwiO1xuXG4gICAgLy8gSWYgYSB2YXJpYWJsZSBpcyBub3Qgc3BlY2lmaWVkLCBwbGFjZSBkYXRhIHZhbHVlcyBpbiBsb2NhbCBzY29wZS5cbiAgICBpZiAoIXNldHRpbmdzLnZhcmlhYmxlKSBzb3VyY2UgPSAnd2l0aChvYmp8fHt9KXtcXG4nICsgc291cmNlICsgJ31cXG4nO1xuXG4gICAgc291cmNlID0gXCJ2YXIgX190LF9fcD0nJyxfX2o9QXJyYXkucHJvdG90eXBlLmpvaW4sXCIgK1xuICAgICAgXCJwcmludD1mdW5jdGlvbigpe19fcCs9X19qLmNhbGwoYXJndW1lbnRzLCcnKTt9O1xcblwiICtcbiAgICAgIHNvdXJjZSArIFwicmV0dXJuIF9fcDtcXG5cIjtcblxuICAgIHRyeSB7XG4gICAgICByZW5kZXIgPSBuZXcgRnVuY3Rpb24oc2V0dGluZ3MudmFyaWFibGUgfHwgJ29iaicsICdfJywgc291cmNlKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBlLnNvdXJjZSA9IHNvdXJjZTtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuXG4gICAgaWYgKGRhdGEpIHJldHVybiByZW5kZXIoZGF0YSwgXyk7XG4gICAgdmFyIHRlbXBsYXRlID0gZnVuY3Rpb24oZGF0YSkge1xuICAgICAgcmV0dXJuIHJlbmRlci5jYWxsKHRoaXMsIGRhdGEsIF8pO1xuICAgIH07XG5cbiAgICAvLyBQcm92aWRlIHRoZSBjb21waWxlZCBmdW5jdGlvbiBzb3VyY2UgYXMgYSBjb252ZW5pZW5jZSBmb3IgcHJlY29tcGlsYXRpb24uXG4gICAgdGVtcGxhdGUuc291cmNlID0gJ2Z1bmN0aW9uKCcgKyAoc2V0dGluZ3MudmFyaWFibGUgfHwgJ29iaicpICsgJyl7XFxuJyArIHNvdXJjZSArICd9JztcblxuICAgIHJldHVybiB0ZW1wbGF0ZTtcbiAgfTtcblxuICAvLyBBZGQgYSBcImNoYWluXCIgZnVuY3Rpb24sIHdoaWNoIHdpbGwgZGVsZWdhdGUgdG8gdGhlIHdyYXBwZXIuXG4gIF8uY2hhaW4gPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gXyhvYmopLmNoYWluKCk7XG4gIH07XG5cbiAgLy8gT09QXG4gIC8vIC0tLS0tLS0tLS0tLS0tLVxuICAvLyBJZiBVbmRlcnNjb3JlIGlzIGNhbGxlZCBhcyBhIGZ1bmN0aW9uLCBpdCByZXR1cm5zIGEgd3JhcHBlZCBvYmplY3QgdGhhdFxuICAvLyBjYW4gYmUgdXNlZCBPTy1zdHlsZS4gVGhpcyB3cmFwcGVyIGhvbGRzIGFsdGVyZWQgdmVyc2lvbnMgb2YgYWxsIHRoZVxuICAvLyB1bmRlcnNjb3JlIGZ1bmN0aW9ucy4gV3JhcHBlZCBvYmplY3RzIG1heSBiZSBjaGFpbmVkLlxuXG4gIC8vIEhlbHBlciBmdW5jdGlvbiB0byBjb250aW51ZSBjaGFpbmluZyBpbnRlcm1lZGlhdGUgcmVzdWx0cy5cbiAgdmFyIHJlc3VsdCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiB0aGlzLl9jaGFpbiA/IF8ob2JqKS5jaGFpbigpIDogb2JqO1xuICB9O1xuXG4gIC8vIEFkZCBhbGwgb2YgdGhlIFVuZGVyc2NvcmUgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyIG9iamVjdC5cbiAgXy5taXhpbihfKTtcblxuICAvLyBBZGQgYWxsIG11dGF0b3IgQXJyYXkgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyLlxuICBlYWNoKFsncG9wJywgJ3B1c2gnLCAncmV2ZXJzZScsICdzaGlmdCcsICdzb3J0JywgJ3NwbGljZScsICd1bnNoaWZ0J10sIGZ1bmN0aW9uKG5hbWUpIHtcbiAgICB2YXIgbWV0aG9kID0gQXJyYXlQcm90b1tuYW1lXTtcbiAgICBfLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIG9iaiA9IHRoaXMuX3dyYXBwZWQ7XG4gICAgICBtZXRob2QuYXBwbHkob2JqLCBhcmd1bWVudHMpO1xuICAgICAgaWYgKChuYW1lID09ICdzaGlmdCcgfHwgbmFtZSA9PSAnc3BsaWNlJykgJiYgb2JqLmxlbmd0aCA9PT0gMCkgZGVsZXRlIG9ialswXTtcbiAgICAgIHJldHVybiByZXN1bHQuY2FsbCh0aGlzLCBvYmopO1xuICAgIH07XG4gIH0pO1xuXG4gIC8vIEFkZCBhbGwgYWNjZXNzb3IgQXJyYXkgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyLlxuICBlYWNoKFsnY29uY2F0JywgJ2pvaW4nLCAnc2xpY2UnXSwgZnVuY3Rpb24obmFtZSkge1xuICAgIHZhciBtZXRob2QgPSBBcnJheVByb3RvW25hbWVdO1xuICAgIF8ucHJvdG90eXBlW25hbWVdID0gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gcmVzdWx0LmNhbGwodGhpcywgbWV0aG9kLmFwcGx5KHRoaXMuX3dyYXBwZWQsIGFyZ3VtZW50cykpO1xuICAgIH07XG4gIH0pO1xuXG4gIF8uZXh0ZW5kKF8ucHJvdG90eXBlLCB7XG5cbiAgICAvLyBTdGFydCBjaGFpbmluZyBhIHdyYXBwZWQgVW5kZXJzY29yZSBvYmplY3QuXG4gICAgY2hhaW46IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5fY2hhaW4gPSB0cnVlO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIEV4dHJhY3RzIHRoZSByZXN1bHQgZnJvbSBhIHdyYXBwZWQgYW5kIGNoYWluZWQgb2JqZWN0LlxuICAgIHZhbHVlOiBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiB0aGlzLl93cmFwcGVkO1xuICAgIH1cblxuICB9KTtcblxufSkuY2FsbCh0aGlzKTtcblxufSkoKSIsIihmdW5jdGlvbigpIHtcbiAgdmFyIGFjdGl2ZSwgY3JlYXRlU2VhcmNoLCBlbXB0eVBhZ2UsIHV0aWwsIHdpa2k7XG5cbiAgd2lraSA9IHJlcXVpcmUoJy4vd2lraScpO1xuXG4gIHV0aWwgPSByZXF1aXJlKCcuL3V0aWwnKTtcblxuICBhY3RpdmUgPSByZXF1aXJlKCcuL2FjdGl2ZScpO1xuXG4gIGVtcHR5UGFnZSA9IHJlcXVpcmUoJy4vcGFnZScpLmVtcHR5UGFnZTtcblxuICBjcmVhdGVTZWFyY2ggPSBmdW5jdGlvbihfYXJnKSB7XG4gICAgdmFyIG5laWdoYm9yaG9vZCwgcGVyZm9ybVNlYXJjaDtcbiAgICBuZWlnaGJvcmhvb2QgPSBfYXJnLm5laWdoYm9yaG9vZDtcbiAgICBwZXJmb3JtU2VhcmNoID0gZnVuY3Rpb24oc2VhcmNoUXVlcnkpIHtcbiAgICAgIHZhciAkcmVzdWx0UGFnZSwgcmVzdWx0LCByZXN1bHRQYWdlLCBzZWFyY2hSZXN1bHRzLCB0YWxseSwgX2ksIF9sZW4sIF9yZWY7XG4gICAgICBzZWFyY2hSZXN1bHRzID0gbmVpZ2hib3Job29kLnNlYXJjaChzZWFyY2hRdWVyeSk7XG4gICAgICB0YWxseSA9IHNlYXJjaFJlc3VsdHMudGFsbHk7XG4gICAgICByZXN1bHRQYWdlID0gZW1wdHlQYWdlKCk7XG4gICAgICByZXN1bHRQYWdlLnNldFRpdGxlKFwiU2VhcmNoIGZvciAnXCIgKyBzZWFyY2hRdWVyeSArIFwiJ1wiKTtcbiAgICAgIHJlc3VsdFBhZ2UuYWRkUGFyYWdyYXBoKFwiU3RyaW5nICdcIiArIHNlYXJjaFF1ZXJ5ICsgXCInIGZvdW5kIG9uIFwiICsgKHRhbGx5LmZpbmRzIHx8ICdub25lJykgKyBcIiBvZiBcIiArICh0YWxseS5wYWdlcyB8fCAnbm8nKSArIFwiIHBhZ2VzIGZyb20gXCIgKyAodGFsbHkuc2l0ZXMgfHwgJ25vJykgKyBcIiBzaXRlcy5cXG5UZXh0IG1hdGNoZWQgb24gXCIgKyAodGFsbHkudGl0bGUgfHwgJ25vJykgKyBcIiB0aXRsZXMsIFwiICsgKHRhbGx5LnRleHQgfHwgJ25vJykgKyBcIiBwYXJhZ3JhcGhzLCBhbmQgXCIgKyAodGFsbHkuc2x1ZyB8fCAnbm8nKSArIFwiIHNsdWdzLlxcbkVsYXBzZWQgdGltZSBcIiArIHRhbGx5Lm1zZWMgKyBcIiBtaWxsaXNlY29uZHMuXCIpO1xuICAgICAgX3JlZiA9IHNlYXJjaFJlc3VsdHMuZmluZHM7XG4gICAgICBmb3IgKF9pID0gMCwgX2xlbiA9IF9yZWYubGVuZ3RoOyBfaSA8IF9sZW47IF9pKyspIHtcbiAgICAgICAgcmVzdWx0ID0gX3JlZltfaV07XG4gICAgICAgIHJlc3VsdFBhZ2UuYWRkSXRlbSh7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwicmVmZXJlbmNlXCIsXG4gICAgICAgICAgXCJzaXRlXCI6IHJlc3VsdC5zaXRlLFxuICAgICAgICAgIFwic2x1Z1wiOiByZXN1bHQucGFnZS5zbHVnLFxuICAgICAgICAgIFwidGl0bGVcIjogcmVzdWx0LnBhZ2UudGl0bGUsXG4gICAgICAgICAgXCJ0ZXh0XCI6IHJlc3VsdC5wYWdlLnN5bm9wc2lzIHx8ICcnXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgJHJlc3VsdFBhZ2UgPSB3aWtpLmNyZWF0ZVBhZ2UocmVzdWx0UGFnZS5nZXRTbHVnKCkpLmFkZENsYXNzKCdnaG9zdCcpO1xuICAgICAgJHJlc3VsdFBhZ2UuYXBwZW5kVG8oJCgnLm1haW4nKSk7XG4gICAgICB3aWtpLmJ1aWxkUGFnZShyZXN1bHRQYWdlLCAkcmVzdWx0UGFnZSk7XG4gICAgICByZXR1cm4gYWN0aXZlLnNldCgkKCcucGFnZScpLmxhc3QoKSk7XG4gICAgfTtcbiAgICByZXR1cm4ge1xuICAgICAgcGVyZm9ybVNlYXJjaDogcGVyZm9ybVNlYXJjaFxuICAgIH07XG4gIH07XG5cbiAgbW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVTZWFyY2g7XG5cbn0pLmNhbGwodGhpcyk7XG4iLCIoZnVuY3Rpb24oKSB7XG4gIHZhciBhY3RpdmUsIGNyZWF0ZVNlYXJjaCwgbmVpZ2hib3Job29kLCBuZXh0QXZhaWxhYmxlRmV0Y2gsIG5leHRGZXRjaEludGVydmFsLCBwb3B1bGF0ZVNpdGVJbmZvRm9yLCB1dGlsLCB3aWtpLCBfLFxuICAgIF9faGFzUHJvcCA9IHt9Lmhhc093blByb3BlcnR5O1xuXG4gIF8gPSByZXF1aXJlKCd1bmRlcnNjb3JlJyk7XG5cbiAgd2lraSA9IHJlcXVpcmUoJy4vd2lraScpO1xuXG4gIGFjdGl2ZSA9IHJlcXVpcmUoJy4vYWN0aXZlJyk7XG5cbiAgdXRpbCA9IHJlcXVpcmUoJy4vdXRpbCcpO1xuXG4gIGNyZWF0ZVNlYXJjaCA9IHJlcXVpcmUoJy4vc2VhcmNoJyk7XG5cbiAgbW9kdWxlLmV4cG9ydHMgPSBuZWlnaGJvcmhvb2QgPSB7fTtcblxuICBpZiAod2lraS5uZWlnaGJvcmhvb2QgPT0gbnVsbCkge1xuICAgIHdpa2kubmVpZ2hib3Job29kID0ge307XG4gIH1cblxuICBuZXh0QXZhaWxhYmxlRmV0Y2ggPSAwO1xuXG4gIG5leHRGZXRjaEludGVydmFsID0gMjAwMDtcblxuICBwb3B1bGF0ZVNpdGVJbmZvRm9yID0gZnVuY3Rpb24oc2l0ZSwgbmVpZ2hib3JJbmZvKSB7XG4gICAgdmFyIGZldGNoTWFwLCBub3csIHRyYW5zaXRpb247XG4gICAgaWYgKG5laWdoYm9ySW5mby5zaXRlbWFwUmVxdWVzdEluZmxpZ2h0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIG5laWdoYm9ySW5mby5zaXRlbWFwUmVxdWVzdEluZmxpZ2h0ID0gdHJ1ZTtcbiAgICB0cmFuc2l0aW9uID0gZnVuY3Rpb24oc2l0ZSwgZnJvbSwgdG8pIHtcbiAgICAgIHJldHVybiAkKFwiLm5laWdoYm9yW2RhdGEtc2l0ZT1cXFwiXCIgKyBzaXRlICsgXCJcXFwiXVwiKS5maW5kKCdkaXYnKS5yZW1vdmVDbGFzcyhmcm9tKS5hZGRDbGFzcyh0byk7XG4gICAgfTtcbiAgICBmZXRjaE1hcCA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIHJlcXVlc3QsIHNpdGVtYXBVcmw7XG4gICAgICBzaXRlbWFwVXJsID0gXCJodHRwOi8vXCIgKyBzaXRlICsgXCIvc3lzdGVtL3NpdGVtYXAuanNvblwiO1xuICAgICAgdHJhbnNpdGlvbihzaXRlLCAnd2FpdCcsICdmZXRjaCcpO1xuICAgICAgcmVxdWVzdCA9ICQuYWpheCh7XG4gICAgICAgIHR5cGU6ICdHRVQnLFxuICAgICAgICBkYXRhVHlwZTogJ2pzb24nLFxuICAgICAgICB1cmw6IHNpdGVtYXBVcmxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHJlcXVlc3QuYWx3YXlzKGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbmVpZ2hib3JJbmZvLnNpdGVtYXBSZXF1ZXN0SW5mbGlnaHQgPSBmYWxzZTtcbiAgICAgIH0pLmRvbmUoZnVuY3Rpb24oZGF0YSkge1xuICAgICAgICBuZWlnaGJvckluZm8uc2l0ZW1hcCA9IGRhdGE7XG4gICAgICAgIHRyYW5zaXRpb24oc2l0ZSwgJ2ZldGNoJywgJ2RvbmUnKTtcbiAgICAgICAgcmV0dXJuICQoJ2JvZHknKS50cmlnZ2VyKCduZXctbmVpZ2hib3ItZG9uZScsIHNpdGUpO1xuICAgICAgfSkuZmFpbChmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgIHJldHVybiB0cmFuc2l0aW9uKHNpdGUsICdmZXRjaCcsICdmYWlsJyk7XG4gICAgICB9KTtcbiAgICB9O1xuICAgIG5vdyA9IERhdGUubm93KCk7XG4gICAgaWYgKG5vdyA+IG5leHRBdmFpbGFibGVGZXRjaCkge1xuICAgICAgbmV4dEF2YWlsYWJsZUZldGNoID0gbm93ICsgbmV4dEZldGNoSW50ZXJ2YWw7XG4gICAgICByZXR1cm4gc2V0VGltZW91dChmZXRjaE1hcCwgMTAwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc2V0VGltZW91dChmZXRjaE1hcCwgbmV4dEF2YWlsYWJsZUZldGNoIC0gbm93KTtcbiAgICAgIHJldHVybiBuZXh0QXZhaWxhYmxlRmV0Y2ggKz0gbmV4dEZldGNoSW50ZXJ2YWw7XG4gICAgfVxuICB9O1xuXG4gIHdpa2kucmVnaXN0ZXJOZWlnaGJvciA9IG5laWdoYm9yaG9vZC5yZWdpc3Rlck5laWdoYm9yID0gZnVuY3Rpb24oc2l0ZSkge1xuICAgIHZhciBuZWlnaGJvckluZm87XG4gICAgaWYgKHdpa2kubmVpZ2hib3Job29kW3NpdGVdICE9IG51bGwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbmVpZ2hib3JJbmZvID0ge307XG4gICAgd2lraS5uZWlnaGJvcmhvb2Rbc2l0ZV0gPSBuZWlnaGJvckluZm87XG4gICAgcG9wdWxhdGVTaXRlSW5mb0ZvcihzaXRlLCBuZWlnaGJvckluZm8pO1xuICAgIHJldHVybiAkKCdib2R5JykudHJpZ2dlcignbmV3LW5laWdoYm9yJywgc2l0ZSk7XG4gIH07XG5cbiAgbmVpZ2hib3Job29kLmxpc3ROZWlnaGJvcnMgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gXy5rZXlzKHdpa2kubmVpZ2hib3Job29kKTtcbiAgfTtcblxuICBuZWlnaGJvcmhvb2Quc2VhcmNoID0gZnVuY3Rpb24oc2VhcmNoUXVlcnkpIHtcbiAgICB2YXIgZmluZHMsIG1hdGNoLCBtYXRjaGluZ1BhZ2VzLCBuZWlnaGJvckluZm8sIG5laWdoYm9yU2l0ZSwgc2l0ZW1hcCwgc3RhcnQsIHRhbGx5LCB0aWNrLCBfcmVmO1xuICAgIGZpbmRzID0gW107XG4gICAgdGFsbHkgPSB7fTtcbiAgICB0aWNrID0gZnVuY3Rpb24oa2V5KSB7XG4gICAgICBpZiAodGFsbHlba2V5XSAhPSBudWxsKSB7XG4gICAgICAgIHJldHVybiB0YWxseVtrZXldKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGFsbHlba2V5XSA9IDE7XG4gICAgICB9XG4gICAgfTtcbiAgICBtYXRjaCA9IGZ1bmN0aW9uKGtleSwgdGV4dCkge1xuICAgICAgdmFyIGhpdDtcbiAgICAgIGhpdCA9ICh0ZXh0ICE9IG51bGwpICYmIHRleHQudG9Mb3dlckNhc2UoKS5pbmRleE9mKHNlYXJjaFF1ZXJ5LnRvTG93ZXJDYXNlKCkpID49IDA7XG4gICAgICBpZiAoaGl0KSB7XG4gICAgICAgIHRpY2soa2V5KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBoaXQ7XG4gICAgfTtcbiAgICBzdGFydCA9IERhdGUubm93KCk7XG4gICAgX3JlZiA9IHdpa2kubmVpZ2hib3Job29kO1xuICAgIGZvciAobmVpZ2hib3JTaXRlIGluIF9yZWYpIHtcbiAgICAgIGlmICghX19oYXNQcm9wLmNhbGwoX3JlZiwgbmVpZ2hib3JTaXRlKSkgY29udGludWU7XG4gICAgICBuZWlnaGJvckluZm8gPSBfcmVmW25laWdoYm9yU2l0ZV07XG4gICAgICBzaXRlbWFwID0gbmVpZ2hib3JJbmZvLnNpdGVtYXA7XG4gICAgICBpZiAoc2l0ZW1hcCAhPSBudWxsKSB7XG4gICAgICAgIHRpY2soJ3NpdGVzJyk7XG4gICAgICB9XG4gICAgICBtYXRjaGluZ1BhZ2VzID0gXy5lYWNoKHNpdGVtYXAsIGZ1bmN0aW9uKHBhZ2UpIHtcbiAgICAgICAgdGljaygncGFnZXMnKTtcbiAgICAgICAgaWYgKCEobWF0Y2goJ3RpdGxlJywgcGFnZS50aXRsZSkgfHwgbWF0Y2goJ3RleHQnLCBwYWdlLnN5bm9wc2lzKSB8fCBtYXRjaCgnc2x1ZycsIHBhZ2Uuc2x1ZykpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRpY2soJ2ZpbmRzJyk7XG4gICAgICAgIHJldHVybiBmaW5kcy5wdXNoKHtcbiAgICAgICAgICBwYWdlOiBwYWdlLFxuICAgICAgICAgIHNpdGU6IG5laWdoYm9yU2l0ZSxcbiAgICAgICAgICByYW5rOiAxXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfVxuICAgIHRhbGx5Wydtc2VjJ10gPSBEYXRlLm5vdygpIC0gc3RhcnQ7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZpbmRzOiBmaW5kcyxcbiAgICAgIHRhbGx5OiB0YWxseVxuICAgIH07XG4gIH07XG5cbiAgJChmdW5jdGlvbigpIHtcbiAgICB2YXIgJG5laWdoYm9yaG9vZCwgZmxhZywgc2VhcmNoO1xuICAgICRuZWlnaGJvcmhvb2QgPSAkKCcubmVpZ2hib3Job29kJyk7XG4gICAgZmxhZyA9IGZ1bmN0aW9uKHNpdGUpIHtcbiAgICAgIHJldHVybiBcIjxzcGFuIGNsYXNzPVxcXCJuZWlnaGJvclxcXCIgZGF0YS1zaXRlPVxcXCJcIiArIHNpdGUgKyBcIlxcXCI+XFxuICA8ZGl2IGNsYXNzPVxcXCJ3YWl0XFxcIj5cXG4gICAgPGltZyBzcmM9XFxcImh0dHA6Ly9cIiArIHNpdGUgKyBcIi9mYXZpY29uLnBuZ1xcXCIgdGl0bGU9XFxcIlwiICsgc2l0ZSArIFwiXFxcIj5cXG4gIDwvZGl2Plxcbjwvc3Bhbj5cIjtcbiAgICB9O1xuICAgICQoJ2JvZHknKS5vbignbmV3LW5laWdoYm9yJywgZnVuY3Rpb24oZSwgc2l0ZSkge1xuICAgICAgcmV0dXJuICRuZWlnaGJvcmhvb2QuYXBwZW5kKGZsYWcoc2l0ZSkpO1xuICAgIH0pLmRlbGVnYXRlKCcubmVpZ2hib3IgaW1nJywgJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgcmV0dXJuIHdpa2kuZG9JbnRlcm5hbExpbmsoJ3dlbGNvbWUtdmlzaXRvcnMnLCBudWxsLCB0aGlzLnRpdGxlKTtcbiAgICB9KTtcbiAgICBzZWFyY2ggPSBjcmVhdGVTZWFyY2goe1xuICAgICAgbmVpZ2hib3Job29kOiBuZWlnaGJvcmhvb2RcbiAgICB9KTtcbiAgICByZXR1cm4gJCgnaW5wdXQuc2VhcmNoJykub24oJ2tleXByZXNzJywgZnVuY3Rpb24oZSkge1xuICAgICAgdmFyIHNlYXJjaFF1ZXJ5O1xuICAgICAgaWYgKGUua2V5Q29kZSAhPT0gMTMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgc2VhcmNoUXVlcnkgPSAkKHRoaXMpLnZhbCgpO1xuICAgICAgc2VhcmNoLnBlcmZvcm1TZWFyY2goc2VhcmNoUXVlcnkpO1xuICAgICAgcmV0dXJuICQodGhpcykudmFsKFwiXCIpO1xuICAgIH0pO1xuICB9KTtcblxufSkuY2FsbCh0aGlzKTtcbiJdfQ==
         | 
| 3607 | 
            +
            ;
         |