Skip to content

Instantly share code, notes, and snippets.

@timelyportfolio
Last active November 22, 2016 22:10
Show Gist options
  • Select an option

  • Save timelyportfolio/2c8e0fcbd5b4fb73151c1be9df17c103 to your computer and use it in GitHub Desktop.

Select an option

Save timelyportfolio/2c8e0fcbd5b4fb73151c1be9df17c103 to your computer and use it in GitHub Desktop.
R plotly + defiant.js with crosstalk
license: mit

Summary

plotly has built-in crosstalk thanks to Carson Sievert and Joe Cheng. This allows us to do some interesting things. In this experiment, I use the really neat defiant.js to query the mpg data and update the selection. plotly knows what to do with it!

Code

library(htmltools)
library(crosstalk)
library(plotly)
library(pipeR)

sd <- SharedData$new(mpg, group="a")
pl <- plot_ly(sd) %>% add_markers(x=~factor(cyl), y=~hwy)

tagList(
  tags$script(
    src = "https://cdn.rawgit.com/hbi99/defiant.js/master/dist/defiant.min.js"
  ),
  tags$div(
    style = "width:30%; display:block; float:left;",
    tags$button("//*[class='compact']"),
    tags$button("//*[hwy > 25]"),
    tags$button("//*[contains(manufacturer,'au') and class='compact']"),
    tags$div(
      tags$pre(id="error-reporter")
    )
  ),
  tags$div(
    style = "width:50%; display:block; float:left;",
    pl
  ),
  tags$script(
sprintf(
"
var d3 = Plotly.d3 //use d3 for convenience from Plotly
var data = %s;
var grp = crosstalk.group('a') // we set this to 'a' in SharedData

function updateQuery(querytext){
  if(querytext !== '') {
    try{
      var res = JSON.search( data, querytext );
      var key = d3.keys(
        d3.nest()
          .key(function(d){return +d.key_;})
          .map(res)
      );
      grp.var('selection').set(key);
      d3.select('#error-reporter').text('success: ' + querytext);
    } catch (err) {
      d3.select('#error-reporter').text(err);
      grp.var('selection').set(null);
    };
  } else {
    grp.var('selection').set(null);
  }
}

d3.selectAll('button').on('click',function(){
  updateQuery(d3.select(this).text());
});

// update reporter to show queried by plotly
grp.var('selection').on('change', function(x){
  if(typeof(x.sender) !== 'undefined'){
    d3.select('#error-reporter').text('queried by plotly');
  }
});
",
  jsonlite::toJSON(sd$data(withKey=TRUE),dataframe="rows")
)
  )
) %>>%
  browsable()
This file has been truncated, but you can view the full file.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="data:application/x-javascript;base64,KGZ1bmN0aW9uKCkgew0KICAvLyBJZiB3aW5kb3cuSFRNTFdpZGdldHMgaXMgYWxyZWFkeSBkZWZpbmVkLCB0aGVuIHVzZSBpdDsgb3RoZXJ3aXNlIGNyZWF0ZSBhDQogIC8vIG5ldyBvYmplY3QuIFRoaXMgYWxsb3dzIHByZWNlZGluZyBjb2RlIHRvIHNldCBvcHRpb25zIHRoYXQgYWZmZWN0IHRoZQ0KICAvLyBpbml0aWFsaXphdGlvbiBwcm9jZXNzICh0aG91Z2ggbm9uZSBjdXJyZW50bHkgZXhpc3QpLg0KICB3aW5kb3cuSFRNTFdpZGdldHMgPSB3aW5kb3cuSFRNTFdpZGdldHMgfHwge307DQoNCiAgLy8gU2VlIGlmIHdlJ3JlIHJ1bm5pbmcgaW4gYSB2aWV3ZXIgcGFuZS4gSWYgbm90LCB3ZSdyZSBpbiBhIHdlYiBicm93c2VyLg0KICB2YXIgdmlld2VyTW9kZSA9IHdpbmRvdy5IVE1MV2lkZ2V0cy52aWV3ZXJNb2RlID0NCiAgICAgIC9cYnZpZXdlcl9wYW5lPTFcYi8udGVzdCh3aW5kb3cubG9jYXRpb24pOw0KDQogIC8vIFNlZSBpZiB3ZSdyZSBydW5uaW5nIGluIFNoaW55IG1vZGUuIElmIG5vdCwgaXQncyBhIHN0YXRpYyBkb2N1bWVudC4NCiAgLy8gTm90ZSB0aGF0IHN0YXRpYyB3aWRnZXRzIGNhbiBhcHBlYXIgaW4gYm90aCBTaGlueSBhbmQgc3RhdGljIG1vZGVzLCBidXQNCiAgLy8gb2J2aW91c2x5LCBTaGlueSB3aWRnZXRzIGNhbiBvbmx5IGFwcGVhciBpbiBTaGlueSBhcHBzL2RvY3VtZW50cy4NCiAgdmFyIHNoaW55TW9kZSA9IHdpbmRvdy5IVE1MV2lkZ2V0cy5zaGlueU1vZGUgPQ0KICAgICAgdHlwZW9mKHdpbmRvdy5TaGlueSkgIT09ICJ1bmRlZmluZWQiICYmICEhd2luZG93LlNoaW55Lm91dHB1dEJpbmRpbmdzOw0KDQogIC8vIFdlIGNhbid0IGNvdW50IG9uIGpRdWVyeSBiZWluZyBhdmFpbGFibGUsIHNvIHdlIGltcGxlbWVudCBvdXIgb3duDQogIC8vIHZlcnNpb24gaWYgbmVjZXNzYXJ5Lg0KICBmdW5jdGlvbiBxdWVyeVNlbGVjdG9yQWxsKHNjb3BlLCBzZWxlY3Rvcikgew0KICAgIGlmICh0eXBlb2YoalF1ZXJ5KSAhPT0gInVuZGVmaW5lZCIgJiYgc2NvcGUgaW5zdGFuY2VvZiBqUXVlcnkpIHsNCiAgICAgIHJldHVybiBzY29wZS5maW5kKHNlbGVjdG9yKTsNCiAgICB9DQogICAgaWYgKHNjb3BlLnF1ZXJ5U2VsZWN0b3JBbGwpIHsNCiAgICAgIHJldHVybiBzY29wZS5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yKTsNCiAgICB9DQogIH0NCg0KICBmdW5jdGlvbiBhc0FycmF5KHZhbHVlKSB7DQogICAgaWYgKHZhbHVlID09PSBudWxsKQ0KICAgICAgcmV0dXJuIFtdOw0KICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKQ0KICAgICAgcmV0dXJuIHZhbHVlOw0KICAgIHJldHVybiBbdmFsdWVdOw0KICB9DQoNCiAgLy8gSW1wbGVtZW50IGpRdWVyeSdzIGV4dGVuZA0KICBmdW5jdGlvbiBleHRlbmQodGFyZ2V0IC8qLCAuLi4gKi8pIHsNCiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PSAxKSB7DQogICAgICByZXR1cm4gdGFyZ2V0Ow0KICAgIH0NCiAgICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykgew0KICAgICAgdmFyIHNvdXJjZSA9IGFyZ3VtZW50c1tpXTsNCiAgICAgIGZvciAodmFyIHByb3AgaW4gc291cmNlKSB7DQogICAgICAgIGlmIChzb3VyY2UuaGFzT3duUHJvcGVydHkocHJvcCkpIHsNCiAgICAgICAgICB0YXJnZXRbcHJvcF0gPSBzb3VyY2VbcHJvcF07DQogICAgICAgIH0NCiAgICAgIH0NCiAgICB9DQogICAgcmV0dXJuIHRhcmdldDsNCiAgfQ0KDQogIC8vIElFOCBkb2Vzbid0IHN1cHBvcnQgQXJyYXkuZm9yRWFjaC4NCiAgZnVuY3Rpb24gZm9yRWFjaCh2YWx1ZXMsIGNhbGxiYWNrLCB0aGlzQXJnKSB7DQogICAgaWYgKHZhbHVlcy5mb3JFYWNoKSB7DQogICAgICB2YWx1ZXMuZm9yRWFjaChjYWxsYmFjaywgdGhpc0FyZyk7DQogICAgfSBlbHNlIHsNCiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdmFsdWVzLmxlbmd0aDsgaSsrKSB7DQogICAgICAgIGNhbGxiYWNrLmNhbGwodGhpc0FyZywgdmFsdWVzW2ldLCBpLCB2YWx1ZXMpOw0KICAgICAgfQ0KICAgIH0NCiAgfQ0KDQogIC8vIFJlcGxhY2VzIHRoZSBzcGVjaWZpZWQgbWV0aG9kIHdpdGggdGhlIHJldHVybiB2YWx1ZSBvZiBmdW5jU291cmNlLg0KICAvLw0KICAvLyBOb3RlIHRoYXQgZnVuY1NvdXJjZSBzaG91bGQgbm90IEJFIHRoZSBuZXcgbWV0aG9kLCBpdCBzaG91bGQgYmUgYSBmdW5jdGlvbg0KICAvLyB0aGF0IFJFVFVSTlMgdGhlIG5ldyBtZXRob2QuIGZ1bmNTb3VyY2UgcmVjZWl2ZXMgYSBzaW5nbGUgYXJndW1lbnQgdGhhdCBpcw0KICAvLyB0aGUgb3ZlcnJpZGRlbiBtZXRob2QsIGl0IGNhbiBiZSBjYWxsZWQgZnJvbSB0aGUgbmV3IG1ldGhvZC4gVGhlIG92ZXJyaWRkZW4NCiAgLy8gbWV0aG9kIGNhbiBiZSBjYWxsZWQgbGlrZSBhIHJlZ3VsYXIgZnVuY3Rpb24sIGl0IGhhcyB0aGUgdGFyZ2V0IHBlcm1hbmVudGx5DQogIC8vIGJvdW5kIHRvIGl0IHNvICJ0aGlzIiB3aWxsIHdvcmsgY29ycmVjdGx5Lg0KICBmdW5jdGlvbiBvdmVycmlkZU1ldGhvZCh0YXJnZXQsIG1ldGhvZE5hbWUsIGZ1bmNTb3VyY2UpIHsNCiAgICB2YXIgc3VwZXJGdW5jID0gdGFyZ2V0W21ldGhvZE5hbWVdIHx8IGZ1bmN0aW9uKCkge307DQogICAgdmFyIHN1cGVyRnVuY0JvdW5kID0gZnVuY3Rpb24oKSB7DQogICAgICByZXR1cm4gc3VwZXJGdW5jLmFwcGx5KHRhcmdldCwgYXJndW1lbnRzKTsNCiAgICB9Ow0KICAgIHRhcmdldFttZXRob2ROYW1lXSA9IGZ1bmNTb3VyY2Uoc3VwZXJGdW5jQm91bmQpOw0KICB9DQoNCiAgLy8gQWRkIGEgbWV0aG9kIHRvIGRlbGVnYXRvciB0aGF0LCB3aGVuIGludm9rZWQsIGNhbGxzDQogIC8vIGRlbGVnYXRlZS5tZXRob2ROYW1lLiBJZiB0aGVyZSBpcyBubyBzdWNoIG1ldGhvZCBvbg0KICAvLyB0aGUgZGVsZWdhdGVlLCBidXQgdGhlcmUgd2FzIG9uZSBvbiBkZWxlZ2F0b3IgYmVmb3JlDQogIC8vIGRlbGVnYXRlTWV0aG9kIHdhcyBjYWxsZWQsIHRoZW4gdGhlIG9yaWdpbmFsIHZlcnNpb24NCiAgLy8gaXMgaW52b2tlZCBpbnN0ZWFkLg0KICAvLyBGb3IgZXhhbXBsZToNCiAgLy8NCiAgLy8gdmFyIGEgPSB7DQogIC8vICAgbWV0aG9kMTogZnVuY3Rpb24oKSB7IGNvbnNvbGUubG9nKCdhMScpOyB9DQogIC8vICAgbWV0aG9kMjogZnVuY3Rpb24oKSB7IGNvbnNvbGUubG9nKCdhMicpOyB9DQogIC8vIH07DQogIC8vIHZhciBiID0gew0KICAvLyAgIG1ldGhvZDE6IGZ1bmN0aW9uKCkgeyBjb25zb2xlLmxvZygnYjEnKTsgfQ0KICAvLyB9Ow0KICAvLyBkZWxlZ2F0ZU1ldGhvZChhLCBiLCAibWV0aG9kMSIpOw0KICAvLyBkZWxlZ2F0ZU1ldGhvZChhLCBiLCAibWV0aG9kMiIpOw0KICAvLyBhLm1ldGhvZDEoKTsNCiAgLy8gYS5tZXRob2QyKCk7DQogIC8vDQogIC8vIFRoZSBvdXRwdXQgd291bGQgYmUgImIxIiwgImEyIi4NCiAgZnVuY3Rpb24gZGVsZWdhdGVNZXRob2QoZGVsZWdhdG9yLCBkZWxlZ2F0ZWUsIG1ldGhvZE5hbWUpIHsNCiAgICB2YXIgaW5oZXJpdGVkID0gZGVsZWdhdG9yW21ldGhvZE5hbWVdOw0KICAgIGRlbGVnYXRvclttZXRob2ROYW1lXSA9IGZ1bmN0aW9uKCkgew0KICAgICAgdmFyIHRhcmdldCA9IGRlbGVnYXRlZTsNCiAgICAgIHZhciBtZXRob2QgPSBkZWxlZ2F0ZWVbbWV0aG9kTmFtZV07DQoNCiAgICAgIC8vIFRoZSBtZXRob2QgZG9lc24ndCBleGlzdCBvbiB0aGUgZGVsZWdhdGVlLiBJbnN0ZWFkLA0KICAgICAgLy8gY2FsbCB0aGUgbWV0aG9kIG9uIHRoZSBkZWxlZ2F0b3IsIGlmIGl0IGV4aXN0cy4NCiAgICAgIGlmICghbWV0aG9kKSB7DQogICAgICAgIHRhcmdldCA9IGRlbGVnYXRvcjsNCiAgICAgICAgbWV0aG9kID0gaW5oZXJpdGVkOw0KICAgICAgfQ0KDQogICAgICBpZiAobWV0aG9kKSB7DQogICAgICAgIHJldHVybiBtZXRob2QuYXBwbHkodGFyZ2V0LCBhcmd1bWVudHMpOw0KICAgICAgfQ0KICAgIH07DQogIH0NCg0KICAvLyBJbXBsZW1lbnQgYSB2YWd1ZSBmYWNzaW1pbGllIG9mIGpRdWVyeSdzIGRhdGEgbWV0aG9kDQogIGZ1bmN0aW9uIGVsZW1lbnREYXRhKGVsLCBuYW1lLCB2YWx1ZSkgew0KICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09IDIpIHsNCiAgICAgIHJldHVybiBlbFsiaHRtbHdpZGdldF9kYXRhXyIgKyBuYW1lXTsNCiAgICB9IGVsc2UgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT0gMykgew0KICAgICAgZWxbImh0bWx3aWRnZXRfZGF0YV8iICsgbmFtZV0gPSB2YWx1ZTsNCiAgICAgIHJldHVybiBlbDsNCiAgICB9IGVsc2Ugew0KICAgICAgdGhyb3cgbmV3IEVycm9yKCJXcm9uZyBudW1iZXIgb2YgYXJndW1lbnRzIGZvciBlbGVtZW50RGF0YTogIiArDQogICAgICAgIGFyZ3VtZW50cy5sZW5ndGgpOw0KICAgIH0NCiAgfQ0KDQogIC8vIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzQ0NjE3MC9lc2NhcGUtc3RyaW5nLWZvci11c2UtaW4tamF2YXNjcmlwdC1yZWdleA0KICBmdW5jdGlvbiBlc2NhcGVSZWdFeHAoc3RyKSB7DQogICAgcmV0dXJuIHN0ci5yZXBsYWNlKC9bXC1cW1xdXC9ce1x9XChcKVwqXCtcP1wuXFxcXlwkXHxdL2csICJcXCQmIik7DQogIH0NCg0KICBmdW5jdGlvbiBoYXNDbGFzcyhlbCwgY2xhc3NOYW1lKSB7DQogICAgdmFyIHJlID0gbmV3IFJlZ0V4cCgiXFxiIiArIGVzY2FwZVJlZ0V4cChjbGFzc05hbWUpICsgIlxcYiIpOw0KICAgIHJldHVybiByZS50ZXN0KGVsLmNsYXNzTmFtZSk7DQogIH0NCg0KICAvLyBlbGVtZW50cyAtIGFycmF5IChvciBhcnJheS1saWtlIG9iamVjdCkgb2YgSFRNTCBlbGVtZW50cw0KICAvLyBjbGFzc05hbWUgLSBjbGFzcyBuYW1lIHRvIHRlc3QgZm9yDQogIC8vIGluY2x1ZGUgLSBpZiB0cnVlLCBvbmx5IHJldHVybiBlbGVtZW50cyB3aXRoIGdpdmVuIGNsYXNzTmFtZTsNCiAgLy8gICBpZiBmYWxzZSwgb25seSByZXR1cm4gZWxlbWVudHMgKndpdGhvdXQqIGdpdmVuIGNsYXNzTmFtZQ0KICBmdW5jdGlvbiBmaWx0ZXJCeUNsYXNzKGVsZW1lbnRzLCBjbGFzc05hbWUsIGluY2x1ZGUpIHsNCiAgICB2YXIgcmVzdWx0cyA9IFtdOw0KICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlbWVudHMubGVuZ3RoOyBpKyspIHsNCiAgICAgIGlmIChoYXNDbGFzcyhlbGVtZW50c1tpXSwgY2xhc3NOYW1lKSA9PSBpbmNsdWRlKQ0KICAgICAgICByZXN1bHRzLnB1c2goZWxlbWVudHNbaV0pOw0KICAgIH0NCiAgICByZXR1cm4gcmVzdWx0czsNCiAgfQ0KDQogIGZ1bmN0aW9uIG9uKG9iaiwgZXZlbnROYW1lLCBmdW5jKSB7DQogICAgaWYgKG9iai5hZGRFdmVudExpc3RlbmVyKSB7DQogICAgICBvYmouYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGZ1bmMsIGZhbHNlKTsNCiAgICB9IGVsc2UgaWYgKG9iai5hdHRhY2hFdmVudCkgew0KICAgICAgb2JqLmF0dGFjaEV2ZW50KGV2ZW50TmFtZSwgZnVuYyk7DQogICAgfQ0KICB9DQoNCiAgZnVuY3Rpb24gb2ZmKG9iaiwgZXZlbnROYW1lLCBmdW5jKSB7DQogICAgaWYgKG9iai5yZW1vdmVFdmVudExpc3RlbmVyKQ0KICAgICAgb2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBmdW5jLCBmYWxzZSk7DQogICAgZWxzZSBpZiAob2JqLmRldGFjaEV2ZW50KSB7DQogICAgICBvYmouZGV0YWNoRXZlbnQoZXZlbnROYW1lLCBmdW5jKTsNCiAgICB9DQogIH0NCg0KICAvLyBUcmFuc2xhdGUgYXJyYXkgb2YgdmFsdWVzIHRvIHRvcC9yaWdodC9ib3R0b20vbGVmdCwgYXMgdXN1YWwgd2l0aA0KICAvLyB0aGUgInBhZGRpbmciIENTUyBwcm9wZXJ0eQ0KICAvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9DU1MvcGFkZGluZw0KICBmdW5jdGlvbiB1bnBhY2tQYWRkaW5nKHZhbHVlKSB7DQogICAgaWYgKHR5cGVvZih2YWx1ZSkgPT09ICJudW1iZXIiKQ0KICAgICAgdmFsdWUgPSBbdmFsdWVdOw0KICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDEpIHsNCiAgICAgIHJldHVybiB7dG9wOiB2YWx1ZVswXSwgcmlnaHQ6IHZhbHVlWzBdLCBib3R0b206IHZhbHVlWzBdLCBsZWZ0OiB2YWx1ZVswXX07DQogICAgfQ0KICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDIpIHsNCiAgICAgIHJldHVybiB7dG9wOiB2YWx1ZVswXSwgcmlnaHQ6IHZhbHVlWzFdLCBib3R0b206IHZhbHVlWzBdLCBsZWZ0OiB2YWx1ZVsxXX07DQogICAgfQ0KICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDMpIHsNCiAgICAgIHJldHVybiB7dG9wOiB2YWx1ZVswXSwgcmlnaHQ6IHZhbHVlWzFdLCBib3R0b206IHZhbHVlWzJdLCBsZWZ0OiB2YWx1ZVsxXX07DQogICAgfQ0KICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDQpIHsNCiAgICAgIHJldHVybiB7dG9wOiB2YWx1ZVswXSwgcmlnaHQ6IHZhbHVlWzFdLCBib3R0b206IHZhbHVlWzJdLCBsZWZ0OiB2YWx1ZVszXX07DQogICAgfQ0KICB9DQoNCiAgLy8gQ29udmVydCBhbiB1bnBhY2tlZCBwYWRkaW5nIG9iamVjdCB0byBhIENTUyB2YWx1ZQ0KICBmdW5jdGlvbiBwYWRkaW5nVG9Dc3MocGFkZGluZ09iaikgew0KICAgIHJldHVybiBwYWRkaW5nT2JqLnRvcCArICJweCAiICsgcGFkZGluZ09iai5yaWdodCArICJweCAiICsgcGFkZGluZ09iai5ib3R0b20gKyAicHggIiArIHBhZGRpbmdPYmoubGVmdCArICJweCI7DQogIH0NCg0KICAvLyBNYWtlcyBhIG51bWJlciBzdWl0YWJsZSBmb3IgQ1NTDQogIGZ1bmN0aW9uIHB4KHgpIHsNCiAgICBpZiAodHlwZW9mKHgpID09PSAibnVtYmVyIikNCiAgICAgIHJldHVybiB4ICsgInB4IjsNCiAgICBlbHNlDQogICAgICByZXR1cm4geDsNCiAgfQ0KDQogIC8vIFJldHJpZXZlcyBydW50aW1lIHdpZGdldCBzaXppbmcgaW5mb3JtYXRpb24gZm9yIGFuIGVsZW1lbnQuDQogIC8vIFRoZSByZXR1cm4gdmFsdWUgaXMgZWl0aGVyIG51bGwsIG9yIGFuIG9iamVjdCB3aXRoIGZpbGwsIHBhZGRpbmcsDQogIC8vIGRlZmF1bHRXaWR0aCwgZGVmYXVsdEhlaWdodCBmaWVsZHMuDQogIGZ1bmN0aW9uIHNpemluZ1BvbGljeShlbCkgew0KICAgIHZhciBzaXppbmdFbCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoInNjcmlwdFtkYXRhLWZvcj0nIiArIGVsLmlkICsgIiddW3R5cGU9J2FwcGxpY2F0aW9uL2h0bWx3aWRnZXQtc2l6aW5nJ10iKTsNCiAgICBpZiAoIXNpemluZ0VsKQ0KICAgICAgcmV0dXJuIG51bGw7DQogICAgdmFyIHNwID0gSlNPTi5wYXJzZShzaXppbmdFbC50ZXh0Q29udGVudCB8fCBzaXppbmdFbC50ZXh0IHx8ICJ7fSIpOw0KICAgIGlmICh2aWV3ZXJNb2RlKSB7DQogICAgICByZXR1cm4gc3Audmlld2VyOw0KICAgIH0gZWxzZSB7DQogICAgICByZXR1cm4gc3AuYnJvd3NlcjsNCiAgICB9DQogIH0NCg0KICAvLyBAcGFyYW0gdGFza3MgQXJyYXkgb2Ygc3RyaW5ncyAob3IgZmFsc3kgdmFsdWUsIGluIHdoaWNoIGNhc2Ugbm8tb3ApLg0KICAvLyAgIEVhY2ggZWxlbWVudCBtdXN0IGJlIGEgdmFsaWQgSmF2YVNjcmlwdCBleHByZXNzaW9uIHRoYXQgeWllbGRzIGENCiAgLy8gICBmdW5jdGlvbi4gT3IsIGNhbiBiZSBhbiBhcnJheSBvZiBvYmplY3RzIHdpdGggImNvZGUiIGFuZCAiZGF0YSINCiAgLy8gICBwcm9wZXJ0aWVzOyBpbiB0aGlzIGNhc2UsIHRoZSAiY29kZSIgcHJvcGVydHkgc2hvdWxkIGJlIGEgc3RyaW5nDQogIC8vICAgb2YgSlMgdGhhdCdzIGFuIGV4cHIgdGhhdCB5aWVsZHMgYSBmdW5jdGlvbiwgYW5kICJkYXRhIiBzaG91bGQgYmUNCiAgLy8gICBhbiBvYmplY3QgdGhhdCB3aWxsIGJlIGFkZGVkIGFzIGFuIGFkZGl0aW9uYWwgYXJndW1lbnQgd2hlbiB0aGF0DQogIC8vICAgZnVuY3Rpb24gaXMgY2FsbGVkLg0KICAvLyBAcGFyYW0gdGFyZ2V0IFRoZSBvYmplY3QgdGhhdCB3aWxsIGJlICJ0aGlzIiBmb3IgZWFjaCBmdW5jdGlvbg0KICAvLyAgIGV4ZWN1dGlvbi4NCiAgLy8gQHBhcmFtIGFyZ3MgQXJyYXkgb2YgYXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb25zLiAoVGhlDQogIC8vICAgc2FtZSBhcmd1bWVudHMgd2lsbCBiZSBwYXNzZWQgdG8gYWxsIGZ1bmN0aW9ucy4pDQogIGZ1bmN0aW9uIGV2YWxBbmRSdW4odGFza3MsIHRhcmdldCwgYXJncykgew0KICAgIGlmICh0YXNrcykgew0KICAgICAgZm9yRWFjaCh0YXNrcywgZnVuY3Rpb24odGFzaykgew0KICAgICAgICB2YXIgdGhlc2VBcmdzID0gYXJnczsNCiAgICAgICAgaWYgKHR5cGVvZih0YXNrKSA9PT0gIm9iamVjdCIpIHsNCiAgICAgICAgICB0aGVzZUFyZ3MgPSB0aGVzZUFyZ3MuY29uY2F0KFt0YXNrLmRhdGFdKTsNCiAgICAgICAgICB0YXNrID0gdGFzay5jb2RlOw0KICAgICAgICB9DQogICAgICAgIHZhciB0YXNrRnVuYyA9IGV2YWwoIigiICsgdGFzayArICIpIik7DQogICAgICAgIGlmICh0eXBlb2YodGFza0Z1bmMpICE9PSAiZnVuY3Rpb24iKSB7DQogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJUYXNrIG11c3QgYmUgYSBmdW5jdGlvbiEgU291cmNlOlxuIiArIHRhc2spOw0KICAgICAgICB9DQogICAgICAgIHRhc2tGdW5jLmFwcGx5KHRhcmdldCwgdGhlc2VBcmdzKTsNCiAgICAgIH0pOw0KICAgIH0NCiAgfQ0KDQogIGZ1bmN0aW9uIGluaXRTaXppbmcoZWwpIHsNCiAgICB2YXIgc2l6aW5nID0gc2l6aW5nUG9saWN5KGVsKTsNCiAgICBpZiAoIXNpemluZykNCiAgICAgIHJldHVybjsNCg0KICAgIHZhciBjZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgiaHRtbHdpZGdldF9jb250YWluZXIiKTsNCiAgICBpZiAoIWNlbCkNCiAgICAgIHJldHVybjsNCg0KICAgIGlmICh0eXBlb2Yoc2l6aW5nLnBhZGRpbmcpICE9PSAidW5kZWZpbmVkIikgew0KICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAiMCI7DQogICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnBhZGRpbmcgPSBwYWRkaW5nVG9Dc3ModW5wYWNrUGFkZGluZyhzaXppbmcucGFkZGluZykpOw0KICAgIH0NCg0KICAgIGlmIChzaXppbmcuZmlsbCkgew0KICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5vdmVyZmxvdyA9ICJoaWRkZW4iOw0KICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS53aWR0aCA9ICIxMDAlIjsNCiAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuaGVpZ2h0ID0gIjEwMCUiOw0KICAgICAgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLndpZHRoID0gIjEwMCUiOw0KICAgICAgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLmhlaWdodCA9ICIxMDAlIjsNCiAgICAgIGlmIChjZWwpIHsNCiAgICAgICAgY2VsLnN0eWxlLnBvc2l0aW9uID0gImFic29sdXRlIjsNCiAgICAgICAgdmFyIHBhZCA9IHVucGFja1BhZGRpbmcoc2l6aW5nLnBhZGRpbmcpOw0KICAgICAgICBjZWwuc3R5bGUudG9wID0gcGFkLnRvcCArICJweCI7DQogICAgICAgIGNlbC5zdHlsZS5yaWdodCA9IHBhZC5yaWdodCArICJweCI7DQogICAgICAgIGNlbC5zdHlsZS5ib3R0b20gPSBwYWQuYm90dG9tICsgInB4IjsNCiAgICAgICAgY2VsLnN0eWxlLmxlZnQgPSBwYWQubGVmdCArICJweCI7DQogICAgICAgIGVsLnN0eWxlLndpZHRoID0gIjEwMCUiOw0KICAgICAgICBlbC5zdHlsZS5oZWlnaHQgPSAiMTAwJSI7DQogICAgICB9DQoNCiAgICAgIHJldHVybiB7DQogICAgICAgIGdldFdpZHRoOiBmdW5jdGlvbigpIHsgcmV0dXJuIGNlbC5vZmZzZXRXaWR0aDsgfSwNCiAgICAgICAgZ2V0SGVpZ2h0OiBmdW5jdGlvbigpIHsgcmV0dXJuIGNlbC5vZmZzZXRIZWlnaHQ7IH0NCiAgICAgIH07DQoNCiAgICB9IGVsc2Ugew0KICAgICAgZWwuc3R5bGUud2lkdGggPSBweChzaXppbmcud2lkdGgpOw0KICAgICAgZWwuc3R5bGUuaGVpZ2h0ID0gcHgoc2l6aW5nLmhlaWdodCk7DQoNCiAgICAgIHJldHVybiB7DQogICAgICAgIGdldFdpZHRoOiBmdW5jdGlvbigpIHsgcmV0dXJuIGVsLm9mZnNldFdpZHRoOyB9LA0KICAgICAgICBnZXRIZWlnaHQ6IGZ1bmN0aW9uKCkgeyByZXR1cm4gZWwub2Zmc2V0SGVpZ2h0OyB9DQogICAgICB9Ow0KICAgIH0NCiAgfQ0KDQogIC8vIERlZmF1bHQgaW1wbGVtZW50YXRpb25zIGZvciBtZXRob2RzDQogIHZhciBkZWZhdWx0cyA9IHsNCiAgICBmaW5kOiBmdW5jdGlvbihzY29wZSkgew0KICAgICAgcmV0dXJuIHF1ZXJ5U2VsZWN0b3JBbGwoc2NvcGUsICIuIiArIHRoaXMubmFtZSk7DQogICAgfSwNCiAgICByZW5kZXJFcnJvcjogZnVuY3Rpb24oZWwsIGVycikgew0KICAgICAgdmFyICRlbCA9ICQoZWwpOw0KDQogICAgICB0aGlzLmNsZWFyRXJyb3IoZWwpOw0KDQogICAgICAvLyBBZGQgYWxsIHRoZXNlIGVycm9yIGNsYXNzZXMsIGFzIFNoaW55IGRvZXMNCiAgICAgIHZhciBlcnJDbGFzcyA9ICJzaGlueS1vdXRwdXQtZXJyb3IiOw0KICAgICAgaWYgKGVyci50eXBlICE9PSBudWxsKSB7DQogICAgICAgIC8vIHVzZSB0aGUgY2xhc3NlcyBvZiB0aGUgZXJyb3IgY29uZGl0aW9uIGFzIENTUyBjbGFzcyBuYW1lcw0KICAgICAgICBlcnJDbGFzcyA9IGVyckNsYXNzICsgIiAiICsgJC5tYXAoYXNBcnJheShlcnIudHlwZSksIGZ1bmN0aW9uKHR5cGUpIHsNCiAgICAgICAgICByZXR1cm4gZXJyQ2xhc3MgKyAiLSIgKyB0eXBlOw0KICAgICAgICB9KS5qb2luKCIgIik7DQogICAgICB9DQogICAgICBlcnJDbGFzcyA9IGVyckNsYXNzICsgIiBodG1sd2lkZ2V0cy1lcnJvciI7DQoNCiAgICAgIC8vIElzIGVsIGlubGluZSBvciBibG9jaz8gSWYgaW5saW5lIG9yIGlubGluZS1ibG9jaywganVzdCBkaXNwbGF5Om5vbmUgaXQNCiAgICAgIC8vIGFuZCBhZGQgYW4gaW5saW5lIGVycm9yLg0KICAgICAgdmFyIGRpc3BsYXkgPSAkZWwuY3NzKCJkaXNwbGF5Iik7DQogICAgICAkZWwuZGF0YSgicmVzdG9yZS1kaXNwbGF5LW1vZGUiLCBkaXNwbGF5KTsNCg0KICAgICAgaWYgKGRpc3BsYXkgPT09ICJpbmxpbmUiIHx8IGRpc3BsYXkgPT09ICJpbmxpbmUtYmxvY2siKSB7DQogICAgICAgICRlbC5oaWRlKCk7DQogICAgICAgIGlmIChlcnIubWVzc2FnZSAhPT0gIiIpIHsNCiAgICAgICAgICB2YXIgZXJyb3JTcGFuID0gJCgiPHNwYW4+IikuYWRkQ2xhc3MoZXJyQ2xhc3MpOw0KICAgICAgICAgIGVycm9yU3Bhbi50ZXh0KGVyci5tZXNzYWdlKTsNCiAgICAgICAgICAkZWwuYWZ0ZXIoZXJyb3JTcGFuKTsNCiAgICAgICAgfQ0KICAgICAgfSBlbHNlIGlmIChkaXNwbGF5ID09PSAiYmxvY2siKSB7DQogICAgICAgIC8vIElmIGJsb2NrLCBhZGQgYW4gZXJyb3IganVzdCBhZnRlciB0aGUgZWwsIHNldCB2aXNpYmlsaXR5Om5vbmUgb24gdGhlDQogICAgICAgIC8vIGVsLCBhbmQgcG9zaXRpb24gdGhlIGVycm9yIHRvIGJlIG9uIHRvcCBvZiB0aGUgZWwuDQogICAgICAgIC8vIE1hcmsgaXQgd2l0aCBhIHVuaXF1ZSBJRCBhbmQgQ1NTIGNsYXNzIHNvIHdlIGNhbiByZW1vdmUgaXQgbGF0ZXIuDQogICAgICAgICRlbC5jc3MoInZpc2liaWxpdHkiLCAiaGlkZGVuIik7DQogICAgICAgIGlmIChlcnIubWVzc2FnZSAhPT0gIiIpIHsNCiAgICAgICAgICB2YXIgZXJyb3JEaXYgPSAkKCI8ZGl2PiIpLmFkZENsYXNzKGVyckNsYXNzKS5jc3MoInBvc2l0aW9uIiwgImFic29sdXRlIikNCiAgICAgICAgICAgIC5jc3MoInRvcCIsIGVsLm9mZnNldFRvcCkNCiAgICAgICAgICAgIC5jc3MoImxlZnQiLCBlbC5vZmZzZXRMZWZ0KQ0KICAgICAgICAgICAgLy8gc2V0dGluZyB3aWR0aCBjYW4gcHVzaCBvdXQgdGhlIHBhZ2Ugc2l6ZSwgZm9yY2luZyBvdGhlcndpc2UNCiAgICAgICAgICAgIC8vIHVubmVjZXNzYXJ5IHNjcm9sbGJhcnMgdG8gYXBwZWFyIGFuZCBtYWtpbmcgaXQgaW1wb3NzaWJsZSBmb3INCiAgICAgICAgICAgIC8vIHRoZSBlbGVtZW50IHRvIHNocmluazsgc28gdXNlIG1heC13aWR0aCBpbnN0ZWFkDQogICAgICAgICAgICAuY3NzKCJtYXhXaWR0aCIsIGVsLm9mZnNldFdpZHRoKQ0KICAgICAgICAgICAgLmNzcygiaGVpZ2h0IiwgZWwub2Zmc2V0SGVpZ2h0KTsNCiAgICAgICAgICBlcnJvckRpdi50ZXh0KGVyci5tZXNzYWdlKTsNCiAgICAgICAgICAkZWwuYWZ0ZXIoZXJyb3JEaXYpOw0KDQogICAgICAgICAgLy8gUmVhbGx5IGR1bWIgd2F5IHRvIGtlZXAgdGhlIHNpemUvcG9zaXRpb24gb2YgdGhlIGVycm9yIGluIHN5bmMgd2l0aA0KICAgICAgICAgIC8vIHRoZSBwYXJlbnQgZWxlbWVudCBhcyB0aGUgd2luZG93IGlzIHJlc2l6ZWQgb3Igd2hhdGV2ZXIuDQogICAgICAgICAgdmFyIGludElkID0gc2V0SW50ZXJ2YWwoZnVuY3Rpb24oKSB7DQogICAgICAgICAgICBpZiAoIWVycm9yRGl2WzBdLnBhcmVudEVsZW1lbnQpIHsNCiAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbChpbnRJZCk7DQogICAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGVycm9yRGl2DQogICAgICAgICAgICAgIC5jc3MoInRvcCIsIGVsLm9mZnNldFRvcCkNCiAgICAgICAgICAgICAgLmNzcygibGVmdCIsIGVsLm9mZnNldExlZnQpDQogICAgICAgICAgICAgIC5jc3MoIm1heFdpZHRoIiwgZWwub2Zmc2V0V2lkdGgpDQogICAgICAgICAgICAgIC5jc3MoImhlaWdodCIsIGVsLm9mZnNldEhlaWdodCk7DQogICAgICAgICAgfSwgNTAwKTsNCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIH0sDQogICAgY2xlYXJFcnJvcjogZnVuY3Rpb24oZWwpIHsNCiAgICAgIHZhciAkZWwgPSAkKGVsKTsNCiAgICAgIHZhciBkaXNwbGF5ID0gJGVsLmRhdGEoInJlc3RvcmUtZGlzcGxheS1tb2RlIik7DQogICAgICAkZWwuZGF0YSgicmVzdG9yZS1kaXNwbGF5LW1vZGUiLCBudWxsKTsNCg0KICAgICAgaWYgKGRpc3BsYXkgPT09ICJpbmxpbmUiIHx8IGRpc3BsYXkgPT09ICJpbmxpbmUtYmxvY2siKSB7DQogICAgICAgIGlmIChkaXNwbGF5KQ0KICAgICAgICAgICRlbC5jc3MoImRpc3BsYXkiLCBkaXNwbGF5KTsNCiAgICAgICAgJChlbC5uZXh0U2libGluZykuZmlsdGVyKCIuaHRtbHdpZGdldHMtZXJyb3IiKS5yZW1vdmUoKTsNCiAgICAgIH0gZWxzZSBpZiAoZGlzcGxheSA9PT0gImJsb2NrIil7DQogICAgICAgICRlbC5jc3MoInZpc2liaWxpdHkiLCAiaW5oZXJpdCIpOw0KICAgICAgICAkKGVsLm5leHRTaWJsaW5nKS5maWx0ZXIoIi5odG1sd2lkZ2V0cy1lcnJvciIpLnJlbW92ZSgpOw0KICAgICAgfQ0KICAgIH0sDQogICAgc2l6aW5nOiB7fQ0KICB9Ow0KDQogIC8vIENhbGxlZCBieSB3aWRnZXQgYmluZGluZ3MgdG8gcmVnaXN0ZXIgYSBuZXcgdHlwZSBvZiB3aWRnZXQuIFRoZSBkZWZpbml0aW9uDQogIC8vIG9iamVjdCBjYW4gY29udGFpbiB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6DQogIC8vIC0gbmFtZSAocmVxdWlyZWQpIC0gQSBzdHJpbmcgaW5kaWNhdGluZyB0aGUgYmluZGluZyBuYW1lLCB3aGljaCB3aWxsIGJlDQogIC8vICAgdXNlZCBieSBkZWZhdWx0IGFzIHRoZSBDU1MgY2xhc3NuYW1lIHRvIGxvb2sgZm9yLg0KICAvLyAtIGluaXRpYWxpemUgKG9wdGlvbmFsKSAtIEEgZnVuY3Rpb24oZWwpIHRoYXQgd2lsbCBiZSBjYWxsZWQgb25jZSBwZXINCiAgLy8gICB3aWRnZXQgZWxlbWVudDsgaWYgYSB2YWx1ZSBpcyByZXR1cm5lZCwgaXQgd2lsbCBiZSBwYXNzZWQgYXMgdGhlIHRoaXJkDQogIC8vICAgdmFsdWUgdG8gcmVuZGVyVmFsdWUuDQogIC8vIC0gcmVuZGVyVmFsdWUgKHJlcXVpcmVkKSAtIEEgZnVuY3Rpb24oZWwsIGRhdGEsIGluaXRWYWx1ZSkgdGhhdCB3aWxsIGJlDQogIC8vICAgY2FsbGVkIHdpdGggZGF0YS4gU3RhdGljIGNvbnRleHRzIHdpbGwgY2F1c2UgdGhpcyB0byBiZSBjYWxsZWQgb25jZSBwZXINCiAgLy8gICBlbGVtZW50OyBTaGlueSBhcHBzIHdpbGwgY2F1c2UgdGhpcyB0byBiZSBjYWxsZWQgbXVsdGlwbGUgdGltZXMgcGVyDQogIC8vICAgZWxlbWVudCwgYXMgdGhlIGRhdGEgY2hhbmdlcy4NCiAgd2luZG93LkhUTUxXaWRnZXRzLndpZGdldCA9IGZ1bmN0aW9uKGRlZmluaXRpb24pIHsNCiAgICBpZiAoIWRlZmluaXRpb24ubmFtZSkgew0KICAgICAgdGhyb3cgbmV3IEVycm9yKCJXaWRnZXQgbXVzdCBoYXZlIGEgbmFtZSIpOw0KICAgIH0NCiAgICBpZiAoIWRlZmluaXRpb24udHlwZSkgew0KICAgICAgdGhyb3cgbmV3IEVycm9yKCJXaWRnZXQgbXVzdCBoYXZlIGEgdHlwZSIpOw0KICAgIH0NCiAgICAvLyBDdXJyZW50bHkgd2Ugb25seSBzdXBwb3J0IG91dHB1dCB3aWRnZXRzDQogICAgaWYgKGRlZmluaXRpb24udHlwZSAhPT0gIm91dHB1dCIpIHsNCiAgICAgIHRocm93IG5ldyBFcnJvcigiVW5yZWNvZ25pemVkIHdpZGdldCB0eXBlICciICsgZGVmaW5pdGlvbi50eXBlICsgIiciKTsNCiAgICB9DQogICAgLy8gVE9ETzogVmVyaWZ5IHRoYXQgLm5hbWUgaXMgYSB2YWxpZCBDU1MgY2xhc3NuYW1lDQoNCiAgICAvLyBTdXBwb3J0IG5ldy1zdHlsZSBpbnN0YW5jZS1ib3VuZCBkZWZpbml0aW9ucy4gT2xkLXN0eWxlIGNsYXNzLWJvdW5kDQogICAgLy8gZGVmaW5pdGlvbnMgaGF2ZSBvbmUgd2lkZ2V0ICJvYmplY3QiIHBlciB3aWRnZXQgcGVyIHR5cGUvY2xhc3Mgb2YNCiAgICAvLyB3aWRnZXQ7IHRoZSByZW5kZXJWYWx1ZSBhbmQgcmVzaXplIG1ldGhvZHMgb24gc3VjaCB3aWRnZXQgb2JqZWN0cw0KICAgIC8vIHRha2UgZWwgYW5kIGluc3RhbmNlIGFyZ3VtZW50cywgYmVjYXVzZSB0aGUgd2lkZ2V0IG9iamVjdCBjYW4ndA0KICAgIC8vIHN0b3JlIHRoZW0uIE5ldy1zdHlsZSBpbnN0YW5jZS1ib3VuZCBkZWZpbml0aW9ucyBoYXZlIG9uZSB3aWRnZXQNCiAgICAvLyBvYmplY3QgcGVyIHdpZGdldCBpbnN0YW5jZTsgdGhlIGRlZmluaXRpb24gdGhhdCdzIHBhc3NlZCBpbiBkb2Vzbid0DQogICAgLy8gcHJvdmlkZSByZW5kZXJWYWx1ZSBvciByZXNpemUgbWV0aG9kcyBhdCBhbGwsIGp1c3QgdGhlIHNpbmdsZSBtZXRob2QNCiAgICAvLyAgIGZhY3RvcnkoZWwsIHdpZHRoLCBoZWlnaHQpDQogICAgLy8gd2hpY2ggcmV0dXJucyBhbiBvYmplY3QgdGhhdCBoYXMgcmVuZGVyVmFsdWUoeCkgYW5kIHJlc2l6ZSh3LCBoKS4NCiAgICAvLyBUaGlzIGVuYWJsZXMgYSBmYXIgbW9yZSBuYXR1cmFsIHByb2dyYW1taW5nIHN0eWxlIGZvciB0aGUgd2lkZ2V0DQogICAgLy8gYXV0aG9yLCB3aG8gY2FuIHN0b3JlIHBlci1pbnN0YW5jZSBzdGF0ZSB1c2luZyBlaXRoZXIgT08tc3R5bGUNCiAgICAvLyBpbnN0YW5jZSBmaWVsZHMgb3IgZnVuY3Rpb25hbC1zdHlsZSBjbG9zdXJlIHZhcmlhYmxlcyAoSSBndWVzcyB0aGlzDQogICAgLy8gaXMgaW4gY29udHJhc3QgdG8gd2hhdCBjYW4gb25seSBiZSBjYWxsZWQgQy1zdHlsZSBwc2V1ZG8tT08gd2hpY2ggaXMNCiAgICAvLyB3aGF0IHdlIHJlcXVpcmVkIGJlZm9yZSkuDQogICAgaWYgKGRlZmluaXRpb24uZmFjdG9yeSkgew0KICAgICAgZGVmaW5pdGlvbiA9IGNyZWF0ZUxlZ2FjeURlZmluaXRpb25BZGFwdGVyKGRlZmluaXRpb24pOw0KICAgIH0NCg0KICAgIGlmICghZGVmaW5pdGlvbi5yZW5kZXJWYWx1ZSkgew0KICAgICAgdGhyb3cgbmV3IEVycm9yKCJXaWRnZXQgbXVzdCBoYXZlIGEgcmVuZGVyVmFsdWUgZnVuY3Rpb24iKTsNCiAgICB9DQoNCiAgICAvLyBGb3Igc3RhdGljIHJlbmRlcmluZyAobm9uLVNoaW55KSwgdXNlIGEgc2ltcGxlIHdpZGdldCByZWdpc3RyYXRpb24NCiAgICAvLyBzY2hlbWUuIFdlIGFsc28gdXNlIHRoaXMgc2NoZW1lIGZvciBTaGlueSBhcHBzL2RvY3VtZW50cyB0aGF0IGFsc28NCiAgICAvLyBjb250YWluIHN0YXRpYyB3aWRnZXRzLg0KICAgIHdpbmRvdy5IVE1MV2lkZ2V0cy53aWRnZXRzID0gd2luZG93LkhUTUxXaWRnZXRzLndpZGdldHMgfHwgW107DQogICAgLy8gTWVyZ2UgZGVmYXVsdHMgaW50byB0aGUgZGVmaW5pdGlvbjsgZG9uJ3QgbXV0YXRlIHRoZSBvcmlnaW5hbCBkZWZpbml0aW9uLg0KICAgIHZhciBzdGF0aWNCaW5kaW5nID0gZXh0ZW5kKHt9LCBkZWZhdWx0cywgZGVmaW5pdGlvbik7DQogICAgb3ZlcnJpZGVNZXRob2Qoc3RhdGljQmluZGluZywgImZpbmQiLCBmdW5jdGlvbihzdXBlcmZ1bmMpIHsNCiAgICAgIHJldHVybiBmdW5jdGlvbihzY29wZSkgew0KICAgICAgICB2YXIgcmVzdWx0cyA9IHN1cGVyZnVuYyhzY29wZSk7DQogICAgICAgIC8vIEZpbHRlciBvdXQgU2hpbnkgb3V0cHV0cywgd2Ugb25seSB3YW50IHRoZSBzdGF0aWMga2luZA0KICAgICAgICByZXR1cm4gZmlsdGVyQnlDbGFzcyhyZXN1bHRzLCAiaHRtbC13aWRnZXQtb3V0cHV0IiwgZmFsc2UpOw0KICAgICAgfTsNCiAgICB9KTsNCiAgICB3aW5kb3cuSFRNTFdpZGdldHMud2lkZ2V0cy5wdXNoKHN0YXRpY0JpbmRpbmcpOw0KDQogICAgaWYgKHNoaW55TW9kZSkgew0KICAgICAgLy8gU2hpbnkgaXMgcnVubmluZy4gUmVnaXN0ZXIgdGhlIGRlZmluaXRpb24gd2l0aCBhbiBvdXRwdXQgYmluZGluZy4NCiAgICAgIC8vIFRoZSBkZWZpbml0aW9uIGl0c2VsZiB3aWxsIG5vdCBiZSB0aGUgb3V0cHV0IGJpbmRpbmcsIGluc3RlYWQNCiAgICAgIC8vIHdlIHdpbGwgbWFrZSBhbiBvdXRwdXQgYmluZGluZyBvYmplY3QgdGhhdCBkZWxlZ2F0ZXMgdG8gdGhlDQogICAgICAvLyBkZWZpbml0aW9uLiBUaGlzIGlzIGJlY2F1c2Ugd2UgZm9vbGlzaGx5IHVzZWQgdGhlIHNhbWUgbWV0aG9kDQogICAgICAvLyBuYW1lIChyZW5kZXJWYWx1ZSkgZm9yIGh0bWx3aWRnZXRzIGRlZmluaXRpb24gYW5kIFNoaW55IGJpbmRpbmdzDQogICAgICAvLyBidXQgdGhleSBhY3R1YWxseSBoYXZlIHF1aXRlIGRpZmZlcmVudCBzZW1hbnRpY3MgKHRoZSBTaGlueQ0KICAgICAgLy8gYmluZGluZ3MgcmVjZWl2ZSBkYXRhIHRoYXQgaW5jbHVkZXMgbG90cyBvZiBtZXRhZGF0YSB0aGF0IGl0DQogICAgICAvLyBzdHJpcHMgb2ZmIGJlZm9yZSBjYWxsaW5nIGh0bWx3aWRnZXRzIHJlbmRlclZhbHVlKS4gV2UgY2FuJ3QNCiAgICAgIC8vIGp1c3QgaWdub3JlIHRoZSBkaWZmZXJlbmNlIGJlY2F1c2UgaW4gc29tZSB3aWRnZXRzIGl0J3MgaGVscGZ1bA0KICAgICAgLy8gdG8gY2FsbCB0aGlzLnJlbmRlclZhbHVlKCkgZnJvbSBpbnNpZGUgb2YgcmVzaXplKCksIGFuZCBpZg0KICAgICAgLy8gd2UncmUgbm90IGRlbGVnYXRpbmcsIHRoZW4gdGhhdCBjYWxsIHdpbGwgZ28gdG8gdGhlIFNoaW55DQogICAgICAvLyB2ZXJzaW9uIGluc3RlYWQgb2YgdGhlIGh0bWx3aWRnZXRzIHZlcnNpb24uDQoNCiAgICAgIC8vIE1lcmdlIGRlZmF1bHRzIHdpdGggZGVmaW5pdGlvbiwgd2l0aG91dCBtdXRhdGluZyBlaXRoZXIuDQogICAgICB2YXIgYmluZGluZ0RlZiA9IGV4dGVuZCh7fSwgZGVmYXVsdHMsIGRlZmluaXRpb24pOw0KDQogICAgICAvLyBUaGlzIG9iamVjdCB3aWxsIGJlIG91ciBhY3R1YWwgU2hpbnkgYmluZGluZy4NCiAgICAgIHZhciBzaGlueUJpbmRpbmcgPSBuZXcgU2hpbnkuT3V0cHV0QmluZGluZygpOw0KDQogICAgICAvLyBXaXRoIGEgZmV3IGV4Y2VwdGlvbnMsIHdlJ2xsIHdhbnQgdG8gc2ltcGx5IHVzZSB0aGUgYmluZGluZ0RlZidzDQogICAgICAvLyB2ZXJzaW9uIG9mIG1ldGhvZHMgaWYgdGhleSBhcmUgYXZhaWxhYmxlLCBvdGhlcndpc2UgZmFsbCBiYWNrIHRvDQogICAgICAvLyBTaGlueSdzIGRlZmF1bHRzLiBOT1RFOiBJZiBTaGlueSdzIG91dHB1dCBiaW5kaW5ncyBnYWluIGFkZGl0aW9uYWwNCiAgICAgIC8vIG1ldGhvZHMgaW4gdGhlIGZ1dHVyZSwgYW5kIHdlIHdhbnQgdGhlbSB0byBiZSBvdmVycmlkZWFibGUgYnkNCiAgICAgIC8vIEhUTUxXaWRnZXQgYmluZGluZyBkZWZpbml0aW9ucywgdGhlbiB3ZSdsbCBuZWVkIHRvIGFkZCB0aGVtIHRvIHRoaXMNCiAgICAgIC8vIGxpc3QuDQogICAgICBkZWxlZ2F0ZU1ldGhvZChzaGlueUJpbmRpbmcsIGJpbmRpbmdEZWYsICJnZXRJZCIpOw0KICAgICAgZGVsZWdhdGVNZXRob2Qoc2hpbnlCaW5kaW5nLCBiaW5kaW5nRGVmLCAib25WYWx1ZUNoYW5nZSIpOw0KICAgICAgZGVsZWdhdGVNZXRob2Qoc2hpbnlCaW5kaW5nLCBiaW5kaW5nRGVmLCAib25WYWx1ZUVycm9yIik7DQogICAgICBkZWxlZ2F0ZU1ldGhvZChzaGlueUJpbmRpbmcsIGJpbmRpbmdEZWYsICJyZW5kZXJFcnJvciIpOw0KICAgICAgZGVsZWdhdGVNZXRob2Qoc2hpbnlCaW5kaW5nLCBiaW5kaW5nRGVmLCAiY2xlYXJFcnJvciIpOw0KICAgICAgZGVsZWdhdGVNZXRob2Qoc2hpbnlCaW5kaW5nLCBiaW5kaW5nRGVmLCAic2hvd1Byb2dyZXNzIik7DQoNCiAgICAgIC8vIFRoZSBmaW5kLCByZW5kZXJWYWx1ZSwgYW5kIHJlc2l6ZSBhcmUgaGFuZGxlZCBkaWZmZXJlbnRseSwgYmVjYXVzZSB3ZQ0KICAgICAgLy8gd2FudCB0byBhY3R1YWxseSBkZWNvcmF0ZSB0aGUgYmVoYXZpb3Igb2YgdGhlIGJpbmRpbmdEZWYgbWV0aG9kcy4NCg0KICAgICAgc2hpbnlCaW5kaW5nLmZpbmQgPSBmdW5jdGlvbihzY29wZSkgew0KICAgICAgICB2YXIgcmVzdWx0cyA9IGJpbmRpbmdEZWYuZmluZChzY29wZSk7DQoNCiAgICAgICAgLy8gT25seSByZXR1cm4gZWxlbWVudHMgdGhhdCBhcmUgU2hpbnkgb3V0cHV0cywgbm90IHN0YXRpYyBvbmVzDQogICAgICAgIHZhciBkeW5hbWljUmVzdWx0cyA9IHJlc3VsdHMuZmlsdGVyKCIuaHRtbC13aWRnZXQtb3V0cHV0Iik7DQoNCiAgICAgICAgLy8gSXQncyBwb3NzaWJsZSB0aGF0IHdoYXRldmVyIGNhdXNlZCBTaGlueSB0byB0aGluayB0aGVyZSBtaWdodCBiZQ0KICAgICAgICAvLyBuZXcgZHluYW1pYyBvdXRwdXRzLCBhbHNvIGNhdXNlZCB0aGVyZSB0byBiZSBuZXcgc3RhdGljIG91dHB1dHMuDQogICAgICAgIC8vIFNpbmNlIHRoZXJlIG1pZ2h0IGJlIGxvdHMgb2YgZGlmZmVyZW50IGh0bWx3aWRnZXRzIGJpbmRpbmdzLCB3ZQ0KICAgICAgICAvLyBzY2hlZHVsZSBleGVjdXRpb24gZm9yIGxhdGVyLS1ubyBuZWVkIHRvIHN0YXRpY1JlbmRlciBtdWx0aXBsZQ0KICAgICAgICAvLyB0aW1lcy4NCiAgICAgICAgaWYgKHJlc3VsdHMubGVuZ3RoICE9PSBkeW5hbWljUmVzdWx0cy5sZW5ndGgpDQogICAgICAgICAgc2NoZWR1bGVTdGF0aWNSZW5kZXIoKTsNCg0KICAgICAgICByZXR1cm4gZHluYW1pY1Jlc3VsdHM7DQogICAgICB9Ow0KDQogICAgICAvLyBXcmFwIHJlbmRlclZhbHVlIHRvIGhhbmRsZSBpbml0aWFsaXphdGlvbiwgd2hpY2ggdW5mb3J0dW5hdGVseSBpc24ndA0KICAgICAgLy8gc3VwcG9ydGVkIG5hdGl2ZWx5IGJ5IFNoaW55IGF0IHRoZSB0aW1lIG9mIHRoaXMgd3JpdGluZy4NCg0KICAgICAgc2hpbnlCaW5kaW5nLnJlbmRlclZhbHVlID0gZnVuY3Rpb24oZWwsIGRhdGEpIHsNCiAgICAgICAgLy8gUmVzb2x2ZSBzdHJpbmdzIG1hcmtlZCBhcyBqYXZhc2NyaXB0IGxpdGVyYWxzIHRvIG9iamVjdHMNCiAgICAgICAgaWYgKCEoZGF0YS5ldmFscyBpbnN0YW5jZW9mIEFycmF5KSkgZGF0YS5ldmFscyA9IFtkYXRhLmV2YWxzXTsNCiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGRhdGEuZXZhbHMgJiYgaSA8IGRhdGEuZXZhbHMubGVuZ3RoOyBpKyspIHsNCiAgICAgICAgICB3aW5kb3cuSFRNTFdpZGdldHMuZXZhbHVhdGVTdHJpbmdNZW1iZXIoZGF0YS54LCBkYXRhLmV2YWxzW2ldKTsNCiAgICAgICAgfQ0KICAgICAgICBpZiAoIWJpbmRpbmdEZWYucmVuZGVyT25OdWxsVmFsdWUpIHsNCiAgICAgICAgICBpZiAoZGF0YS54ID09PSBudWxsKSB7DQogICAgICAgICAgICBlbC5zdHlsZS52aXNpYmlsaXR5ID0gImhpZGRlbiI7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICAgIGVsLnN0eWxlLnZpc2liaWxpdHkgPSAiaW5oZXJpdCI7DQogICAgICAgICAgfQ0KICAgICAgICB9DQogICAgICAgIGlmICghZWxlbWVudERhdGEoZWwsICJpbml0aWFsaXplZCIpKSB7DQogICAgICAgICAgaW5pdFNpemluZyhlbCk7DQoNCiAgICAgICAgICBlbGVtZW50RGF0YShlbCwgImluaXRpYWxpemVkIiwgdHJ1ZSk7DQogICAgICAgICAgaWYgKGJpbmRpbmdEZWYuaW5pdGlhbGl6ZSkgew0KICAgICAgICAgICAgdmFyIHJlc3VsdCA9IGJpbmRpbmdEZWYuaW5pdGlhbGl6ZShlbCwgZWwub2Zmc2V0V2lkdGgsDQogICAgICAgICAgICAgIGVsLm9mZnNldEhlaWdodCk7DQogICAgICAgICAgICBlbGVtZW50RGF0YShlbCwgImluaXRfcmVzdWx0IiwgcmVzdWx0KTsNCiAgICAgICAgICB9DQogICAgICAgIH0NCiAgICAgICAgU2hpbnkucmVuZGVyRGVwZW5kZW5jaWVzKGRhdGEuZGVwcyk7DQogICAgICAgIGJpbmRpbmdEZWYucmVuZGVyVmFsdWUoZWwsIGRhdGEueCwgZWxlbWVudERhdGEoZWwsICJpbml0X3Jlc3VsdCIpKTsNCiAgICAgICAgZXZhbEFuZFJ1bihkYXRhLmpzSG9va3MucmVuZGVyLCBlbGVtZW50RGF0YShlbCwgImluaXRfcmVzdWx0IiksIFtlbCwgZGF0YS54XSk7DQogICAgICB9Ow0KDQogICAgICAvLyBPbmx5IG92ZXJyaWRlIHJlc2l6ZSBpZiBiaW5kaW5nRGVmIGltcGxlbWVudHMgaXQNCiAgICAgIGlmIChiaW5kaW5nRGVmLnJlc2l6ZSkgew0KICAgICAgICBzaGlueUJpbmRpbmcucmVzaXplID0gZnVuY3Rpb24oZWwsIHdpZHRoLCBoZWlnaHQpIHsNCiAgICAgICAgICAvLyBTaGlueSBjYW4gY2FsbCByZXNpemUgYmVmb3JlIGluaXRpYWxpemUvcmVuZGVyVmFsdWUgaGF2ZSBiZWVuDQogICAgICAgICAgLy8gY2FsbGVkLCB3aGljaCBkb2Vzbid0IG1ha2Ugc2Vuc2UgZm9yIHdpZGdldHMuDQogICAgICAgICAgaWYgKGVsZW1lbnREYXRhKGVsLCAiaW5pdGlhbGl6ZWQiKSkgew0KICAgICAgICAgICAgYmluZGluZ0RlZi5yZXNpemUoZWwsIHdpZHRoLCBoZWlnaHQsIGVsZW1lbnREYXRhKGVsLCAiaW5pdF9yZXN1bHQiKSk7DQogICAgICAgICAgfQ0KICAgICAgICB9Ow0KICAgICAgfQ0KDQogICAgICBTaGlueS5vdXRwdXRCaW5kaW5ncy5yZWdpc3RlcihzaGlueUJpbmRpbmcsIGJpbmRpbmdEZWYubmFtZSk7DQogICAgfQ0KICB9Ow0KDQogIHZhciBzY2hlZHVsZVN0YXRpY1JlbmRlclRpbWVySWQgPSBudWxsOw0KICBmdW5jdGlvbiBzY2hlZHVsZVN0YXRpY1JlbmRlcigpIHsNCiAgICBpZiAoIXNjaGVkdWxlU3RhdGljUmVuZGVyVGltZXJJZCkgew0KICAgICAgc2NoZWR1bGVTdGF0aWNSZW5kZXJUaW1lcklkID0gc2V0VGltZW91dChmdW5jdGlvbigpIHsNCiAgICAgICAgc2NoZWR1bGVTdGF0aWNSZW5kZXJUaW1lcklkID0gbnVsbDsNCiAgICAgICAgd2luZG93LkhUTUxXaWRnZXRzLnN0YXRpY1JlbmRlcigpOw0KICAgICAgfSwgMSk7DQogICAgfQ0KICB9DQoNCiAgLy8gUmVuZGVyIHN0YXRpYyB3aWRnZXRzIGFmdGVyIHRoZSBkb2N1bWVudCBmaW5pc2hlcyBsb2FkaW5nDQogIC8vIFN0YXRpY2FsbHkgcmVuZGVyIGFsbCBlbGVtZW50cyB0aGF0IGFyZSBvZiB0aGlzIHdpZGdldCdzIGNsYXNzDQogIHdpbmRvdy5IVE1MV2lkZ2V0cy5zdGF0aWNSZW5kZXIgPSBmdW5jdGlvbigpIHsNCiAgICB2YXIgYmluZGluZ3MgPSB3aW5kb3cuSFRNTFdpZGdldHMud2lkZ2V0cyB8fCBbXTsNCiAgICBmb3JFYWNoKGJpbmRpbmdzLCBmdW5jdGlvbihiaW5kaW5nKSB7DQogICAgICB2YXIgbWF0Y2hlcyA9IGJpbmRpbmcuZmluZChkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpOw0KICAgICAgZm9yRWFjaChtYXRjaGVzLCBmdW5jdGlvbihlbCkgew0KICAgICAgICB2YXIgc2l6ZU9iaiA9IGluaXRTaXppbmcoZWwsIGJpbmRpbmcpOw0KDQogICAgICAgIGlmIChoYXNDbGFzcyhlbCwgImh0bWwtd2lkZ2V0LXN0YXRpYy1ib3VuZCIpKQ0KICAgICAgICAgIHJldHVybjsNCiAgICAgICAgZWwuY2xhc3NOYW1lID0gZWwuY2xhc3NOYW1lICsgIiBodG1sLXdpZGdldC1zdGF0aWMtYm91bmQiOw0KDQogICAgICAgIHZhciBpbml0UmVzdWx0Ow0KICAgICAgICBpZiAoYmluZGluZy5pbml0aWFsaXplKSB7DQogICAgICAgICAgaW5pdFJlc3VsdCA9IGJpbmRpbmcuaW5pdGlhbGl6ZShlbCwNCiAgICAgICAgICAgIHNpemVPYmogPyBzaXplT2JqLmdldFdpZHRoKCkgOiBlbC5vZmZzZXRXaWR0aCwNCiAgICAgICAgICAgIHNpemVPYmogPyBzaXplT2JqLmdldEhlaWdodCgpIDogZWwub2Zmc2V0SGVpZ2h0DQogICAgICAgICAgKTsNCiAgICAgICAgICBlbGVtZW50RGF0YShlbCwgImluaXRfcmVzdWx0IiwgaW5pdFJlc3VsdCk7DQogICAgICAgIH0NCg0KICAgICAgICBpZiAoYmluZGluZy5yZXNpemUpIHsNCiAgICAgICAgICB2YXIgbGFzdFNpemUgPSB7fTsNCiAgICAgICAgICB2YXIgcmVzaXplSGFuZGxlciA9IGZ1bmN0aW9uKGUpIHsNCiAgICAgICAgICAgIHZhciBzaXplID0gew0KICAgICAgICAgICAgICB3OiBzaXplT2JqID8gc2l6ZU9iai5nZXRXaWR0aCgpIDogZWwub2Zmc2V0V2lkdGgsDQogICAgICAgICAgICAgIGg6IHNpemVPYmogPyBzaXplT2JqLmdldEhlaWdodCgpIDogZWwub2Zmc2V0SGVpZ2h0DQogICAgICAgICAgICB9Ow0KICAgICAgICAgICAgaWYgKHNpemUudyA9PT0gMCAmJiBzaXplLmggPT09IDApDQogICAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgICAgIGlmIChzaXplLncgPT09IGxhc3RTaXplLncgJiYgc2l6ZS5oID09PSBsYXN0U2l6ZS5oKQ0KICAgICAgICAgICAgICByZXR1cm47DQogICAgICAgICAgICBsYXN0U2l6ZSA9IHNpemU7DQogICAgICAgICAgICBiaW5kaW5nLnJlc2l6ZShlbCwgc2l6ZS53LCBzaXplLmgsIGluaXRSZXN1bHQpOw0KICAgICAgICAgIH07DQoNCiAgICAgICAgICBvbih3aW5kb3csICJyZXNpemUiLCByZXNpemVIYW5kbGVyKTsNCg0KICAgICAgICAgIC8vIFRoaXMgaXMgbmVlZGVkIGZvciBjYXNlcyB3aGVyZSB3ZSdyZSBydW5uaW5nIGluIGEgU2hpbnkNCiAgICAgICAgICAvLyBhcHAsIGJ1dCB0aGUgd2lkZ2V0IGl0c2VsZiBpcyBub3QgYSBTaGlueSBvdXRwdXQsIGJ1dA0KICAgICAgICAgIC8vIHJhdGhlciBhIHNpbXBsZSBzdGF0aWMgd2lkZ2V0LiBPbmUgZXhhbXBsZSBvZiB0aGlzIGlzDQogICAgICAgICAgLy8gYW4gcm1hcmtkb3duIGRvY3VtZW50IHRoYXQgaGFzIHJ1bnRpbWU6c2hpbnkgYW5kIHdpZGdldA0KICAgICAgICAgIC8vIHRoYXQgaXNuJ3QgaW4gYSByZW5kZXIgZnVuY3Rpb24uIFNoaW55IG9ubHkga25vd3MgdG8NCiAgICAgICAgICAvLyBjYWxsIHJlc2l6ZSBoYW5kbGVycyBmb3IgU2hpbnkgb3V0cHV0cywgbm90IGZvciBzdGF0aWMNCiAgICAgICAgICAvLyB3aWRnZXRzLCBzbyB3ZSBkbyBpdCBvdXJzZWx2ZXMuDQogICAgICAgICAgaWYgKHdpbmRvdy5qUXVlcnkpIHsNCiAgICAgICAgICAgIHdpbmRvdy5qUXVlcnkoZG9jdW1lbnQpLm9uKA0KICAgICAgICAgICAgICAic2hvd24uaHRtbHdpZGdldHMgc2hvd24uYnMudGFiLmh0bWx3aWRnZXRzIHNob3duLmJzLmNvbGxhcHNlLmh0bWx3aWRnZXRzIiwNCiAgICAgICAgICAgICAgcmVzaXplSGFuZGxlcg0KICAgICAgICAgICAgKTsNCiAgICAgICAgICAgIHdpbmRvdy5qUXVlcnkoZG9jdW1lbnQpLm9uKA0KICAgICAgICAgICAgICAiaGlkZGVuLmh0bWx3aWRnZXRzIGhpZGRlbi5icy50YWIuaHRtbHdpZGdldHMgaGlkZGVuLmJzLmNvbGxhcHNlLmh0bWx3aWRnZXRzIiwNCiAgICAgICAgICAgICAgcmVzaXplSGFuZGxlcg0KICAgICAgICAgICAgKTsNCiAgICAgICAgICB9DQoNCiAgICAgICAgICAvLyBUaGlzIGlzIG5lZWRlZCBmb3IgdGhlIHNwZWNpZmljIGNhc2Ugb2YgaW9zbGlkZXMsIHdoaWNoDQogICAgICAgICAgLy8gZmxpcHMgc2xpZGVzIGJldHdlZW4gZGlzcGxheTpub25lIGFuZCBkaXNwbGF5OmJsb2NrLg0KICAgICAgICAgIC8vIElkZWFsbHkgd2Ugd291bGQgbm90IGhhdmUgdG8gaGF2ZSBpb3NsaWRlLXNwZWNpZmljIGNvZGUNCiAgICAgICAgICAvLyBoZXJlLCBidXQgcmF0aGVyIGhhdmUgaW9zbGlkZXMgcmFpc2UgYSBnZW5lcmljIGV2ZW50LA0KICAgICAgICAgIC8vIGJ1dCB0aGUgcm1hcmtkb3duIHBhY2thZ2UganVzdCB3ZW50IHRvIENSQU4gc28gdGhlDQogICAgICAgICAgLy8gd2luZG93IHRvIGdldHRpbmcgdGhhdCBmaXhlZCBtYXkgYmUgbG9uZy4NCiAgICAgICAgICBpZiAod2luZG93LmFkZEV2ZW50TGlzdGVuZXIpIHsNCiAgICAgICAgICAgIC8vIEl0J3MgT0sgdG8gbGltaXQgdGhpcyB0byB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcg0KICAgICAgICAgICAgLy8gYnJvd3NlcnMgYmVjYXVzZSBpb3NsaWRlcyBpdHNlbGYgb25seSBzdXBwb3J0cw0KICAgICAgICAgICAgLy8gc3VjaCBicm93c2Vycy4NCiAgICAgICAgICAgIG9uKGRvY3VtZW50LCAic2xpZGVlbnRlciIsIHJlc2l6ZUhhbmRsZXIpOw0KICAgICAgICAgICAgb24oZG9jdW1lbnQsICJzbGlkZWxlYXZlIiwgcmVzaXplSGFuZGxlcik7DQogICAgICAgICAgfQ0KICAgICAgICB9DQoNCiAgICAgICAgdmFyIHNjcmlwdERhdGEgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCJzY3JpcHRbZGF0YS1mb3I9JyIgKyBlbC5pZCArICInXVt0eXBlPSdhcHBsaWNhdGlvbi9qc29uJ10iKTsNCiAgICAgICAgaWYgKHNjcmlwdERhdGEpIHsNCiAgICAgICAgICB2YXIgZGF0YSA9IEpTT04ucGFyc2Uoc2NyaXB0RGF0YS50ZXh0Q29udGVudCB8fCBzY3JpcHREYXRhLnRleHQpOw0KICAgICAgICAgIC8vIFJlc29sdmUgc3RyaW5ncyBtYXJrZWQgYXMgamF2YXNjcmlwdCBsaXRlcmFscyB0byBvYmplY3RzDQogICAgICAgICAgaWYgKCEoZGF0YS5ldmFscyBpbnN0YW5jZW9mIEFycmF5KSkgZGF0YS5ldmFscyA9IFtkYXRhLmV2YWxzXTsNCiAgICAgICAgICBmb3IgKHZhciBrID0gMDsgZGF0YS5ldmFscyAmJiBrIDwgZGF0YS5ldmFscy5sZW5ndGg7IGsrKykgew0KICAgICAgICAgICAgd2luZG93LkhUTUxXaWRnZXRzLmV2YWx1YXRlU3RyaW5nTWVtYmVyKGRhdGEueCwgZGF0YS5ldmFsc1trXSk7DQogICAgICAgICAgfQ0KICAgICAgICAgIGJpbmRpbmcucmVuZGVyVmFsdWUoZWwsIGRhdGEueCwgaW5pdFJlc3VsdCk7DQogICAgICAgICAgZXZhbEFuZFJ1bihkYXRhLmpzSG9va3MucmVuZGVyLCBpbml0UmVzdWx0LCBbZWwsIGRhdGEueF0pOw0KICAgICAgICB9DQogICAgICB9KTsNCiAgICB9KTsNCg0KICAgIGludm9rZVBvc3RSZW5kZXJIYW5kbGVycygpOw0KICB9DQoNCiAgLy8gV2FpdCB1bnRpbCBhZnRlciB0aGUgZG9jdW1lbnQgaGFzIGxvYWRlZCB0byByZW5kZXIgdGhlIHdpZGdldHMuDQogIGlmIChkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKSB7DQogICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsIGZ1bmN0aW9uKCkgew0KICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsIGFyZ3VtZW50cy5jYWxsZWUsIGZhbHNlKTsNCiAgICAgIHdpbmRvdy5IVE1MV2lkZ2V0cy5zdGF0aWNSZW5kZXIoKTsNCiAgICB9LCBmYWxzZSk7DQogIH0gZWxzZSBpZiAoZG9jdW1lbnQuYXR0YWNoRXZlbnQpIHsNCiAgICBkb2N1bWVudC5hdHRhY2hFdmVudCgib25yZWFkeXN0YXRlY2hhbmdlIiwgZnVuY3Rpb24oKSB7DQogICAgICBpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gImNvbXBsZXRlIikgew0KICAgICAgICBkb2N1bWVudC5kZXRhY2hFdmVudCgib25yZWFkeXN0YXRlY2hhbmdlIiwgYXJndW1lbnRzLmNhbGxlZSk7DQogICAgICAgIHdpbmRvdy5IVE1MV2lkZ2V0cy5zdGF0aWNSZW5kZXIoKTsNCiAgICAgIH0NCiAgICB9KTsNCiAgfQ0KDQoNCiAgd2luZG93LkhUTUxXaWRnZXRzLmdldEF0dGFjaG1lbnRVcmwgPSBmdW5jdGlvbihkZXBuYW1lLCBrZXkpIHsNCiAgICAvLyBJZiBubyBrZXksIGRlZmF1bHQgdG8gdGhlIGZpcnN0IGl0ZW0NCiAgICBpZiAodHlwZW9mKGtleSkgPT09ICJ1bmRlZmluZWQiKQ0KICAgICAga2V5ID0gMTsNCg0KICAgIHZhciBsaW5rID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoZGVwbmFtZSArICItIiArIGtleSArICItYXR0YWNobWVudCIpOw0KICAgIGlmICghbGluaykgew0KICAgICAgdGhyb3cgbmV3IEVycm9yKCJBdHRhY2htZW50ICIgKyBkZXBuYW1lICsgIi8iICsga2V5ICsgIiBub3QgZm91bmQgaW4gZG9jdW1lbnQiKTsNCiAgICB9DQogICAgcmV0dXJuIGxpbmsuZ2V0QXR0cmlidXRlKCJocmVmIik7DQogIH07DQoNCiAgd2luZG93LkhUTUxXaWRnZXRzLmRhdGFmcmFtZVRvRDMgPSBmdW5jdGlvbihkZikgew0KICAgIHZhciBuYW1lcyA9IFtdOw0KICAgIHZhciBsZW5ndGg7DQogICAgZm9yICh2YXIgbmFtZSBpbiBkZikgew0KICAgICAgICBpZiAoZGYuaGFzT3duUHJvcGVydHkobmFtZSkpDQogICAgICAgICAgICBuYW1lcy5wdXNoKG5hbWUpOw0KICAgICAgICBpZiAodHlwZW9mKGRmW25hbWVdKSAhPT0gIm9iamVjdCIgfHwgdHlwZW9mKGRmW25hbWVdLmxlbmd0aCkgPT09ICJ1bmRlZmluZWQiKSB7DQogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkFsbCBmaWVsZHMgbXVzdCBiZSBhcnJheXMiKTsNCiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YobGVuZ3RoKSAhPT0gInVuZGVmaW5lZCIgJiYgbGVuZ3RoICE9PSBkZltuYW1lXS5sZW5ndGgpIHsNCiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiQWxsIGZpZWxkcyBtdXN0IGJlIGFycmF5cyBvZiB0aGUgc2FtZSBsZW5ndGgiKTsNCiAgICAgICAgfQ0KICAgICAgICBsZW5ndGggPSBkZltuYW1lXS5sZW5ndGg7DQogICAgfQ0KICAgIHZhciByZXN1bHRzID0gW107DQogICAgdmFyIGl0ZW07DQogICAgZm9yICh2YXIgcm93ID0gMDsgcm93IDwgbGVuZ3RoOyByb3crKykgew0KICAgICAgICBpdGVtID0ge307DQogICAgICAgIGZvciAodmFyIGNvbCA9IDA7IGNvbCA8IG5hbWVzLmxlbmd0aDsgY29sKyspIHsNCiAgICAgICAgICAgIGl0ZW1bbmFtZXNbY29sXV0gPSBkZltuYW1lc1tjb2xdXVtyb3ddOw0KICAgICAgICB9DQogICAgICAgIHJlc3VsdHMucHVzaChpdGVtKTsNCiAgICB9DQogICAgcmV0dXJuIHJlc3VsdHM7DQogIH07DQoNCiAgd2luZG93LkhUTUxXaWRnZXRzLnRyYW5zcG9zZUFycmF5MkQgPSBmdW5jdGlvbihhcnJheSkgew0KICAgICAgaWYgKGFycmF5Lmxlbmd0aCA9PT0gMCkgcmV0dXJuIGFycmF5Ow0KICAgICAgdmFyIG5ld0FycmF5ID0gYXJyYXlbMF0ubWFwKGZ1bmN0aW9uKGNvbCwgaSkgew0KICAgICAgICAgIHJldHVybiBhcnJheS5tYXAoZnVuY3Rpb24ocm93KSB7DQogICAgICAgICAgICAgIHJldHVybiByb3dbaV0NCiAgICAgICAgICB9KQ0KICAgICAgfSk7DQogICAgICByZXR1cm4gbmV3QXJyYXk7DQogIH07DQogIC8vIFNwbGl0IHZhbHVlIGF0IHNwbGl0Q2hhciwgYnV0IGFsbG93IHNwbGl0Q2hhciB0byBiZSBlc2NhcGVkDQogIC8vIHVzaW5nIGVzY2FwZUNoYXIuIEFueSBvdGhlciBjaGFyYWN0ZXJzIGVzY2FwZWQgYnkgZXNjYXBlQ2hhcg0KICAvLyB3aWxsIGJlIGluY2x1ZGVkIGFzIHVzdWFsIChpbmNsdWRpbmcgZXNjYXBlQ2hhciBpdHNlbGYpLg0KICBmdW5jdGlvbiBzcGxpdFdpdGhFc2NhcGUodmFsdWUsIHNwbGl0Q2hhciwgZXNjYXBlQ2hhcikgew0KICAgIHZhciByZXN1bHRzID0gW107DQogICAgdmFyIGVzY2FwZU1vZGUgPSBmYWxzZTsNCiAgICB2YXIgY3VycmVudFJlc3VsdCA9ICIiOw0KICAgIGZvciAodmFyIHBvcyA9IDA7IHBvcyA8IHZhbHVlLmxlbmd0aDsgcG9zKyspIHsNCiAgICAgIGlmICghZXNjYXBlTW9kZSkgew0KICAgICAgICBpZiAodmFsdWVbcG9zXSA9PT0gc3BsaXRDaGFyKSB7DQogICAgICAgICAgcmVzdWx0cy5wdXNoKGN1cnJlbnRSZXN1bHQpOw0KICAgICAgICAgIGN1cnJlbnRSZXN1bHQgPSAiIjsNCiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVtwb3NdID09PSBlc2NhcGVDaGFyKSB7DQogICAgICAgICAgZXNjYXBlTW9kZSA9IHRydWU7DQogICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgY3VycmVudFJlc3VsdCArPSB2YWx1ZVtwb3NdOw0KICAgICAgICB9DQogICAgICB9IGVsc2Ugew0KICAgICAgICBjdXJyZW50UmVzdWx0ICs9IHZhbHVlW3Bvc107DQogICAgICAgIGVzY2FwZU1vZGUgPSBmYWxzZTsNCiAgICAgIH0NCiAgICB9DQogICAgaWYgKGN1cnJlbnRSZXN1bHQgIT09ICIiKSB7DQogICAgICByZXN1bHRzLnB1c2goY3VycmVudFJlc3VsdCk7DQogICAgfQ0KICAgIHJldHVybiByZXN1bHRzOw0KICB9DQogIC8vIEZ1bmN0aW9uIGF1dGhvcmVkIGJ5IFlpaHVpL0pKIEFsbGFpcmUNCiAgd2luZG93LkhUTUxXaWRnZXRzLmV2YWx1YXRlU3RyaW5nTWVtYmVyID0gZnVuY3Rpb24obywgbWVtYmVyKSB7DQogICAgdmFyIHBhcnRzID0gc3BsaXRXaXRoRXNjYXBlKG1lbWJlciwgJy4nLCAnXFwnKTsNCiAgICBmb3IgKHZhciBpID0gMCwgbCA9IHBhcnRzLmxlbmd0aDsgaSA8IGw7IGkrKykgew0KICAgICAgdmFyIHBhcnQgPSBwYXJ0c1tpXTsNCiAgICAgIC8vIHBhcnQgbWF5IGJlIGEgY2hhcmFjdGVyIG9yICdudW1lcmljJyBtZW1iZXIgbmFtZQ0KICAgICAgaWYgKG8gIT09IG51bGwgJiYgdHlwZW9mIG8gPT09ICJvYmplY3QiICYmIHBhcnQgaW4gbykgew0KICAgICAgICBpZiAoaSA9PSAobCAtIDEpKSB7IC8vIGlmIHdlIGFyZSBhdCB0aGUgZW5kIG9mIHRoZSBsaW5lIHRoZW4gZXZhbHVsYXRlDQogICAgICAgICAgaWYgKHR5cGVvZiBvW3BhcnRdID09PSAic3RyaW5nIikNCiAgICAgICAgICAgIG9bcGFydF0gPSBldmFsKCIoIiArIG9bcGFydF0gKyAiKSIpOw0KICAgICAgICB9IGVsc2UgeyAvLyBvdGhlcndpc2UgY29udGludWUgdG8gbmV4dCBlbWJlZGRlZCBvYmplY3QNCiAgICAgICAgICBvID0gb1twYXJ0XTsNCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIH0NCiAgfTsNCg0KICAvLyBSZXRyaWV2ZSB0aGUgSFRNTFdpZGdldCBpbnN0YW5jZSAoaS5lLiB0aGUgcmV0dXJuIHZhbHVlIG9mIGFuDQogIC8vIEhUTUxXaWRnZXQgYmluZGluZydzIGluaXRpYWxpemUoKSBvciBmYWN0b3J5KCkgZnVuY3Rpb24pDQogIC8vIGFzc29jaWF0ZWQgd2l0aCBhbiBlbGVtZW50LCBvciBudWxsIGlmIG5vbmUuDQogIHdpbmRvdy5IVE1MV2lkZ2V0cy5nZXRJbnN0YW5jZSA9IGZ1bmN0aW9uKGVsKSB7DQogICAgcmV0dXJuIGVsZW1lbnREYXRhKGVsLCAiaW5pdF9yZXN1bHQiKTsNCiAgfTsNCg0KICAvLyBGaW5kcyB0aGUgZmlyc3QgZWxlbWVudCBpbiB0aGUgc2NvcGUgdGhhdCBtYXRjaGVzIHRoZSBzZWxlY3RvciwNCiAgLy8gYW5kIHJldHVybnMgdGhlIEhUTUxXaWRnZXQgaW5zdGFuY2UgKGkuZS4gdGhlIHJldHVybiB2YWx1ZSBvZg0KICAvLyBhbiBIVE1MV2lkZ2V0IGJpbmRpbmcncyBpbml0aWFsaXplKCkgb3IgZmFjdG9yeSgpIGZ1bmN0aW9uKQ0KICAvLyBhc3NvY2lhdGVkIHdpdGggdGhhdCBlbGVtZW50LCBpZiBhbnkuIElmIG5vIGVsZW1lbnQgbWF0Y2hlcyB0aGUNCiAgLy8gc2VsZWN0b3IsIG9yIHRoZSBmaXJzdCBtYXRjaGluZyBlbGVtZW50IGhhcyBubyBIVE1MV2lkZ2V0DQogIC8vIGluc3RhbmNlIGFzc29jaWF0ZWQgd2l0aCBpdCwgdGhlbiBudWxsIGlzIHJldHVybmVkLg0KICAvLw0KICAvLyBUaGUgc2NvcGUgYXJndW1lbnQgaXMgb3B0aW9uYWwsIGFuZCBkZWZhdWx0cyB0byB3aW5kb3cuZG9jdW1lbnQuDQogIHdpbmRvdy5IVE1MV2lkZ2V0cy5maW5kID0gZnVuY3Rpb24oc2NvcGUsIHNlbGVjdG9yKSB7DQogICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT0gMSkgew0KICAgICAgc2VsZWN0b3IgPSBzY29wZTsNCiAgICAgIHNjb3BlID0gZG9jdW1lbnQ7DQogICAgfQ0KDQogICAgdmFyIGVsID0gc2NvcGUucXVlcnlTZWxlY3RvcihzZWxlY3Rvcik7DQogICAgaWYgKGVsID09PSBudWxsKSB7DQogICAgICByZXR1cm4gbnVsbDsNCiAgICB9IGVsc2Ugew0KICAgICAgcmV0dXJuIHdpbmRvdy5IVE1MV2lkZ2V0cy5nZXRJbnN0YW5jZShlbCk7DQogICAgfQ0KICB9Ow0KDQogIC8vIEZpbmRzIGFsbCBlbGVtZW50cyBpbiB0aGUgc2NvcGUgdGhhdCBtYXRjaCB0aGUgc2VsZWN0b3IsIGFuZA0KICAvLyByZXR1cm5zIHRoZSBIVE1MV2lkZ2V0IGluc3RhbmNlcyAoaS5lLiB0aGUgcmV0dXJuIHZhbHVlcyBvZg0KICAvLyBhbiBIVE1MV2lkZ2V0IGJpbmRpbmcncyBpbml0aWFsaXplKCkgb3IgZmFjdG9yeSgpIGZ1bmN0aW9uKQ0KICAvLyBhc3NvY2lhdGVkIHdpdGggdGhlIGVsZW1lbnRzLCBpbiBhbiBhcnJheS4gSWYgZWxlbWVudHMgdGhhdA0KICAvLyBtYXRjaCB0aGUgc2VsZWN0b3IgZG9uJ3QgaGF2ZSBhbiBhc3NvY2lhdGVkIEhUTUxXaWRnZXQNCiAgLy8gaW5zdGFuY2UsIHRoZSByZXR1cm5lZCBhcnJheSB3aWxsIGNvbnRhaW4gbnVsbHMuDQogIC8vDQogIC8vIFRoZSBzY29wZSBhcmd1bWVudCBpcyBvcHRpb25hbCwgYW5kIGRlZmF1bHRzIHRvIHdpbmRvdy5kb2N1bWVudC4NCiAgd2luZG93LkhUTUxXaWRnZXRzLmZpbmRBbGwgPSBmdW5jdGlvbihzY29wZSwgc2VsZWN0b3IpIHsNCiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PSAxKSB7DQogICAgICBzZWxlY3RvciA9IHNjb3BlOw0KICAgICAgc2NvcGUgPSBkb2N1bWVudDsNCiAgICB9DQoNCiAgICB2YXIgbm9kZXMgPSBzY29wZS5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yKTsNCiAgICB2YXIgcmVzdWx0cyA9IFtdOw0KICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHsNCiAgICAgIHJlc3VsdHMucHVzaCh3aW5kb3cuSFRNTFdpZGdldHMuZ2V0SW5zdGFuY2Uobm9kZXNbaV0pKTsNCiAgICB9DQogICAgcmV0dXJuIHJlc3VsdHM7DQogIH07DQoNCiAgdmFyIHBvc3RSZW5kZXJIYW5kbGVycyA9IFtdOw0KICBmdW5jdGlvbiBpbnZva2VQb3N0UmVuZGVySGFuZGxlcnMoKSB7DQogICAgd2hpbGUgKHBvc3RSZW5kZXJIYW5kbGVycy5sZW5ndGgpIHsNCiAgICAgIHZhciBoYW5kbGVyID0gcG9zdFJlbmRlckhhbmRsZXJzLnNoaWZ0KCk7DQogICAgICBpZiAoaGFuZGxlcikgew0KICAgICAgICBoYW5kbGVyKCk7DQogICAgICB9DQogICAgfQ0KICB9DQoNCiAgLy8gUmVnaXN0ZXIgdGhlIGdpdmVuIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYWZ0ZXIgdGhlDQogIC8vIG5leHQgdGltZSBzdGF0aWMgd2lkZ2V0cyBhcmUgcmVuZGVyZWQuDQogIHdpbmRvdy5IVE1MV2lkZ2V0cy5hZGRQb3N0UmVuZGVySGFuZGxlciA9IGZ1bmN0aW9uKGNhbGxiYWNrKSB7DQogICAgcG9zdFJlbmRlckhhbmRsZXJzLnB1c2goY2FsbGJhY2spOw0KICB9Ow0KDQogIC8vIFRha2VzIGEgbmV3LXN0eWxlIGluc3RhbmNlLWJvdW5kIGRlZmluaXRpb24sIGFuZCByZXR1cm5zIGFuDQogIC8vIG9sZC1zdHlsZSBjbGFzcy1ib3VuZCBkZWZpbml0aW9uLiBUaGlzIHNhdmVzIHVzIGZyb20gaGF2aW5nDQogIC8vIHRvIHJld3JpdGUgYWxsIHRoZSBsb2dpYyBpbiB0aGlzIGZpbGUgdG8gYWNjb21vZGF0ZSBib3RoDQogIC8vIHR5cGVzIG9mIGRlZmluaXRpb25zLg0KICBmdW5jdGlvbiBjcmVhdGVMZWdhY3lEZWZpbml0aW9uQWRhcHRlcihkZWZuKSB7DQogICAgdmFyIHJlc3VsdCA9IHsNCiAgICAgIG5hbWU6IGRlZm4ubmFtZSwNCiAgICAgIHR5cGU6IGRlZm4udHlwZSwNCiAgICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uKGVsLCB3aWR0aCwgaGVpZ2h0KSB7DQogICAgICAgIHJldHVybiBkZWZuLmZhY3RvcnkoZWwsIHdpZHRoLCBoZWlnaHQpOw0KICAgICAgfSwNCiAgICAgIHJlbmRlclZhbHVlOiBmdW5jdGlvbihlbCwgeCwgaW5zdGFuY2UpIHsNCiAgICAgICAgcmV0dXJuIGluc3RhbmNlLnJlbmRlclZhbHVlKHgpOw0KICAgICAgfSwNCiAgICAgIHJlc2l6ZTogZnVuY3Rpb24oZWwsIHdpZHRoLCBoZWlnaHQsIGluc3RhbmNlKSB7DQogICAgICAgIHJldHVybiBpbnN0YW5jZS5yZXNpemUod2lkdGgsIGhlaWdodCk7DQogICAgICB9DQogICAgfTsNCg0KICAgIGlmIChkZWZuLmZpbmQpDQogICAgICByZXN1bHQuZmluZCA9IGRlZm4uZmluZDsNCiAgICBpZiAoZGVmbi5yZW5kZXJFcnJvcikNCiAgICAgIHJlc3VsdC5yZW5kZXJFcnJvciA9IGRlZm4ucmVuZGVyRXJyb3I7DQogICAgaWYgKGRlZm4uY2xlYXJFcnJvcikNCiAgICAgIHJlc3VsdC5jbGVhckVycm9yID0gZGVmbi5jbGVhckVycm9yOw0KDQogICAgcmV0dXJuIHJlc3VsdDsNCiAgfQ0KfSkoKTsNCg0K"></script>
<link href="data:text/css;charset=utf-8,%0Aslide%3Anot%28%2Ecurrent%29%20%2Eplotly%2Ehtml%2Dwidget%7B%0Adisplay%3A%20none%3B%0A%7D%0A" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment