Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save firmai/77443ed65c89015a97f995a2bf1ae522 to your computer and use it in GitHub Desktop.
Save firmai/77443ed65c89015a97f995a2bf1ae522 to your computer and use it in GitHub Desktop.
Replicate Paper by Rapach, Strauss, Tu, Zhou.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Replicate Paper by Rapach, Strauss, Tu, Zhou.ipynb",
"provenance": [],
"collapsed_sections": [
"rF7Dy6I8fkZt",
"DgB_mQX4fkaq",
"GKFBQzIHfkbr"
],
"include_colab_link": true
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.6"
},
"kernelspec": {
"display_name": "tensorflow3",
"language": "python",
"name": "tensorflow3"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/firmai/77443ed65c89015a97f995a2bf1ae522/replicate-paper-by-rapach-strauss-tu-zhou.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "aIP2O7ORjARs"
},
"source": [
"## Industury Factors"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fQKJm2jGEfZF"
},
"source": [
"\n",
"This notebook is wholly inspired by Druce Vertes from Streeteye.com, do pay him some support."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3lRSi-4zfkXp"
},
"source": [
"Replicate [Dynamic Return Dependencies Across Industries: A Machine Learning Approach](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3120110&download=yes) by David Rapach, Jack Strauss, Jun Tu and Guofu Zhou.\n",
"\n",
"1) Use industry returns from [Ken French](http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html)\n",
"\n",
"2) Forecast (for example) this month's Chemical industry return using last month's returns from all 30 industries \n",
"\n",
"3) Use LASSO for predictor subset selection over the entire 1960-2016 period to determine that e.g. Beer is predicted by Food, Clothing, Coal\n",
"\n",
"4) Use LASSO-selected predictors and simple linear regression to predict returns\n",
"\n",
"5) Generate portfolios and run backtests.\n",
"\n",
"- Predictor selection - finds same predictors except 2 industries. Possibly use of AICc instead of AIC (don't see an sklearn implementation that uses AICc)\n",
"\n",
"- Prediction by industry - R-squareds line up pretty closely\n",
"\n",
"- Portfolio performance, similar ballpark results. Maybe AICc/AIC; Also paper standardizes predictors, which is pretty standard. Finally, for some reason their mean returns don't line up to geometric mean annualized, they seem to be calculating something different.\n",
"\n",
"- Replicating exactly is hard but it does replicate closely and perform well\n",
"\n",
"6) Run various sklearn regressors to see which performs best, understand metrics that predict performance. MSE does not predict Sharpe. Kendall's tau, i.e. correlation of predicted vs. actual rankings, performs better.\n",
"\n",
"7) Tune ElasticNet to get slightly better performance than Lasso/OLS\n",
"\n",
"8) Run Keras NNs. They don't improve on Lasso/OLS or ElasticNet.\n",
"\n",
"\n",
" "
]
},
{
"cell_type": "code",
"metadata": {
"id": "8NNyTvkGkA5U"
},
"source": [
"#!pip install beakerx"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "7V4P7roTkUTP"
},
"source": [
"#!pip install tornado==5.1.1"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "-xj-ey0VfkXq",
"outputId": "16ae6b64-a3c3-4c6c-ca1b-93df276846f3",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
}
},
"source": [
"import os\n",
"import sys\n",
"import warnings\n",
"import numpy as np\n",
"import pandas as pd\n",
"import time \n",
"import copy\n",
"import random\n",
"from itertools import product\n",
"\n",
"os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' #Hide messy TensorFlow warnings\n",
"warnings.filterwarnings(\"ignore\") #Hide messy numpy warnings\n",
"\n",
"import sklearn\n",
"from sklearn.model_selection import train_test_split, KFold\n",
"from sklearn.metrics import confusion_matrix, mean_squared_error, explained_variance_score, r2_score, accuracy_score\n",
"from sklearn.linear_model import LinearRegression, Lasso, lasso_path, lars_path, LassoLarsIC\n",
"from sklearn.ensemble.forest import RandomForestRegressor\n",
"from sklearn.neural_network import MLPRegressor\n",
"from sklearn.preprocessing import MinMaxScaler, StandardScaler\n",
"from sklearn.utils.testing import all_estimators\n",
"import xgboost\n",
"\n",
"from scipy.stats import chisquare, kendalltau\n",
"\n",
"import tensorflow as tf\n",
"tf.set_random_seed(1764)\n",
"print(tf.__version__)\n",
"# confirm GPU is in use\n",
"with tf.device('/gpu:0'):\n",
" a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')\n",
" b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')\n",
" c = tf.matmul(a, b)\n",
"\n",
"with tf.Session() as sess:\n",
" print (sess.run(c))\n",
"\n",
"import keras\n",
"from keras.layers.core import Dense, Activation\n",
"from keras.layers import Input\n",
"from keras.models import Model\n",
"\n",
"from keras.layers.recurrent import LSTM, GRU\n",
"from keras.regularizers import l1\n",
"from keras.models import Sequential\n",
"from keras.models import load_model\n",
" \n",
"#import ffn\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"import seaborn as sns\n",
"\n",
"# this will make dataframe display as sortable widget\n",
"# commented out because sortable tables not viewable using nbviewer\n",
"#from beakerx import *\n",
"\n",
"import plotly\n",
"# print (plotly.__version__) # requires version >= 1.9.0\n",
"from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\n",
"from plotly.graph_objs import *\n",
"import plotly.figure_factory as ff\n",
"\n",
"init_notebook_mode(connected=True)\n",
"\n",
"random.seed(1764)\n",
"np.random.seed(1764)\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"1.14.0-rc1\n",
"[[22. 28.]\n",
" [49. 64.]]\n"
],
"name": "stdout"
},
{
"output_type": "stream",
"text": [
"Using TensorFlow backend.\n"
],
"name": "stderr"
},
{
"output_type": "display_data",
"data": {
"text/html": [
"<script>requirejs.config({paths: { 'plotly': ['https://cdn.plot.ly/plotly-latest.min']},});if(!window.Plotly) {{require(['plotly'],function(plotly) {window.Plotly=plotly;});}}</script>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "M7dE96IAfkXy"
},
"source": [
"### 1. Replicate paper"
]
},
{
"cell_type": "code",
"metadata": {
"id": "f3DSQj07mM8d",
"outputId": "6c2cc13e-c215-40a4-fc46-8b420768ccce",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
}
},
"source": [
"## Save future files to your drive\n",
"import numpy as np\n",
"from google.colab import drive\n",
"drive.mount('/content/drive',force_remount=True)\n",
"%cd \"/content/drive/My Drive/FirmAI/FinML/Data/Industry Factors\"\n",
"\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Mounted at /content/drive\n",
"/content/drive/My Drive/FirmAI/FinML/Data/Industry Factors\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "dyjHTej4fkXz",
"outputId": "a63af907-385c-4be2-b646-5ddce57d9120",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"print(\"Loading data...\")\n",
"data = pd.read_csv(\"input/30_Industry_Portfolios.csv\")\n",
"data = data.set_index('yyyymm')\n",
"industries = list(data.columns)\n",
"# map industry names to col nums\n",
"ind_reverse_dict = dict([(industries[i], i) for i in range(len(industries))])\n",
"\n",
"rfdata = pd.read_csv(\"input/F-F_Research_Data_Factors.csv\")\n",
"rfdata = rfdata.set_index('yyyymm')\n",
"data['rf'] = rfdata['RF']\n",
"\n",
"# subtract risk-free rate\n",
"# create a response variable led by 1 period to predict\n",
"for ind in industries:\n",
" data[ind] = data[ind] - data['rf']\n",
"\n",
"#for ind in industries:\n",
"# data[ind+\".3m\"] = pd.rolling_mean(data[ind],3)\n",
" \n",
"#for ind in industries:\n",
"# data[ind+\".6m\"] = pd.rolling_mean(data[ind],6)\n",
"\n",
"#for ind in industries:\n",
"# data[ind+\".12m\"] = pd.rolling_mean(data[ind],12)\n",
"\n",
"# Create lead columns\n",
"for ind in industries:\n",
" data[ind+\".lead\"] = data[ind].shift(-1)\n",
"\n",
"data = data.loc[data.index[data.index > 195911]]\n",
"data = data.drop(columns=['rf']) \n",
"data = data.dropna(axis=0, how='any')\n",
"\n",
"nresponses = len(industries)\n",
"npredictors = data.shape[1]-nresponses\n",
"\n",
"predictors = list(data.columns[:npredictors])\n",
"predictor_reverse_dict = dict([(predictors[i], i) for i in range(len(predictors))])\n",
"\n",
"responses = list(data.columns[-nresponses:])\n",
"response_reverse_dict = dict([(responses[i], i) for i in range(len(responses))])\n",
"\n",
"print(data.shape)\n",
"\n",
"data[['Food', 'Food.lead']]\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Loading data...\n",
"(697, 60)\n"
],
"name": "stdout"
},
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Food</th>\n",
" <th>Food.lead</th>\n",
" </tr>\n",
" <tr>\n",
" <th>yyyymm</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>195912</th>\n",
" <td>2.01</td>\n",
" <td>-4.49</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196001</th>\n",
" <td>-4.49</td>\n",
" <td>3.35</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196002</th>\n",
" <td>3.35</td>\n",
" <td>-1.67</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196003</th>\n",
" <td>-1.67</td>\n",
" <td>1.17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196004</th>\n",
" <td>1.17</td>\n",
" <td>8.20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196005</th>\n",
" <td>8.20</td>\n",
" <td>5.39</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196006</th>\n",
" <td>5.39</td>\n",
" <td>-2.11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196007</th>\n",
" <td>-2.11</td>\n",
" <td>4.57</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196008</th>\n",
" <td>4.57</td>\n",
" <td>-3.88</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196009</th>\n",
" <td>-3.88</td>\n",
" <td>1.02</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196010</th>\n",
" <td>1.02</td>\n",
" <td>9.46</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196011</th>\n",
" <td>9.46</td>\n",
" <td>4.51</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196012</th>\n",
" <td>4.51</td>\n",
" <td>4.70</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196101</th>\n",
" <td>4.70</td>\n",
" <td>4.21</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196102</th>\n",
" <td>4.21</td>\n",
" <td>4.64</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196103</th>\n",
" <td>4.64</td>\n",
" <td>-1.39</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196104</th>\n",
" <td>-1.39</td>\n",
" <td>4.20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196105</th>\n",
" <td>4.20</td>\n",
" <td>-2.17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196106</th>\n",
" <td>-2.17</td>\n",
" <td>2.72</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196107</th>\n",
" <td>2.72</td>\n",
" <td>4.92</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196108</th>\n",
" <td>4.92</td>\n",
" <td>-0.62</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196109</th>\n",
" <td>-0.62</td>\n",
" <td>3.73</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196110</th>\n",
" <td>3.73</td>\n",
" <td>5.28</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196111</th>\n",
" <td>5.28</td>\n",
" <td>-3.69</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196112</th>\n",
" <td>-3.69</td>\n",
" <td>-6.67</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196201</th>\n",
" <td>-6.67</td>\n",
" <td>-0.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196202</th>\n",
" <td>-0.25</td>\n",
" <td>0.98</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196203</th>\n",
" <td>0.98</td>\n",
" <td>-4.59</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196204</th>\n",
" <td>-4.59</td>\n",
" <td>-11.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196205</th>\n",
" <td>-11.25</td>\n",
" <td>-8.75</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201507</th>\n",
" <td>4.03</td>\n",
" <td>-4.37</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201508</th>\n",
" <td>-4.37</td>\n",
" <td>-1.19</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201509</th>\n",
" <td>-1.19</td>\n",
" <td>5.81</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201510</th>\n",
" <td>5.81</td>\n",
" <td>0.11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201511</th>\n",
" <td>0.11</td>\n",
" <td>1.96</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201512</th>\n",
" <td>1.96</td>\n",
" <td>-1.67</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201601</th>\n",
" <td>-1.67</td>\n",
" <td>0.95</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201602</th>\n",
" <td>0.95</td>\n",
" <td>4.69</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201603</th>\n",
" <td>4.69</td>\n",
" <td>0.63</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201604</th>\n",
" <td>0.63</td>\n",
" <td>2.06</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201605</th>\n",
" <td>2.06</td>\n",
" <td>4.75</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201606</th>\n",
" <td>4.75</td>\n",
" <td>-0.51</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201607</th>\n",
" <td>-0.51</td>\n",
" <td>-0.52</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201608</th>\n",
" <td>-0.52</td>\n",
" <td>-2.92</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201609</th>\n",
" <td>-2.92</td>\n",
" <td>-0.33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201610</th>\n",
" <td>-0.33</td>\n",
" <td>-4.41</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201611</th>\n",
" <td>-4.41</td>\n",
" <td>4.43</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201612</th>\n",
" <td>4.43</td>\n",
" <td>0.95</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201701</th>\n",
" <td>0.95</td>\n",
" <td>1.71</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201702</th>\n",
" <td>1.71</td>\n",
" <td>0.52</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201703</th>\n",
" <td>0.52</td>\n",
" <td>0.76</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201704</th>\n",
" <td>0.76</td>\n",
" <td>1.63</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201705</th>\n",
" <td>1.63</td>\n",
" <td>-2.65</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201706</th>\n",
" <td>-2.65</td>\n",
" <td>1.52</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201707</th>\n",
" <td>1.52</td>\n",
" <td>-2.77</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201708</th>\n",
" <td>-2.77</td>\n",
" <td>0.43</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201709</th>\n",
" <td>0.43</td>\n",
" <td>0.71</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201710</th>\n",
" <td>0.71</td>\n",
" <td>4.15</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201711</th>\n",
" <td>4.15</td>\n",
" <td>-0.10</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201712</th>\n",
" <td>-0.10</td>\n",
" <td>2.27</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>697 rows × 2 columns</p>\n",
"</div>"
],
"text/plain": [
" Food Food.lead\n",
"yyyymm \n",
"195912 2.01 -4.49\n",
"196001 -4.49 3.35\n",
"196002 3.35 -1.67\n",
"196003 -1.67 1.17\n",
"196004 1.17 8.20\n",
"196005 8.20 5.39\n",
"196006 5.39 -2.11\n",
"196007 -2.11 4.57\n",
"196008 4.57 -3.88\n",
"196009 -3.88 1.02\n",
"196010 1.02 9.46\n",
"196011 9.46 4.51\n",
"196012 4.51 4.70\n",
"196101 4.70 4.21\n",
"196102 4.21 4.64\n",
"196103 4.64 -1.39\n",
"196104 -1.39 4.20\n",
"196105 4.20 -2.17\n",
"196106 -2.17 2.72\n",
"196107 2.72 4.92\n",
"196108 4.92 -0.62\n",
"196109 -0.62 3.73\n",
"196110 3.73 5.28\n",
"196111 5.28 -3.69\n",
"196112 -3.69 -6.67\n",
"196201 -6.67 -0.25\n",
"196202 -0.25 0.98\n",
"196203 0.98 -4.59\n",
"196204 -4.59 -11.25\n",
"196205 -11.25 -8.75\n",
"... ... ...\n",
"201507 4.03 -4.37\n",
"201508 -4.37 -1.19\n",
"201509 -1.19 5.81\n",
"201510 5.81 0.11\n",
"201511 0.11 1.96\n",
"201512 1.96 -1.67\n",
"201601 -1.67 0.95\n",
"201602 0.95 4.69\n",
"201603 4.69 0.63\n",
"201604 0.63 2.06\n",
"201605 2.06 4.75\n",
"201606 4.75 -0.51\n",
"201607 -0.51 -0.52\n",
"201608 -0.52 -2.92\n",
"201609 -2.92 -0.33\n",
"201610 -0.33 -4.41\n",
"201611 -4.41 4.43\n",
"201612 4.43 0.95\n",
"201701 0.95 1.71\n",
"201702 1.71 0.52\n",
"201703 0.52 0.76\n",
"201704 0.76 1.63\n",
"201705 1.63 -2.65\n",
"201706 -2.65 1.52\n",
"201707 1.52 -2.77\n",
"201708 -2.77 0.43\n",
"201709 0.43 0.71\n",
"201710 0.71 4.15\n",
"201711 4.15 -0.10\n",
"201712 -0.10 2.27\n",
"\n",
"[697 rows x 2 columns]"
]
},
"metadata": {
"tags": []
},
"execution_count": 6
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "CY8mnEjbfkX3",
"outputId": "b5d28785-81a8-4740-8337-d1d47db39ea2",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"# exclude 2017 and later to tie to paper\n",
"data = data.loc[data.index[data.index < 201701]]\n",
"data = data.loc[data.index[data.index > 195911]]\n",
"data\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Food</th>\n",
" <th>Beer</th>\n",
" <th>Smoke</th>\n",
" <th>Games</th>\n",
" <th>Books</th>\n",
" <th>Hshld</th>\n",
" <th>Clths</th>\n",
" <th>Hlth</th>\n",
" <th>Chems</th>\n",
" <th>Txtls</th>\n",
" <th>Cnstr</th>\n",
" <th>Steel</th>\n",
" <th>FabPr</th>\n",
" <th>ElcEq</th>\n",
" <th>Autos</th>\n",
" <th>Carry</th>\n",
" <th>Mines</th>\n",
" <th>Coal</th>\n",
" <th>Oil</th>\n",
" <th>Util</th>\n",
" <th>Telcm</th>\n",
" <th>Servs</th>\n",
" <th>BusEq</th>\n",
" <th>Paper</th>\n",
" <th>Trans</th>\n",
" <th>Whlsl</th>\n",
" <th>Rtail</th>\n",
" <th>Meals</th>\n",
" <th>Fin</th>\n",
" <th>Other</th>\n",
" <th>Food.lead</th>\n",
" <th>Beer.lead</th>\n",
" <th>Smoke.lead</th>\n",
" <th>Games.lead</th>\n",
" <th>Books.lead</th>\n",
" <th>Hshld.lead</th>\n",
" <th>Clths.lead</th>\n",
" <th>Hlth.lead</th>\n",
" <th>Chems.lead</th>\n",
" <th>Txtls.lead</th>\n",
" <th>Cnstr.lead</th>\n",
" <th>Steel.lead</th>\n",
" <th>FabPr.lead</th>\n",
" <th>ElcEq.lead</th>\n",
" <th>Autos.lead</th>\n",
" <th>Carry.lead</th>\n",
" <th>Mines.lead</th>\n",
" <th>Coal.lead</th>\n",
" <th>Oil.lead</th>\n",
" <th>Util.lead</th>\n",
" <th>Telcm.lead</th>\n",
" <th>Servs.lead</th>\n",
" <th>BusEq.lead</th>\n",
" <th>Paper.lead</th>\n",
" <th>Trans.lead</th>\n",
" <th>Whlsl.lead</th>\n",
" <th>Rtail.lead</th>\n",
" <th>Meals.lead</th>\n",
" <th>Fin.lead</th>\n",
" <th>Other.lead</th>\n",
" </tr>\n",
" <tr>\n",
" <th>yyyymm</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>195912</th>\n",
" <td>2.01</td>\n",
" <td>0.35</td>\n",
" <td>-3.02</td>\n",
" <td>1.64</td>\n",
" <td>7.29</td>\n",
" <td>0.67</td>\n",
" <td>1.87</td>\n",
" <td>-1.97</td>\n",
" <td>3.08</td>\n",
" <td>0.74</td>\n",
" <td>0.72</td>\n",
" <td>2.18</td>\n",
" <td>3.11</td>\n",
" <td>5.53</td>\n",
" <td>5.28</td>\n",
" <td>-4.88</td>\n",
" <td>4.40</td>\n",
" <td>2.07</td>\n",
" <td>3.93</td>\n",
" <td>1.79</td>\n",
" <td>3.97</td>\n",
" <td>-1.96</td>\n",
" <td>0.67</td>\n",
" <td>1.46</td>\n",
" <td>2.03</td>\n",
" <td>-0.30</td>\n",
" <td>2.41</td>\n",
" <td>2.71</td>\n",
" <td>0.15</td>\n",
" <td>-6.50</td>\n",
" <td>-4.49</td>\n",
" <td>-5.71</td>\n",
" <td>-2.05</td>\n",
" <td>1.21</td>\n",
" <td>-5.47</td>\n",
" <td>-7.84</td>\n",
" <td>-8.53</td>\n",
" <td>-6.68</td>\n",
" <td>-10.03</td>\n",
" <td>-4.77</td>\n",
" <td>-6.67</td>\n",
" <td>-9.38</td>\n",
" <td>-4.42</td>\n",
" <td>-12.30</td>\n",
" <td>-11.71</td>\n",
" <td>-5.03</td>\n",
" <td>-3.81</td>\n",
" <td>-7.91</td>\n",
" <td>-7.82</td>\n",
" <td>-2.40</td>\n",
" <td>0.62</td>\n",
" <td>-6.18</td>\n",
" <td>-7.93</td>\n",
" <td>-9.41</td>\n",
" <td>-4.31</td>\n",
" <td>-5.33</td>\n",
" <td>-6.09</td>\n",
" <td>-10.08</td>\n",
" <td>-4.68</td>\n",
" <td>-3.98</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196001</th>\n",
" <td>-4.49</td>\n",
" <td>-5.71</td>\n",
" <td>-2.05</td>\n",
" <td>1.21</td>\n",
" <td>-5.47</td>\n",
" <td>-7.84</td>\n",
" <td>-8.53</td>\n",
" <td>-6.68</td>\n",
" <td>-10.03</td>\n",
" <td>-4.77</td>\n",
" <td>-6.67</td>\n",
" <td>-9.38</td>\n",
" <td>-4.42</td>\n",
" <td>-12.30</td>\n",
" <td>-11.71</td>\n",
" <td>-5.03</td>\n",
" <td>-3.81</td>\n",
" <td>-7.91</td>\n",
" <td>-7.82</td>\n",
" <td>-2.40</td>\n",
" <td>0.62</td>\n",
" <td>-6.18</td>\n",
" <td>-7.93</td>\n",
" <td>-9.41</td>\n",
" <td>-4.31</td>\n",
" <td>-5.33</td>\n",
" <td>-6.09</td>\n",
" <td>-10.08</td>\n",
" <td>-4.68</td>\n",
" <td>-3.98</td>\n",
" <td>3.35</td>\n",
" <td>-2.14</td>\n",
" <td>2.27</td>\n",
" <td>4.23</td>\n",
" <td>2.39</td>\n",
" <td>9.31</td>\n",
" <td>1.44</td>\n",
" <td>-0.02</td>\n",
" <td>-0.74</td>\n",
" <td>0.32</td>\n",
" <td>3.07</td>\n",
" <td>-2.03</td>\n",
" <td>-2.13</td>\n",
" <td>5.11</td>\n",
" <td>-2.15</td>\n",
" <td>2.05</td>\n",
" <td>1.57</td>\n",
" <td>-2.97</td>\n",
" <td>-3.74</td>\n",
" <td>2.48</td>\n",
" <td>8.07</td>\n",
" <td>9.13</td>\n",
" <td>5.09</td>\n",
" <td>3.00</td>\n",
" <td>-0.94</td>\n",
" <td>1.42</td>\n",
" <td>4.00</td>\n",
" <td>1.81</td>\n",
" <td>-0.98</td>\n",
" <td>6.32</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196002</th>\n",
" <td>3.35</td>\n",
" <td>-2.14</td>\n",
" <td>2.27</td>\n",
" <td>4.23</td>\n",
" <td>2.39</td>\n",
" <td>9.31</td>\n",
" <td>1.44</td>\n",
" <td>-0.02</td>\n",
" <td>-0.74</td>\n",
" <td>0.32</td>\n",
" <td>3.07</td>\n",
" <td>-2.03</td>\n",
" <td>-2.13</td>\n",
" <td>5.11</td>\n",
" <td>-2.15</td>\n",
" <td>2.05</td>\n",
" <td>1.57</td>\n",
" <td>-2.97</td>\n",
" <td>-3.74</td>\n",
" <td>2.48</td>\n",
" <td>8.07</td>\n",
" <td>9.13</td>\n",
" <td>5.09</td>\n",
" <td>3.00</td>\n",
" <td>-0.94</td>\n",
" <td>1.42</td>\n",
" <td>4.00</td>\n",
" <td>1.81</td>\n",
" <td>-0.98</td>\n",
" <td>6.32</td>\n",
" <td>-1.67</td>\n",
" <td>-2.94</td>\n",
" <td>-0.18</td>\n",
" <td>-0.65</td>\n",
" <td>2.18</td>\n",
" <td>-0.56</td>\n",
" <td>-2.59</td>\n",
" <td>1.26</td>\n",
" <td>-2.75</td>\n",
" <td>-6.79</td>\n",
" <td>-0.78</td>\n",
" <td>-5.58</td>\n",
" <td>-3.58</td>\n",
" <td>-0.89</td>\n",
" <td>-6.64</td>\n",
" <td>-8.19</td>\n",
" <td>-2.99</td>\n",
" <td>-5.47</td>\n",
" <td>-1.07</td>\n",
" <td>1.42</td>\n",
" <td>-0.21</td>\n",
" <td>-0.31</td>\n",
" <td>3.34</td>\n",
" <td>-2.43</td>\n",
" <td>-4.99</td>\n",
" <td>-1.37</td>\n",
" <td>-0.13</td>\n",
" <td>-3.88</td>\n",
" <td>0.05</td>\n",
" <td>-2.43</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196003</th>\n",
" <td>-1.67</td>\n",
" <td>-2.94</td>\n",
" <td>-0.18</td>\n",
" <td>-0.65</td>\n",
" <td>2.18</td>\n",
" <td>-0.56</td>\n",
" <td>-2.59</td>\n",
" <td>1.26</td>\n",
" <td>-2.75</td>\n",
" <td>-6.79</td>\n",
" <td>-0.78</td>\n",
" <td>-5.58</td>\n",
" <td>-3.58</td>\n",
" <td>-0.89</td>\n",
" <td>-6.64</td>\n",
" <td>-8.19</td>\n",
" <td>-2.99</td>\n",
" <td>-5.47</td>\n",
" <td>-1.07</td>\n",
" <td>1.42</td>\n",
" <td>-0.21</td>\n",
" <td>-0.31</td>\n",
" <td>3.34</td>\n",
" <td>-2.43</td>\n",
" <td>-4.99</td>\n",
" <td>-1.37</td>\n",
" <td>-0.13</td>\n",
" <td>-3.88</td>\n",
" <td>0.05</td>\n",
" <td>-2.43</td>\n",
" <td>1.17</td>\n",
" <td>-2.16</td>\n",
" <td>1.35</td>\n",
" <td>6.46</td>\n",
" <td>-1.17</td>\n",
" <td>-1.27</td>\n",
" <td>0.21</td>\n",
" <td>1.49</td>\n",
" <td>-5.53</td>\n",
" <td>-1.10</td>\n",
" <td>-1.45</td>\n",
" <td>-5.53</td>\n",
" <td>-4.10</td>\n",
" <td>-1.11</td>\n",
" <td>-2.31</td>\n",
" <td>-1.36</td>\n",
" <td>-0.81</td>\n",
" <td>-2.97</td>\n",
" <td>-4.48</td>\n",
" <td>1.18</td>\n",
" <td>-1.24</td>\n",
" <td>7.14</td>\n",
" <td>1.77</td>\n",
" <td>0.41</td>\n",
" <td>-2.13</td>\n",
" <td>0.45</td>\n",
" <td>-0.53</td>\n",
" <td>8.86</td>\n",
" <td>-0.64</td>\n",
" <td>0.55</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196004</th>\n",
" <td>1.17</td>\n",
" <td>-2.16</td>\n",
" <td>1.35</td>\n",
" <td>6.46</td>\n",
" <td>-1.17</td>\n",
" <td>-1.27</td>\n",
" <td>0.21</td>\n",
" <td>1.49</td>\n",
" <td>-5.53</td>\n",
" <td>-1.10</td>\n",
" <td>-1.45</td>\n",
" <td>-5.53</td>\n",
" <td>-4.10</td>\n",
" <td>-1.11</td>\n",
" <td>-2.31</td>\n",
" <td>-1.36</td>\n",
" <td>-0.81</td>\n",
" <td>-2.97</td>\n",
" <td>-4.48</td>\n",
" <td>1.18</td>\n",
" <td>-1.24</td>\n",
" <td>7.14</td>\n",
" <td>1.77</td>\n",
" <td>0.41</td>\n",
" <td>-2.13</td>\n",
" <td>0.45</td>\n",
" <td>-0.53</td>\n",
" <td>8.86</td>\n",
" <td>-0.64</td>\n",
" <td>0.55</td>\n",
" <td>8.20</td>\n",
" <td>-0.52</td>\n",
" <td>2.44</td>\n",
" <td>7.28</td>\n",
" <td>11.67</td>\n",
" <td>7.74</td>\n",
" <td>1.74</td>\n",
" <td>13.50</td>\n",
" <td>3.40</td>\n",
" <td>2.10</td>\n",
" <td>3.18</td>\n",
" <td>2.35</td>\n",
" <td>0.92</td>\n",
" <td>6.48</td>\n",
" <td>0.27</td>\n",
" <td>9.27</td>\n",
" <td>-1.39</td>\n",
" <td>2.41</td>\n",
" <td>-3.85</td>\n",
" <td>1.25</td>\n",
" <td>3.05</td>\n",
" <td>-1.75</td>\n",
" <td>11.90</td>\n",
" <td>2.85</td>\n",
" <td>0.90</td>\n",
" <td>1.65</td>\n",
" <td>3.11</td>\n",
" <td>0.80</td>\n",
" <td>-0.45</td>\n",
" <td>1.02</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196005</th>\n",
" <td>8.20</td>\n",
" <td>-0.52</td>\n",
" <td>2.44</td>\n",
" <td>7.28</td>\n",
" <td>11.67</td>\n",
" <td>7.74</td>\n",
" <td>1.74</td>\n",
" <td>13.50</td>\n",
" <td>3.40</td>\n",
" <td>2.10</td>\n",
" <td>3.18</td>\n",
" <td>2.35</td>\n",
" <td>0.92</td>\n",
" <td>6.48</td>\n",
" <td>0.27</td>\n",
" <td>9.27</td>\n",
" <td>-1.39</td>\n",
" <td>2.41</td>\n",
" <td>-3.85</td>\n",
" <td>1.25</td>\n",
" <td>3.05</td>\n",
" <td>-1.75</td>\n",
" <td>11.90</td>\n",
" <td>2.85</td>\n",
" <td>0.90</td>\n",
" <td>1.65</td>\n",
" <td>3.11</td>\n",
" <td>0.80</td>\n",
" <td>-0.45</td>\n",
" <td>1.02</td>\n",
" <td>5.39</td>\n",
" <td>0.47</td>\n",
" <td>4.73</td>\n",
" <td>2.24</td>\n",
" <td>0.02</td>\n",
" <td>6.38</td>\n",
" <td>-1.59</td>\n",
" <td>-0.40</td>\n",
" <td>0.45</td>\n",
" <td>4.04</td>\n",
" <td>2.54</td>\n",
" <td>1.32</td>\n",
" <td>1.63</td>\n",
" <td>-0.20</td>\n",
" <td>-0.29</td>\n",
" <td>0.36</td>\n",
" <td>-1.41</td>\n",
" <td>-1.34</td>\n",
" <td>3.38</td>\n",
" <td>5.55</td>\n",
" <td>-0.58</td>\n",
" <td>-8.07</td>\n",
" <td>2.39</td>\n",
" <td>3.50</td>\n",
" <td>2.17</td>\n",
" <td>5.96</td>\n",
" <td>3.41</td>\n",
" <td>1.03</td>\n",
" <td>3.72</td>\n",
" <td>6.41</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196006</th>\n",
" <td>5.39</td>\n",
" <td>0.47</td>\n",
" <td>4.73</td>\n",
" <td>2.24</td>\n",
" <td>0.02</td>\n",
" <td>6.38</td>\n",
" <td>-1.59</td>\n",
" <td>-0.40</td>\n",
" <td>0.45</td>\n",
" <td>4.04</td>\n",
" <td>2.54</td>\n",
" <td>1.32</td>\n",
" <td>1.63</td>\n",
" <td>-0.20</td>\n",
" <td>-0.29</td>\n",
" <td>0.36</td>\n",
" <td>-1.41</td>\n",
" <td>-1.34</td>\n",
" <td>3.38</td>\n",
" <td>5.55</td>\n",
" <td>-0.58</td>\n",
" <td>-8.07</td>\n",
" <td>2.39</td>\n",
" <td>3.50</td>\n",
" <td>2.17</td>\n",
" <td>5.96</td>\n",
" <td>3.41</td>\n",
" <td>1.03</td>\n",
" <td>3.72</td>\n",
" <td>6.41</td>\n",
" <td>-2.11</td>\n",
" <td>-0.79</td>\n",
" <td>4.60</td>\n",
" <td>-4.72</td>\n",
" <td>0.23</td>\n",
" <td>-0.60</td>\n",
" <td>-1.10</td>\n",
" <td>-3.99</td>\n",
" <td>-6.80</td>\n",
" <td>-3.14</td>\n",
" <td>-5.17</td>\n",
" <td>-2.38</td>\n",
" <td>-3.89</td>\n",
" <td>-6.96</td>\n",
" <td>-1.32</td>\n",
" <td>1.75</td>\n",
" <td>2.42</td>\n",
" <td>2.04</td>\n",
" <td>0.54</td>\n",
" <td>-1.36</td>\n",
" <td>-0.03</td>\n",
" <td>2.84</td>\n",
" <td>-2.02</td>\n",
" <td>-4.10</td>\n",
" <td>-3.11</td>\n",
" <td>-6.16</td>\n",
" <td>-2.99</td>\n",
" <td>-1.25</td>\n",
" <td>0.09</td>\n",
" <td>-5.95</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196007</th>\n",
" <td>-2.11</td>\n",
" <td>-0.79</td>\n",
" <td>4.60</td>\n",
" <td>-4.72</td>\n",
" <td>0.23</td>\n",
" <td>-0.60</td>\n",
" <td>-1.10</td>\n",
" <td>-3.99</td>\n",
" <td>-6.80</td>\n",
" <td>-3.14</td>\n",
" <td>-5.17</td>\n",
" <td>-2.38</td>\n",
" <td>-3.89</td>\n",
" <td>-6.96</td>\n",
" <td>-1.32</td>\n",
" <td>1.75</td>\n",
" <td>2.42</td>\n",
" <td>2.04</td>\n",
" <td>0.54</td>\n",
" <td>-1.36</td>\n",
" <td>-0.03</td>\n",
" <td>2.84</td>\n",
" <td>-2.02</td>\n",
" <td>-4.10</td>\n",
" <td>-3.11</td>\n",
" <td>-6.16</td>\n",
" <td>-2.99</td>\n",
" <td>-1.25</td>\n",
" <td>0.09</td>\n",
" <td>-5.95</td>\n",
" <td>4.57</td>\n",
" <td>3.24</td>\n",
" <td>5.20</td>\n",
" <td>7.16</td>\n",
" <td>3.63</td>\n",
" <td>5.09</td>\n",
" <td>3.34</td>\n",
" <td>2.29</td>\n",
" <td>1.17</td>\n",
" <td>-0.84</td>\n",
" <td>0.57</td>\n",
" <td>0.63</td>\n",
" <td>0.80</td>\n",
" <td>-1.04</td>\n",
" <td>2.89</td>\n",
" <td>6.93</td>\n",
" <td>6.94</td>\n",
" <td>3.47</td>\n",
" <td>3.94</td>\n",
" <td>4.29</td>\n",
" <td>6.94</td>\n",
" <td>5.69</td>\n",
" <td>2.71</td>\n",
" <td>1.18</td>\n",
" <td>1.98</td>\n",
" <td>4.51</td>\n",
" <td>2.85</td>\n",
" <td>2.05</td>\n",
" <td>3.47</td>\n",
" <td>3.48</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196008</th>\n",
" <td>4.57</td>\n",
" <td>3.24</td>\n",
" <td>5.20</td>\n",
" <td>7.16</td>\n",
" <td>3.63</td>\n",
" <td>5.09</td>\n",
" <td>3.34</td>\n",
" <td>2.29</td>\n",
" <td>1.17</td>\n",
" <td>-0.84</td>\n",
" <td>0.57</td>\n",
" <td>0.63</td>\n",
" <td>0.80</td>\n",
" <td>-1.04</td>\n",
" <td>2.89</td>\n",
" <td>6.93</td>\n",
" <td>6.94</td>\n",
" <td>3.47</td>\n",
" <td>3.94</td>\n",
" <td>4.29</td>\n",
" <td>6.94</td>\n",
" <td>5.69</td>\n",
" <td>2.71</td>\n",
" <td>1.18</td>\n",
" <td>1.98</td>\n",
" <td>4.51</td>\n",
" <td>2.85</td>\n",
" <td>2.05</td>\n",
" <td>3.47</td>\n",
" <td>3.48</td>\n",
" <td>-3.88</td>\n",
" <td>-5.00</td>\n",
" <td>-2.09</td>\n",
" <td>-2.33</td>\n",
" <td>-6.20</td>\n",
" <td>-9.18</td>\n",
" <td>-4.23</td>\n",
" <td>-8.87</td>\n",
" <td>-6.70</td>\n",
" <td>-5.25</td>\n",
" <td>-5.03</td>\n",
" <td>-8.24</td>\n",
" <td>-5.69</td>\n",
" <td>-10.46</td>\n",
" <td>-5.90</td>\n",
" <td>-8.73</td>\n",
" <td>-2.21</td>\n",
" <td>-5.19</td>\n",
" <td>-1.08</td>\n",
" <td>-4.71</td>\n",
" <td>-6.07</td>\n",
" <td>-3.53</td>\n",
" <td>-7.61</td>\n",
" <td>-7.37</td>\n",
" <td>-7.07</td>\n",
" <td>-8.44</td>\n",
" <td>-8.57</td>\n",
" <td>-1.90</td>\n",
" <td>-5.78</td>\n",
" <td>-4.21</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196009</th>\n",
" <td>-3.88</td>\n",
" <td>-5.00</td>\n",
" <td>-2.09</td>\n",
" <td>-2.33</td>\n",
" <td>-6.20</td>\n",
" <td>-9.18</td>\n",
" <td>-4.23</td>\n",
" <td>-8.87</td>\n",
" <td>-6.70</td>\n",
" <td>-5.25</td>\n",
" <td>-5.03</td>\n",
" <td>-8.24</td>\n",
" <td>-5.69</td>\n",
" <td>-10.46</td>\n",
" <td>-5.90</td>\n",
" <td>-8.73</td>\n",
" <td>-2.21</td>\n",
" <td>-5.19</td>\n",
" <td>-1.08</td>\n",
" <td>-4.71</td>\n",
" <td>-6.07</td>\n",
" <td>-3.53</td>\n",
" <td>-7.61</td>\n",
" <td>-7.37</td>\n",
" <td>-7.07</td>\n",
" <td>-8.44</td>\n",
" <td>-8.57</td>\n",
" <td>-1.90</td>\n",
" <td>-5.78</td>\n",
" <td>-4.21</td>\n",
" <td>1.02</td>\n",
" <td>0.54</td>\n",
" <td>3.87</td>\n",
" <td>0.11</td>\n",
" <td>2.38</td>\n",
" <td>6.48</td>\n",
" <td>-3.50</td>\n",
" <td>-3.71</td>\n",
" <td>-1.59</td>\n",
" <td>-3.06</td>\n",
" <td>-1.41</td>\n",
" <td>-2.35</td>\n",
" <td>-1.42</td>\n",
" <td>-3.58</td>\n",
" <td>-1.24</td>\n",
" <td>1.04</td>\n",
" <td>3.19</td>\n",
" <td>-1.63</td>\n",
" <td>2.28</td>\n",
" <td>-0.54</td>\n",
" <td>-0.08</td>\n",
" <td>4.62</td>\n",
" <td>-3.40</td>\n",
" <td>-1.85</td>\n",
" <td>-1.02</td>\n",
" <td>-4.22</td>\n",
" <td>0.31</td>\n",
" <td>-4.54</td>\n",
" <td>-0.40</td>\n",
" <td>0.38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196010</th>\n",
" <td>1.02</td>\n",
" <td>0.54</td>\n",
" <td>3.87</td>\n",
" <td>0.11</td>\n",
" <td>2.38</td>\n",
" <td>6.48</td>\n",
" <td>-3.50</td>\n",
" <td>-3.71</td>\n",
" <td>-1.59</td>\n",
" <td>-3.06</td>\n",
" <td>-1.41</td>\n",
" <td>-2.35</td>\n",
" <td>-1.42</td>\n",
" <td>-3.58</td>\n",
" <td>-1.24</td>\n",
" <td>1.04</td>\n",
" <td>3.19</td>\n",
" <td>-1.63</td>\n",
" <td>2.28</td>\n",
" <td>-0.54</td>\n",
" <td>-0.08</td>\n",
" <td>4.62</td>\n",
" <td>-3.40</td>\n",
" <td>-1.85</td>\n",
" <td>-1.02</td>\n",
" <td>-4.22</td>\n",
" <td>0.31</td>\n",
" <td>-4.54</td>\n",
" <td>-0.40</td>\n",
" <td>0.38</td>\n",
" <td>9.46</td>\n",
" <td>6.57</td>\n",
" <td>5.44</td>\n",
" <td>13.91</td>\n",
" <td>10.11</td>\n",
" <td>9.13</td>\n",
" <td>3.15</td>\n",
" <td>3.91</td>\n",
" <td>4.25</td>\n",
" <td>2.04</td>\n",
" <td>6.62</td>\n",
" <td>1.27</td>\n",
" <td>8.28</td>\n",
" <td>5.22</td>\n",
" <td>-0.41</td>\n",
" <td>7.55</td>\n",
" <td>7.42</td>\n",
" <td>6.64</td>\n",
" <td>3.21</td>\n",
" <td>3.66</td>\n",
" <td>4.06</td>\n",
" <td>9.49</td>\n",
" <td>8.19</td>\n",
" <td>5.31</td>\n",
" <td>5.35</td>\n",
" <td>9.72</td>\n",
" <td>6.50</td>\n",
" <td>4.40</td>\n",
" <td>7.71</td>\n",
" <td>4.01</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196011</th>\n",
" <td>9.46</td>\n",
" <td>6.57</td>\n",
" <td>5.44</td>\n",
" <td>13.91</td>\n",
" <td>10.11</td>\n",
" <td>9.13</td>\n",
" <td>3.15</td>\n",
" <td>3.91</td>\n",
" <td>4.25</td>\n",
" <td>2.04</td>\n",
" <td>6.62</td>\n",
" <td>1.27</td>\n",
" <td>8.28</td>\n",
" <td>5.22</td>\n",
" <td>-0.41</td>\n",
" <td>7.55</td>\n",
" <td>7.42</td>\n",
" <td>6.64</td>\n",
" <td>3.21</td>\n",
" <td>3.66</td>\n",
" <td>4.06</td>\n",
" <td>9.49</td>\n",
" <td>8.19</td>\n",
" <td>5.31</td>\n",
" <td>5.35</td>\n",
" <td>9.72</td>\n",
" <td>6.50</td>\n",
" <td>4.40</td>\n",
" <td>7.71</td>\n",
" <td>4.01</td>\n",
" <td>4.51</td>\n",
" <td>-0.31</td>\n",
" <td>3.54</td>\n",
" <td>7.77</td>\n",
" <td>7.41</td>\n",
" <td>1.76</td>\n",
" <td>3.28</td>\n",
" <td>6.06</td>\n",
" <td>2.85</td>\n",
" <td>0.52</td>\n",
" <td>4.27</td>\n",
" <td>4.79</td>\n",
" <td>4.79</td>\n",
" <td>1.02</td>\n",
" <td>-0.37</td>\n",
" <td>2.42</td>\n",
" <td>5.94</td>\n",
" <td>1.58</td>\n",
" <td>5.21</td>\n",
" <td>6.26</td>\n",
" <td>12.29</td>\n",
" <td>8.18</td>\n",
" <td>4.29</td>\n",
" <td>5.57</td>\n",
" <td>2.27</td>\n",
" <td>2.06</td>\n",
" <td>2.05</td>\n",
" <td>2.08</td>\n",
" <td>5.56</td>\n",
" <td>3.80</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196012</th>\n",
" <td>4.51</td>\n",
" <td>-0.31</td>\n",
" <td>3.54</td>\n",
" <td>7.77</td>\n",
" <td>7.41</td>\n",
" <td>1.76</td>\n",
" <td>3.28</td>\n",
" <td>6.06</td>\n",
" <td>2.85</td>\n",
" <td>0.52</td>\n",
" <td>4.27</td>\n",
" <td>4.79</td>\n",
" <td>4.79</td>\n",
" <td>1.02</td>\n",
" <td>-0.37</td>\n",
" <td>2.42</td>\n",
" <td>5.94</td>\n",
" <td>1.58</td>\n",
" <td>5.21</td>\n",
" <td>6.26</td>\n",
" <td>12.29</td>\n",
" <td>8.18</td>\n",
" <td>4.29</td>\n",
" <td>5.57</td>\n",
" <td>2.27</td>\n",
" <td>2.06</td>\n",
" <td>2.05</td>\n",
" <td>2.08</td>\n",
" <td>5.56</td>\n",
" <td>3.80</td>\n",
" <td>4.70</td>\n",
" <td>5.23</td>\n",
" <td>8.77</td>\n",
" <td>0.56</td>\n",
" <td>9.47</td>\n",
" <td>4.36</td>\n",
" <td>5.94</td>\n",
" <td>5.86</td>\n",
" <td>6.46</td>\n",
" <td>11.21</td>\n",
" <td>5.66</td>\n",
" <td>8.30</td>\n",
" <td>5.95</td>\n",
" <td>-0.59</td>\n",
" <td>8.50</td>\n",
" <td>6.42</td>\n",
" <td>5.95</td>\n",
" <td>10.86</td>\n",
" <td>9.54</td>\n",
" <td>4.67</td>\n",
" <td>7.70</td>\n",
" <td>4.29</td>\n",
" <td>5.08</td>\n",
" <td>4.56</td>\n",
" <td>8.35</td>\n",
" <td>7.93</td>\n",
" <td>2.28</td>\n",
" <td>4.08</td>\n",
" <td>7.12</td>\n",
" <td>8.23</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196101</th>\n",
" <td>4.70</td>\n",
" <td>5.23</td>\n",
" <td>8.77</td>\n",
" <td>0.56</td>\n",
" <td>9.47</td>\n",
" <td>4.36</td>\n",
" <td>5.94</td>\n",
" <td>5.86</td>\n",
" <td>6.46</td>\n",
" <td>11.21</td>\n",
" <td>5.66</td>\n",
" <td>8.30</td>\n",
" <td>5.95</td>\n",
" <td>-0.59</td>\n",
" <td>8.50</td>\n",
" <td>6.42</td>\n",
" <td>5.95</td>\n",
" <td>10.86</td>\n",
" <td>9.54</td>\n",
" <td>4.67</td>\n",
" <td>7.70</td>\n",
" <td>4.29</td>\n",
" <td>5.08</td>\n",
" <td>4.56</td>\n",
" <td>8.35</td>\n",
" <td>7.93</td>\n",
" <td>2.28</td>\n",
" <td>4.08</td>\n",
" <td>7.12</td>\n",
" <td>8.23</td>\n",
" <td>4.21</td>\n",
" <td>8.16</td>\n",
" <td>5.41</td>\n",
" <td>22.33</td>\n",
" <td>2.15</td>\n",
" <td>5.90</td>\n",
" <td>7.84</td>\n",
" <td>5.05</td>\n",
" <td>2.13</td>\n",
" <td>6.81</td>\n",
" <td>4.79</td>\n",
" <td>5.74</td>\n",
" <td>9.03</td>\n",
" <td>-0.29</td>\n",
" <td>4.22</td>\n",
" <td>5.99</td>\n",
" <td>-1.72</td>\n",
" <td>9.24</td>\n",
" <td>0.42</td>\n",
" <td>3.54</td>\n",
" <td>0.61</td>\n",
" <td>0.20</td>\n",
" <td>4.54</td>\n",
" <td>6.83</td>\n",
" <td>4.22</td>\n",
" <td>3.31</td>\n",
" <td>4.82</td>\n",
" <td>8.23</td>\n",
" <td>7.00</td>\n",
" <td>6.00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196102</th>\n",
" <td>4.21</td>\n",
" <td>8.16</td>\n",
" <td>5.41</td>\n",
" <td>22.33</td>\n",
" <td>2.15</td>\n",
" <td>5.90</td>\n",
" <td>7.84</td>\n",
" <td>5.05</td>\n",
" <td>2.13</td>\n",
" <td>6.81</td>\n",
" <td>4.79</td>\n",
" <td>5.74</td>\n",
" <td>9.03</td>\n",
" <td>-0.29</td>\n",
" <td>4.22</td>\n",
" <td>5.99</td>\n",
" <td>-1.72</td>\n",
" <td>9.24</td>\n",
" <td>0.42</td>\n",
" <td>3.54</td>\n",
" <td>0.61</td>\n",
" <td>0.20</td>\n",
" <td>4.54</td>\n",
" <td>6.83</td>\n",
" <td>4.22</td>\n",
" <td>3.31</td>\n",
" <td>4.82</td>\n",
" <td>8.23</td>\n",
" <td>7.00</td>\n",
" <td>6.00</td>\n",
" <td>4.64</td>\n",
" <td>2.55</td>\n",
" <td>5.60</td>\n",
" <td>7.18</td>\n",
" <td>4.77</td>\n",
" <td>6.34</td>\n",
" <td>3.08</td>\n",
" <td>3.60</td>\n",
" <td>0.92</td>\n",
" <td>5.92</td>\n",
" <td>2.50</td>\n",
" <td>1.84</td>\n",
" <td>1.52</td>\n",
" <td>2.98</td>\n",
" <td>3.14</td>\n",
" <td>1.40</td>\n",
" <td>2.43</td>\n",
" <td>-0.76</td>\n",
" <td>1.27</td>\n",
" <td>1.55</td>\n",
" <td>7.23</td>\n",
" <td>-0.20</td>\n",
" <td>2.31</td>\n",
" <td>-0.69</td>\n",
" <td>0.86</td>\n",
" <td>4.45</td>\n",
" <td>5.76</td>\n",
" <td>4.06</td>\n",
" <td>4.34</td>\n",
" <td>7.08</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196103</th>\n",
" <td>4.64</td>\n",
" <td>2.55</td>\n",
" <td>5.60</td>\n",
" <td>7.18</td>\n",
" <td>4.77</td>\n",
" <td>6.34</td>\n",
" <td>3.08</td>\n",
" <td>3.60</td>\n",
" <td>0.92</td>\n",
" <td>5.92</td>\n",
" <td>2.50</td>\n",
" <td>1.84</td>\n",
" <td>1.52</td>\n",
" <td>2.98</td>\n",
" <td>3.14</td>\n",
" <td>1.40</td>\n",
" <td>2.43</td>\n",
" <td>-0.76</td>\n",
" <td>1.27</td>\n",
" <td>1.55</td>\n",
" <td>7.23</td>\n",
" <td>-0.20</td>\n",
" <td>2.31</td>\n",
" <td>-0.69</td>\n",
" <td>0.86</td>\n",
" <td>4.45</td>\n",
" <td>5.76</td>\n",
" <td>4.06</td>\n",
" <td>4.34</td>\n",
" <td>7.08</td>\n",
" <td>-1.39</td>\n",
" <td>1.40</td>\n",
" <td>-0.23</td>\n",
" <td>-2.21</td>\n",
" <td>-6.37</td>\n",
" <td>2.66</td>\n",
" <td>2.60</td>\n",
" <td>-0.47</td>\n",
" <td>-1.47</td>\n",
" <td>-5.31</td>\n",
" <td>-3.51</td>\n",
" <td>-1.61</td>\n",
" <td>-2.32</td>\n",
" <td>-2.53</td>\n",
" <td>-1.84</td>\n",
" <td>1.98</td>\n",
" <td>0.97</td>\n",
" <td>0.51</td>\n",
" <td>4.67</td>\n",
" <td>1.70</td>\n",
" <td>0.63</td>\n",
" <td>-0.12</td>\n",
" <td>2.19</td>\n",
" <td>-0.37</td>\n",
" <td>-1.62</td>\n",
" <td>3.08</td>\n",
" <td>0.22</td>\n",
" <td>4.23</td>\n",
" <td>1.38</td>\n",
" <td>-3.67</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196104</th>\n",
" <td>-1.39</td>\n",
" <td>1.40</td>\n",
" <td>-0.23</td>\n",
" <td>-2.21</td>\n",
" <td>-6.37</td>\n",
" <td>2.66</td>\n",
" <td>2.60</td>\n",
" <td>-0.47</td>\n",
" <td>-1.47</td>\n",
" <td>-5.31</td>\n",
" <td>-3.51</td>\n",
" <td>-1.61</td>\n",
" <td>-2.32</td>\n",
" <td>-2.53</td>\n",
" <td>-1.84</td>\n",
" <td>1.98</td>\n",
" <td>0.97</td>\n",
" <td>0.51</td>\n",
" <td>4.67</td>\n",
" <td>1.70</td>\n",
" <td>0.63</td>\n",
" <td>-0.12</td>\n",
" <td>2.19</td>\n",
" <td>-0.37</td>\n",
" <td>-1.62</td>\n",
" <td>3.08</td>\n",
" <td>0.22</td>\n",
" <td>4.23</td>\n",
" <td>1.38</td>\n",
" <td>-3.67</td>\n",
" <td>4.20</td>\n",
" <td>5.38</td>\n",
" <td>3.39</td>\n",
" <td>-3.91</td>\n",
" <td>2.71</td>\n",
" <td>-0.02</td>\n",
" <td>6.80</td>\n",
" <td>2.10</td>\n",
" <td>5.50</td>\n",
" <td>5.47</td>\n",
" <td>2.11</td>\n",
" <td>5.89</td>\n",
" <td>4.64</td>\n",
" <td>4.46</td>\n",
" <td>3.35</td>\n",
" <td>2.07</td>\n",
" <td>8.46</td>\n",
" <td>7.64</td>\n",
" <td>-0.18</td>\n",
" <td>2.32</td>\n",
" <td>-1.22</td>\n",
" <td>-0.70</td>\n",
" <td>1.57</td>\n",
" <td>1.39</td>\n",
" <td>4.74</td>\n",
" <td>-0.04</td>\n",
" <td>4.31</td>\n",
" <td>-1.90</td>\n",
" <td>4.00</td>\n",
" <td>3.32</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196105</th>\n",
" <td>4.20</td>\n",
" <td>5.38</td>\n",
" <td>3.39</td>\n",
" <td>-3.91</td>\n",
" <td>2.71</td>\n",
" <td>-0.02</td>\n",
" <td>6.80</td>\n",
" <td>2.10</td>\n",
" <td>5.50</td>\n",
" <td>5.47</td>\n",
" <td>2.11</td>\n",
" <td>5.89</td>\n",
" <td>4.64</td>\n",
" <td>4.46</td>\n",
" <td>3.35</td>\n",
" <td>2.07</td>\n",
" <td>8.46</td>\n",
" <td>7.64</td>\n",
" <td>-0.18</td>\n",
" <td>2.32</td>\n",
" <td>-1.22</td>\n",
" <td>-0.70</td>\n",
" <td>1.57</td>\n",
" <td>1.39</td>\n",
" <td>4.74</td>\n",
" <td>-0.04</td>\n",
" <td>4.31</td>\n",
" <td>-1.90</td>\n",
" <td>4.00</td>\n",
" <td>3.32</td>\n",
" <td>-2.17</td>\n",
" <td>-3.12</td>\n",
" <td>3.97</td>\n",
" <td>-5.87</td>\n",
" <td>-3.85</td>\n",
" <td>3.43</td>\n",
" <td>-5.50</td>\n",
" <td>-3.58</td>\n",
" <td>-1.32</td>\n",
" <td>-3.36</td>\n",
" <td>-2.95</td>\n",
" <td>-7.65</td>\n",
" <td>-3.14</td>\n",
" <td>-3.92</td>\n",
" <td>-1.31</td>\n",
" <td>-3.38</td>\n",
" <td>-5.96</td>\n",
" <td>-4.41</td>\n",
" <td>-4.22</td>\n",
" <td>-2.02</td>\n",
" <td>-4.19</td>\n",
" <td>0.13</td>\n",
" <td>-3.31</td>\n",
" <td>-4.46</td>\n",
" <td>-4.57</td>\n",
" <td>-4.90</td>\n",
" <td>0.80</td>\n",
" <td>-5.63</td>\n",
" <td>-2.88</td>\n",
" <td>0.37</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196106</th>\n",
" <td>-2.17</td>\n",
" <td>-3.12</td>\n",
" <td>3.97</td>\n",
" <td>-5.87</td>\n",
" <td>-3.85</td>\n",
" <td>3.43</td>\n",
" <td>-5.50</td>\n",
" <td>-3.58</td>\n",
" <td>-1.32</td>\n",
" <td>-3.36</td>\n",
" <td>-2.95</td>\n",
" <td>-7.65</td>\n",
" <td>-3.14</td>\n",
" <td>-3.92</td>\n",
" <td>-1.31</td>\n",
" <td>-3.38</td>\n",
" <td>-5.96</td>\n",
" <td>-4.41</td>\n",
" <td>-4.22</td>\n",
" <td>-2.02</td>\n",
" <td>-4.19</td>\n",
" <td>0.13</td>\n",
" <td>-3.31</td>\n",
" <td>-4.46</td>\n",
" <td>-4.57</td>\n",
" <td>-4.90</td>\n",
" <td>0.80</td>\n",
" <td>-5.63</td>\n",
" <td>-2.88</td>\n",
" <td>0.37</td>\n",
" <td>2.72</td>\n",
" <td>0.88</td>\n",
" <td>5.95</td>\n",
" <td>-1.21</td>\n",
" <td>-2.55</td>\n",
" <td>1.97</td>\n",
" <td>2.03</td>\n",
" <td>3.27</td>\n",
" <td>2.95</td>\n",
" <td>1.53</td>\n",
" <td>-0.17</td>\n",
" <td>4.12</td>\n",
" <td>1.07</td>\n",
" <td>3.19</td>\n",
" <td>6.52</td>\n",
" <td>3.83</td>\n",
" <td>2.58</td>\n",
" <td>3.23</td>\n",
" <td>2.07</td>\n",
" <td>2.70</td>\n",
" <td>6.25</td>\n",
" <td>-8.25</td>\n",
" <td>0.56</td>\n",
" <td>-0.50</td>\n",
" <td>-0.32</td>\n",
" <td>-0.01</td>\n",
" <td>2.45</td>\n",
" <td>2.69</td>\n",
" <td>3.35</td>\n",
" <td>5.37</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196107</th>\n",
" <td>2.72</td>\n",
" <td>0.88</td>\n",
" <td>5.95</td>\n",
" <td>-1.21</td>\n",
" <td>-2.55</td>\n",
" <td>1.97</td>\n",
" <td>2.03</td>\n",
" <td>3.27</td>\n",
" <td>2.95</td>\n",
" <td>1.53</td>\n",
" <td>-0.17</td>\n",
" <td>4.12</td>\n",
" <td>1.07</td>\n",
" <td>3.19</td>\n",
" <td>6.52</td>\n",
" <td>3.83</td>\n",
" <td>2.58</td>\n",
" <td>3.23</td>\n",
" <td>2.07</td>\n",
" <td>2.70</td>\n",
" <td>6.25</td>\n",
" <td>-8.25</td>\n",
" <td>0.56</td>\n",
" <td>-0.50</td>\n",
" <td>-0.32</td>\n",
" <td>-0.01</td>\n",
" <td>2.45</td>\n",
" <td>2.69</td>\n",
" <td>3.35</td>\n",
" <td>5.37</td>\n",
" <td>4.92</td>\n",
" <td>3.20</td>\n",
" <td>7.74</td>\n",
" <td>0.89</td>\n",
" <td>0.89</td>\n",
" <td>10.45</td>\n",
" <td>5.21</td>\n",
" <td>3.70</td>\n",
" <td>2.35</td>\n",
" <td>5.77</td>\n",
" <td>0.82</td>\n",
" <td>0.19</td>\n",
" <td>1.63</td>\n",
" <td>3.23</td>\n",
" <td>1.95</td>\n",
" <td>-0.90</td>\n",
" <td>4.57</td>\n",
" <td>1.62</td>\n",
" <td>0.02</td>\n",
" <td>3.66</td>\n",
" <td>0.12</td>\n",
" <td>8.99</td>\n",
" <td>5.11</td>\n",
" <td>5.37</td>\n",
" <td>3.52</td>\n",
" <td>3.09</td>\n",
" <td>3.03</td>\n",
" <td>0.46</td>\n",
" <td>8.65</td>\n",
" <td>1.64</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196108</th>\n",
" <td>4.92</td>\n",
" <td>3.20</td>\n",
" <td>7.74</td>\n",
" <td>0.89</td>\n",
" <td>0.89</td>\n",
" <td>10.45</td>\n",
" <td>5.21</td>\n",
" <td>3.70</td>\n",
" <td>2.35</td>\n",
" <td>5.77</td>\n",
" <td>0.82</td>\n",
" <td>0.19</td>\n",
" <td>1.63</td>\n",
" <td>3.23</td>\n",
" <td>1.95</td>\n",
" <td>-0.90</td>\n",
" <td>4.57</td>\n",
" <td>1.62</td>\n",
" <td>0.02</td>\n",
" <td>3.66</td>\n",
" <td>0.12</td>\n",
" <td>8.99</td>\n",
" <td>5.11</td>\n",
" <td>5.37</td>\n",
" <td>3.52</td>\n",
" <td>3.09</td>\n",
" <td>3.03</td>\n",
" <td>0.46</td>\n",
" <td>8.65</td>\n",
" <td>1.64</td>\n",
" <td>-0.62</td>\n",
" <td>-1.48</td>\n",
" <td>-0.07</td>\n",
" <td>1.24</td>\n",
" <td>0.75</td>\n",
" <td>-3.05</td>\n",
" <td>-1.14</td>\n",
" <td>-1.48</td>\n",
" <td>-4.45</td>\n",
" <td>-4.25</td>\n",
" <td>-2.32</td>\n",
" <td>-7.89</td>\n",
" <td>-4.51</td>\n",
" <td>-1.38</td>\n",
" <td>4.59</td>\n",
" <td>-6.36</td>\n",
" <td>-6.28</td>\n",
" <td>1.16</td>\n",
" <td>-6.78</td>\n",
" <td>1.23</td>\n",
" <td>-2.94</td>\n",
" <td>-6.04</td>\n",
" <td>1.01</td>\n",
" <td>-2.74</td>\n",
" <td>-1.16</td>\n",
" <td>-4.22</td>\n",
" <td>0.66</td>\n",
" <td>-6.21</td>\n",
" <td>-0.40</td>\n",
" <td>3.14</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196109</th>\n",
" <td>-0.62</td>\n",
" <td>-1.48</td>\n",
" <td>-0.07</td>\n",
" <td>1.24</td>\n",
" <td>0.75</td>\n",
" <td>-3.05</td>\n",
" <td>-1.14</td>\n",
" <td>-1.48</td>\n",
" <td>-4.45</td>\n",
" <td>-4.25</td>\n",
" <td>-2.32</td>\n",
" <td>-7.89</td>\n",
" <td>-4.51</td>\n",
" <td>-1.38</td>\n",
" <td>4.59</td>\n",
" <td>-6.36</td>\n",
" <td>-6.28</td>\n",
" <td>1.16</td>\n",
" <td>-6.78</td>\n",
" <td>1.23</td>\n",
" <td>-2.94</td>\n",
" <td>-6.04</td>\n",
" <td>1.01</td>\n",
" <td>-2.74</td>\n",
" <td>-1.16</td>\n",
" <td>-4.22</td>\n",
" <td>0.66</td>\n",
" <td>-6.21</td>\n",
" <td>-0.40</td>\n",
" <td>3.14</td>\n",
" <td>3.73</td>\n",
" <td>-0.84</td>\n",
" <td>7.05</td>\n",
" <td>-5.26</td>\n",
" <td>0.99</td>\n",
" <td>-0.67</td>\n",
" <td>8.28</td>\n",
" <td>3.33</td>\n",
" <td>0.05</td>\n",
" <td>3.11</td>\n",
" <td>0.74</td>\n",
" <td>-1.90</td>\n",
" <td>0.55</td>\n",
" <td>-1.95</td>\n",
" <td>0.07</td>\n",
" <td>-5.26</td>\n",
" <td>-2.23</td>\n",
" <td>4.64</td>\n",
" <td>6.47</td>\n",
" <td>5.11</td>\n",
" <td>0.00</td>\n",
" <td>2.24</td>\n",
" <td>6.53</td>\n",
" <td>1.74</td>\n",
" <td>2.16</td>\n",
" <td>4.30</td>\n",
" <td>9.35</td>\n",
" <td>0.71</td>\n",
" <td>2.02</td>\n",
" <td>0.39</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196110</th>\n",
" <td>3.73</td>\n",
" <td>-0.84</td>\n",
" <td>7.05</td>\n",
" <td>-5.26</td>\n",
" <td>0.99</td>\n",
" <td>-0.67</td>\n",
" <td>8.28</td>\n",
" <td>3.33</td>\n",
" <td>0.05</td>\n",
" <td>3.11</td>\n",
" <td>0.74</td>\n",
" <td>-1.90</td>\n",
" <td>0.55</td>\n",
" <td>-1.95</td>\n",
" <td>0.07</td>\n",
" <td>-5.26</td>\n",
" <td>-2.23</td>\n",
" <td>4.64</td>\n",
" <td>6.47</td>\n",
" <td>5.11</td>\n",
" <td>0.00</td>\n",
" <td>2.24</td>\n",
" <td>6.53</td>\n",
" <td>1.74</td>\n",
" <td>2.16</td>\n",
" <td>4.30</td>\n",
" <td>9.35</td>\n",
" <td>0.71</td>\n",
" <td>2.02</td>\n",
" <td>0.39</td>\n",
" <td>5.28</td>\n",
" <td>4.47</td>\n",
" <td>8.03</td>\n",
" <td>0.25</td>\n",
" <td>3.75</td>\n",
" <td>4.51</td>\n",
" <td>5.30</td>\n",
" <td>3.12</td>\n",
" <td>2.49</td>\n",
" <td>7.37</td>\n",
" <td>6.06</td>\n",
" <td>1.65</td>\n",
" <td>3.01</td>\n",
" <td>5.78</td>\n",
" <td>8.60</td>\n",
" <td>3.19</td>\n",
" <td>3.56</td>\n",
" <td>6.09</td>\n",
" <td>5.37</td>\n",
" <td>3.26</td>\n",
" <td>8.34</td>\n",
" <td>8.27</td>\n",
" <td>0.99</td>\n",
" <td>2.05</td>\n",
" <td>0.47</td>\n",
" <td>5.65</td>\n",
" <td>4.90</td>\n",
" <td>1.08</td>\n",
" <td>7.22</td>\n",
" <td>1.69</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196111</th>\n",
" <td>5.28</td>\n",
" <td>4.47</td>\n",
" <td>8.03</td>\n",
" <td>0.25</td>\n",
" <td>3.75</td>\n",
" <td>4.51</td>\n",
" <td>5.30</td>\n",
" <td>3.12</td>\n",
" <td>2.49</td>\n",
" <td>7.37</td>\n",
" <td>6.06</td>\n",
" <td>1.65</td>\n",
" <td>3.01</td>\n",
" <td>5.78</td>\n",
" <td>8.60</td>\n",
" <td>3.19</td>\n",
" <td>3.56</td>\n",
" <td>6.09</td>\n",
" <td>5.37</td>\n",
" <td>3.26</td>\n",
" <td>8.34</td>\n",
" <td>8.27</td>\n",
" <td>0.99</td>\n",
" <td>2.05</td>\n",
" <td>0.47</td>\n",
" <td>5.65</td>\n",
" <td>4.90</td>\n",
" <td>1.08</td>\n",
" <td>7.22</td>\n",
" <td>1.69</td>\n",
" <td>-3.69</td>\n",
" <td>1.41</td>\n",
" <td>-6.12</td>\n",
" <td>1.97</td>\n",
" <td>-3.66</td>\n",
" <td>-3.78</td>\n",
" <td>0.32</td>\n",
" <td>-2.21</td>\n",
" <td>-0.16</td>\n",
" <td>-1.17</td>\n",
" <td>0.17</td>\n",
" <td>3.12</td>\n",
" <td>0.07</td>\n",
" <td>-1.42</td>\n",
" <td>1.74</td>\n",
" <td>0.21</td>\n",
" <td>-3.07</td>\n",
" <td>0.10</td>\n",
" <td>3.69</td>\n",
" <td>-4.40</td>\n",
" <td>3.14</td>\n",
" <td>-0.68</td>\n",
" <td>-0.55</td>\n",
" <td>-2.65</td>\n",
" <td>-0.24</td>\n",
" <td>0.46</td>\n",
" <td>-0.63</td>\n",
" <td>-2.21</td>\n",
" <td>-4.44</td>\n",
" <td>-0.77</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196112</th>\n",
" <td>-3.69</td>\n",
" <td>1.41</td>\n",
" <td>-6.12</td>\n",
" <td>1.97</td>\n",
" <td>-3.66</td>\n",
" <td>-3.78</td>\n",
" <td>0.32</td>\n",
" <td>-2.21</td>\n",
" <td>-0.16</td>\n",
" <td>-1.17</td>\n",
" <td>0.17</td>\n",
" <td>3.12</td>\n",
" <td>0.07</td>\n",
" <td>-1.42</td>\n",
" <td>1.74</td>\n",
" <td>0.21</td>\n",
" <td>-3.07</td>\n",
" <td>0.10</td>\n",
" <td>3.69</td>\n",
" <td>-4.40</td>\n",
" <td>3.14</td>\n",
" <td>-0.68</td>\n",
" <td>-0.55</td>\n",
" <td>-2.65</td>\n",
" <td>-0.24</td>\n",
" <td>0.46</td>\n",
" <td>-0.63</td>\n",
" <td>-2.21</td>\n",
" <td>-4.44</td>\n",
" <td>-0.77</td>\n",
" <td>-6.67</td>\n",
" <td>-3.45</td>\n",
" <td>-4.28</td>\n",
" <td>-13.23</td>\n",
" <td>-3.44</td>\n",
" <td>-7.37</td>\n",
" <td>-5.89</td>\n",
" <td>-4.86</td>\n",
" <td>-4.76</td>\n",
" <td>0.57</td>\n",
" <td>-5.50</td>\n",
" <td>-3.99</td>\n",
" <td>-0.65</td>\n",
" <td>-2.46</td>\n",
" <td>-1.27</td>\n",
" <td>6.47</td>\n",
" <td>-1.58</td>\n",
" <td>4.67</td>\n",
" <td>-0.27</td>\n",
" <td>-2.82</td>\n",
" <td>-6.32</td>\n",
" <td>-4.88</td>\n",
" <td>-6.91</td>\n",
" <td>-5.22</td>\n",
" <td>2.52</td>\n",
" <td>-0.79</td>\n",
" <td>-9.56</td>\n",
" <td>-3.90</td>\n",
" <td>-4.99</td>\n",
" <td>-3.62</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196201</th>\n",
" <td>-6.67</td>\n",
" <td>-3.45</td>\n",
" <td>-4.28</td>\n",
" <td>-13.23</td>\n",
" <td>-3.44</td>\n",
" <td>-7.37</td>\n",
" <td>-5.89</td>\n",
" <td>-4.86</td>\n",
" <td>-4.76</td>\n",
" <td>0.57</td>\n",
" <td>-5.50</td>\n",
" <td>-3.99</td>\n",
" <td>-0.65</td>\n",
" <td>-2.46</td>\n",
" <td>-1.27</td>\n",
" <td>6.47</td>\n",
" <td>-1.58</td>\n",
" <td>4.67</td>\n",
" <td>-0.27</td>\n",
" <td>-2.82</td>\n",
" <td>-6.32</td>\n",
" <td>-4.88</td>\n",
" <td>-6.91</td>\n",
" <td>-5.22</td>\n",
" <td>2.52</td>\n",
" <td>-0.79</td>\n",
" <td>-9.56</td>\n",
" <td>-3.90</td>\n",
" <td>-4.99</td>\n",
" <td>-3.62</td>\n",
" <td>-0.25</td>\n",
" <td>0.28</td>\n",
" <td>0.68</td>\n",
" <td>-2.02</td>\n",
" <td>-0.52</td>\n",
" <td>-0.90</td>\n",
" <td>2.01</td>\n",
" <td>3.56</td>\n",
" <td>3.30</td>\n",
" <td>1.93</td>\n",
" <td>1.09</td>\n",
" <td>-1.06</td>\n",
" <td>1.51</td>\n",
" <td>-0.45</td>\n",
" <td>-1.54</td>\n",
" <td>-3.34</td>\n",
" <td>-3.31</td>\n",
" <td>0.46</td>\n",
" <td>5.27</td>\n",
" <td>2.42</td>\n",
" <td>3.89</td>\n",
" <td>-1.94</td>\n",
" <td>-0.07</td>\n",
" <td>3.87</td>\n",
" <td>0.32</td>\n",
" <td>-0.09</td>\n",
" <td>1.58</td>\n",
" <td>-0.59</td>\n",
" <td>3.59</td>\n",
" <td>4.20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196202</th>\n",
" <td>-0.25</td>\n",
" <td>0.28</td>\n",
" <td>0.68</td>\n",
" <td>-2.02</td>\n",
" <td>-0.52</td>\n",
" <td>-0.90</td>\n",
" <td>2.01</td>\n",
" <td>3.56</td>\n",
" <td>3.30</td>\n",
" <td>1.93</td>\n",
" <td>1.09</td>\n",
" <td>-1.06</td>\n",
" <td>1.51</td>\n",
" <td>-0.45</td>\n",
" <td>-1.54</td>\n",
" <td>-3.34</td>\n",
" <td>-3.31</td>\n",
" <td>0.46</td>\n",
" <td>5.27</td>\n",
" <td>2.42</td>\n",
" <td>3.89</td>\n",
" <td>-1.94</td>\n",
" <td>-0.07</td>\n",
" <td>3.87</td>\n",
" <td>0.32</td>\n",
" <td>-0.09</td>\n",
" <td>1.58</td>\n",
" <td>-0.59</td>\n",
" <td>3.59</td>\n",
" <td>4.20</td>\n",
" <td>0.98</td>\n",
" <td>-0.34</td>\n",
" <td>-6.67</td>\n",
" <td>-5.34</td>\n",
" <td>0.41</td>\n",
" <td>4.31</td>\n",
" <td>-1.18</td>\n",
" <td>0.34</td>\n",
" <td>-2.72</td>\n",
" <td>-0.74</td>\n",
" <td>-0.58</td>\n",
" <td>0.76</td>\n",
" <td>-1.90</td>\n",
" <td>1.20</td>\n",
" <td>-1.10</td>\n",
" <td>-3.54</td>\n",
" <td>-1.49</td>\n",
" <td>-4.68</td>\n",
" <td>-1.79</td>\n",
" <td>1.78</td>\n",
" <td>-3.14</td>\n",
" <td>-1.41</td>\n",
" <td>-0.76</td>\n",
" <td>1.13</td>\n",
" <td>-1.68</td>\n",
" <td>-2.30</td>\n",
" <td>0.90</td>\n",
" <td>-4.07</td>\n",
" <td>-2.13</td>\n",
" <td>-1.83</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196203</th>\n",
" <td>0.98</td>\n",
" <td>-0.34</td>\n",
" <td>-6.67</td>\n",
" <td>-5.34</td>\n",
" <td>0.41</td>\n",
" <td>4.31</td>\n",
" <td>-1.18</td>\n",
" <td>0.34</td>\n",
" <td>-2.72</td>\n",
" <td>-0.74</td>\n",
" <td>-0.58</td>\n",
" <td>0.76</td>\n",
" <td>-1.90</td>\n",
" <td>1.20</td>\n",
" <td>-1.10</td>\n",
" <td>-3.54</td>\n",
" <td>-1.49</td>\n",
" <td>-4.68</td>\n",
" <td>-1.79</td>\n",
" <td>1.78</td>\n",
" <td>-3.14</td>\n",
" <td>-1.41</td>\n",
" <td>-0.76</td>\n",
" <td>1.13</td>\n",
" <td>-1.68</td>\n",
" <td>-2.30</td>\n",
" <td>0.90</td>\n",
" <td>-4.07</td>\n",
" <td>-2.13</td>\n",
" <td>-1.83</td>\n",
" <td>-4.59</td>\n",
" <td>-3.59</td>\n",
" <td>-12.99</td>\n",
" <td>-11.04</td>\n",
" <td>-8.74</td>\n",
" <td>-7.03</td>\n",
" <td>-8.01</td>\n",
" <td>-11.23</td>\n",
" <td>-6.23</td>\n",
" <td>-7.53</td>\n",
" <td>-7.47</td>\n",
" <td>-10.60</td>\n",
" <td>-7.95</td>\n",
" <td>-10.16</td>\n",
" <td>-5.51</td>\n",
" <td>-10.21</td>\n",
" <td>-7.73</td>\n",
" <td>-10.11</td>\n",
" <td>-3.70</td>\n",
" <td>-3.01</td>\n",
" <td>-4.93</td>\n",
" <td>-3.11</td>\n",
" <td>-12.01</td>\n",
" <td>-7.93</td>\n",
" <td>-6.27</td>\n",
" <td>-5.78</td>\n",
" <td>-4.61</td>\n",
" <td>-9.09</td>\n",
" <td>-7.69</td>\n",
" <td>-2.12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196204</th>\n",
" <td>-4.59</td>\n",
" <td>-3.59</td>\n",
" <td>-12.99</td>\n",
" <td>-11.04</td>\n",
" <td>-8.74</td>\n",
" <td>-7.03</td>\n",
" <td>-8.01</td>\n",
" <td>-11.23</td>\n",
" <td>-6.23</td>\n",
" <td>-7.53</td>\n",
" <td>-7.47</td>\n",
" <td>-10.60</td>\n",
" <td>-7.95</td>\n",
" <td>-10.16</td>\n",
" <td>-5.51</td>\n",
" <td>-10.21</td>\n",
" <td>-7.73</td>\n",
" <td>-10.11</td>\n",
" <td>-3.70</td>\n",
" <td>-3.01</td>\n",
" <td>-4.93</td>\n",
" <td>-3.11</td>\n",
" <td>-12.01</td>\n",
" <td>-7.93</td>\n",
" <td>-6.27</td>\n",
" <td>-5.78</td>\n",
" <td>-4.61</td>\n",
" <td>-9.09</td>\n",
" <td>-7.69</td>\n",
" <td>-2.12</td>\n",
" <td>-11.25</td>\n",
" <td>-9.05</td>\n",
" <td>-14.14</td>\n",
" <td>-11.39</td>\n",
" <td>-14.87</td>\n",
" <td>-10.19</td>\n",
" <td>-10.01</td>\n",
" <td>-11.14</td>\n",
" <td>-8.25</td>\n",
" <td>-7.50</td>\n",
" <td>-9.01</td>\n",
" <td>-7.41</td>\n",
" <td>-8.11</td>\n",
" <td>-8.77</td>\n",
" <td>-5.54</td>\n",
" <td>-5.58</td>\n",
" <td>-4.64</td>\n",
" <td>-9.94</td>\n",
" <td>-5.12</td>\n",
" <td>-10.70</td>\n",
" <td>-7.35</td>\n",
" <td>-10.97</td>\n",
" <td>-13.19</td>\n",
" <td>-11.03</td>\n",
" <td>-5.17</td>\n",
" <td>-11.34</td>\n",
" <td>-9.09</td>\n",
" <td>-7.46</td>\n",
" <td>-10.02</td>\n",
" <td>-11.83</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196205</th>\n",
" <td>-11.25</td>\n",
" <td>-9.05</td>\n",
" <td>-14.14</td>\n",
" <td>-11.39</td>\n",
" <td>-14.87</td>\n",
" <td>-10.19</td>\n",
" <td>-10.01</td>\n",
" <td>-11.14</td>\n",
" <td>-8.25</td>\n",
" <td>-7.50</td>\n",
" <td>-9.01</td>\n",
" <td>-7.41</td>\n",
" <td>-8.11</td>\n",
" <td>-8.77</td>\n",
" <td>-5.54</td>\n",
" <td>-5.58</td>\n",
" <td>-4.64</td>\n",
" <td>-9.94</td>\n",
" <td>-5.12</td>\n",
" <td>-10.70</td>\n",
" <td>-7.35</td>\n",
" <td>-10.97</td>\n",
" <td>-13.19</td>\n",
" <td>-11.03</td>\n",
" <td>-5.17</td>\n",
" <td>-11.34</td>\n",
" <td>-9.09</td>\n",
" <td>-7.46</td>\n",
" <td>-10.02</td>\n",
" <td>-11.83</td>\n",
" <td>-8.75</td>\n",
" <td>-6.17</td>\n",
" <td>-8.33</td>\n",
" <td>-15.75</td>\n",
" <td>-16.53</td>\n",
" <td>-12.32</td>\n",
" <td>-8.91</td>\n",
" <td>-12.79</td>\n",
" <td>-8.68</td>\n",
" <td>-4.51</td>\n",
" <td>-11.36</td>\n",
" <td>-10.21</td>\n",
" <td>-8.39</td>\n",
" <td>-10.60</td>\n",
" <td>-7.24</td>\n",
" <td>-7.44</td>\n",
" <td>-4.28</td>\n",
" <td>-7.16</td>\n",
" <td>-5.02</td>\n",
" <td>-5.30</td>\n",
" <td>-8.72</td>\n",
" <td>-13.11</td>\n",
" <td>-12.59</td>\n",
" <td>-9.62</td>\n",
" <td>-7.81</td>\n",
" <td>-11.11</td>\n",
" <td>-10.43</td>\n",
" <td>-12.90</td>\n",
" <td>-11.01</td>\n",
" <td>-14.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201407</th>\n",
" <td>-5.83</td>\n",
" <td>-2.92</td>\n",
" <td>-3.48</td>\n",
" <td>-3.70</td>\n",
" <td>-1.60</td>\n",
" <td>-2.62</td>\n",
" <td>-0.62</td>\n",
" <td>-0.33</td>\n",
" <td>-3.26</td>\n",
" <td>-5.70</td>\n",
" <td>-8.80</td>\n",
" <td>1.53</td>\n",
" <td>-6.34</td>\n",
" <td>-6.60</td>\n",
" <td>-3.77</td>\n",
" <td>-5.68</td>\n",
" <td>1.93</td>\n",
" <td>-11.20</td>\n",
" <td>-3.49</td>\n",
" <td>-6.47</td>\n",
" <td>0.46</td>\n",
" <td>0.52</td>\n",
" <td>-0.26</td>\n",
" <td>-4.08</td>\n",
" <td>-2.04</td>\n",
" <td>-2.76</td>\n",
" <td>-1.86</td>\n",
" <td>-3.11</td>\n",
" <td>-2.08</td>\n",
" <td>-2.07</td>\n",
" <td>6.38</td>\n",
" <td>5.46</td>\n",
" <td>5.08</td>\n",
" <td>-1.80</td>\n",
" <td>2.64</td>\n",
" <td>5.87</td>\n",
" <td>3.53</td>\n",
" <td>5.44</td>\n",
" <td>4.39</td>\n",
" <td>10.14</td>\n",
" <td>6.72</td>\n",
" <td>6.26</td>\n",
" <td>5.11</td>\n",
" <td>3.42</td>\n",
" <td>4.26</td>\n",
" <td>5.74</td>\n",
" <td>1.34</td>\n",
" <td>4.18</td>\n",
" <td>2.25</td>\n",
" <td>5.38</td>\n",
" <td>0.52</td>\n",
" <td>3.49</td>\n",
" <td>5.10</td>\n",
" <td>3.38</td>\n",
" <td>4.57</td>\n",
" <td>4.87</td>\n",
" <td>5.71</td>\n",
" <td>3.32</td>\n",
" <td>3.81</td>\n",
" <td>7.19</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201408</th>\n",
" <td>6.38</td>\n",
" <td>5.46</td>\n",
" <td>5.08</td>\n",
" <td>-1.80</td>\n",
" <td>2.64</td>\n",
" <td>5.87</td>\n",
" <td>3.53</td>\n",
" <td>5.44</td>\n",
" <td>4.39</td>\n",
" <td>10.14</td>\n",
" <td>6.72</td>\n",
" <td>6.26</td>\n",
" <td>5.11</td>\n",
" <td>3.42</td>\n",
" <td>4.26</td>\n",
" <td>5.74</td>\n",
" <td>1.34</td>\n",
" <td>4.18</td>\n",
" <td>2.25</td>\n",
" <td>5.38</td>\n",
" <td>0.52</td>\n",
" <td>3.49</td>\n",
" <td>5.10</td>\n",
" <td>3.38</td>\n",
" <td>4.57</td>\n",
" <td>4.87</td>\n",
" <td>5.71</td>\n",
" <td>3.32</td>\n",
" <td>3.81</td>\n",
" <td>7.19</td>\n",
" <td>-0.53</td>\n",
" <td>0.83</td>\n",
" <td>2.15</td>\n",
" <td>-4.38</td>\n",
" <td>-7.29</td>\n",
" <td>0.84</td>\n",
" <td>4.44</td>\n",
" <td>-0.08</td>\n",
" <td>-2.14</td>\n",
" <td>-2.38</td>\n",
" <td>-6.38</td>\n",
" <td>-5.07</td>\n",
" <td>-7.00</td>\n",
" <td>-4.82</td>\n",
" <td>-10.06</td>\n",
" <td>-0.96</td>\n",
" <td>-10.77</td>\n",
" <td>-14.41</td>\n",
" <td>-7.98</td>\n",
" <td>-3.41</td>\n",
" <td>-1.70</td>\n",
" <td>-1.20</td>\n",
" <td>-1.91</td>\n",
" <td>-3.49</td>\n",
" <td>0.71</td>\n",
" <td>-2.29</td>\n",
" <td>-1.50</td>\n",
" <td>-0.60</td>\n",
" <td>-0.59</td>\n",
" <td>0.16</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201409</th>\n",
" <td>-0.53</td>\n",
" <td>0.83</td>\n",
" <td>2.15</td>\n",
" <td>-4.38</td>\n",
" <td>-7.29</td>\n",
" <td>0.84</td>\n",
" <td>4.44</td>\n",
" <td>-0.08</td>\n",
" <td>-2.14</td>\n",
" <td>-2.38</td>\n",
" <td>-6.38</td>\n",
" <td>-5.07</td>\n",
" <td>-7.00</td>\n",
" <td>-4.82</td>\n",
" <td>-10.06</td>\n",
" <td>-0.96</td>\n",
" <td>-10.77</td>\n",
" <td>-14.41</td>\n",
" <td>-7.98</td>\n",
" <td>-3.41</td>\n",
" <td>-1.70</td>\n",
" <td>-1.20</td>\n",
" <td>-1.91</td>\n",
" <td>-3.49</td>\n",
" <td>0.71</td>\n",
" <td>-2.29</td>\n",
" <td>-1.50</td>\n",
" <td>-0.60</td>\n",
" <td>-0.59</td>\n",
" <td>0.16</td>\n",
" <td>1.70</td>\n",
" <td>3.28</td>\n",
" <td>6.13</td>\n",
" <td>0.58</td>\n",
" <td>3.28</td>\n",
" <td>3.71</td>\n",
" <td>1.57</td>\n",
" <td>5.77</td>\n",
" <td>-1.09</td>\n",
" <td>2.08</td>\n",
" <td>3.97</td>\n",
" <td>2.49</td>\n",
" <td>2.49</td>\n",
" <td>3.21</td>\n",
" <td>1.98</td>\n",
" <td>1.18</td>\n",
" <td>-9.28</td>\n",
" <td>-6.31</td>\n",
" <td>-4.47</td>\n",
" <td>6.69</td>\n",
" <td>1.42</td>\n",
" <td>0.46</td>\n",
" <td>2.83</td>\n",
" <td>6.42</td>\n",
" <td>6.22</td>\n",
" <td>3.32</td>\n",
" <td>3.32</td>\n",
" <td>1.28</td>\n",
" <td>3.87</td>\n",
" <td>1.58</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201410</th>\n",
" <td>1.70</td>\n",
" <td>3.28</td>\n",
" <td>6.13</td>\n",
" <td>0.58</td>\n",
" <td>3.28</td>\n",
" <td>3.71</td>\n",
" <td>1.57</td>\n",
" <td>5.77</td>\n",
" <td>-1.09</td>\n",
" <td>2.08</td>\n",
" <td>3.97</td>\n",
" <td>2.49</td>\n",
" <td>2.49</td>\n",
" <td>3.21</td>\n",
" <td>1.98</td>\n",
" <td>1.18</td>\n",
" <td>-9.28</td>\n",
" <td>-6.31</td>\n",
" <td>-4.47</td>\n",
" <td>6.69</td>\n",
" <td>1.42</td>\n",
" <td>0.46</td>\n",
" <td>2.83</td>\n",
" <td>6.42</td>\n",
" <td>6.22</td>\n",
" <td>3.32</td>\n",
" <td>3.32</td>\n",
" <td>1.28</td>\n",
" <td>3.87</td>\n",
" <td>1.58</td>\n",
" <td>5.68</td>\n",
" <td>4.35</td>\n",
" <td>0.76</td>\n",
" <td>-0.40</td>\n",
" <td>1.11</td>\n",
" <td>3.23</td>\n",
" <td>8.89</td>\n",
" <td>2.67</td>\n",
" <td>2.21</td>\n",
" <td>7.53</td>\n",
" <td>1.32</td>\n",
" <td>-2.26</td>\n",
" <td>-1.19</td>\n",
" <td>-0.08</td>\n",
" <td>5.26</td>\n",
" <td>4.68</td>\n",
" <td>-0.88</td>\n",
" <td>3.96</td>\n",
" <td>-10.03</td>\n",
" <td>0.29</td>\n",
" <td>3.03</td>\n",
" <td>2.05</td>\n",
" <td>6.47</td>\n",
" <td>4.80</td>\n",
" <td>5.88</td>\n",
" <td>1.83</td>\n",
" <td>8.91</td>\n",
" <td>5.57</td>\n",
" <td>1.93</td>\n",
" <td>4.55</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201411</th>\n",
" <td>5.68</td>\n",
" <td>4.35</td>\n",
" <td>0.76</td>\n",
" <td>-0.40</td>\n",
" <td>1.11</td>\n",
" <td>3.23</td>\n",
" <td>8.89</td>\n",
" <td>2.67</td>\n",
" <td>2.21</td>\n",
" <td>7.53</td>\n",
" <td>1.32</td>\n",
" <td>-2.26</td>\n",
" <td>-1.19</td>\n",
" <td>-0.08</td>\n",
" <td>5.26</td>\n",
" <td>4.68</td>\n",
" <td>-0.88</td>\n",
" <td>3.96</td>\n",
" <td>-10.03</td>\n",
" <td>0.29</td>\n",
" <td>3.03</td>\n",
" <td>2.05</td>\n",
" <td>6.47</td>\n",
" <td>4.80</td>\n",
" <td>5.88</td>\n",
" <td>1.83</td>\n",
" <td>8.91</td>\n",
" <td>5.57</td>\n",
" <td>1.93</td>\n",
" <td>4.55</td>\n",
" <td>-2.48</td>\n",
" <td>-4.30</td>\n",
" <td>-3.11</td>\n",
" <td>-4.60</td>\n",
" <td>1.83</td>\n",
" <td>0.02</td>\n",
" <td>-0.82</td>\n",
" <td>-0.89</td>\n",
" <td>0.83</td>\n",
" <td>-0.31</td>\n",
" <td>0.04</td>\n",
" <td>-6.01</td>\n",
" <td>-1.13</td>\n",
" <td>-0.90</td>\n",
" <td>0.56</td>\n",
" <td>-0.59</td>\n",
" <td>-6.40</td>\n",
" <td>-16.46</td>\n",
" <td>0.58</td>\n",
" <td>1.84</td>\n",
" <td>-1.73</td>\n",
" <td>-0.60</td>\n",
" <td>-1.87</td>\n",
" <td>2.08</td>\n",
" <td>1.09</td>\n",
" <td>0.26</td>\n",
" <td>2.25</td>\n",
" <td>-0.43</td>\n",
" <td>2.08</td>\n",
" <td>0.17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201412</th>\n",
" <td>-2.48</td>\n",
" <td>-4.30</td>\n",
" <td>-3.11</td>\n",
" <td>-4.60</td>\n",
" <td>1.83</td>\n",
" <td>0.02</td>\n",
" <td>-0.82</td>\n",
" <td>-0.89</td>\n",
" <td>0.83</td>\n",
" <td>-0.31</td>\n",
" <td>0.04</td>\n",
" <td>-6.01</td>\n",
" <td>-1.13</td>\n",
" <td>-0.90</td>\n",
" <td>0.56</td>\n",
" <td>-0.59</td>\n",
" <td>-6.40</td>\n",
" <td>-16.46</td>\n",
" <td>0.58</td>\n",
" <td>1.84</td>\n",
" <td>-1.73</td>\n",
" <td>-0.60</td>\n",
" <td>-1.87</td>\n",
" <td>2.08</td>\n",
" <td>1.09</td>\n",
" <td>0.26</td>\n",
" <td>2.25</td>\n",
" <td>-0.43</td>\n",
" <td>2.08</td>\n",
" <td>0.17</td>\n",
" <td>-1.64</td>\n",
" <td>0.90</td>\n",
" <td>2.95</td>\n",
" <td>0.25</td>\n",
" <td>-2.18</td>\n",
" <td>-4.92</td>\n",
" <td>-3.75</td>\n",
" <td>1.56</td>\n",
" <td>-2.01</td>\n",
" <td>2.02</td>\n",
" <td>-5.09</td>\n",
" <td>-8.96</td>\n",
" <td>-7.59</td>\n",
" <td>-5.38</td>\n",
" <td>-6.25</td>\n",
" <td>1.02</td>\n",
" <td>-4.35</td>\n",
" <td>-17.48</td>\n",
" <td>-4.30</td>\n",
" <td>1.18</td>\n",
" <td>-4.89</td>\n",
" <td>-4.44</td>\n",
" <td>-2.14</td>\n",
" <td>-2.43</td>\n",
" <td>-4.53</td>\n",
" <td>-2.37</td>\n",
" <td>-0.29</td>\n",
" <td>0.66</td>\n",
" <td>-7.61</td>\n",
" <td>-4.11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201501</th>\n",
" <td>-1.64</td>\n",
" <td>0.90</td>\n",
" <td>2.95</td>\n",
" <td>0.25</td>\n",
" <td>-2.18</td>\n",
" <td>-4.92</td>\n",
" <td>-3.75</td>\n",
" <td>1.56</td>\n",
" <td>-2.01</td>\n",
" <td>2.02</td>\n",
" <td>-5.09</td>\n",
" <td>-8.96</td>\n",
" <td>-7.59</td>\n",
" <td>-5.38</td>\n",
" <td>-6.25</td>\n",
" <td>1.02</td>\n",
" <td>-4.35</td>\n",
" <td>-17.48</td>\n",
" <td>-4.30</td>\n",
" <td>1.18</td>\n",
" <td>-4.89</td>\n",
" <td>-4.44</td>\n",
" <td>-2.14</td>\n",
" <td>-2.43</td>\n",
" <td>-4.53</td>\n",
" <td>-2.37</td>\n",
" <td>-0.29</td>\n",
" <td>0.66</td>\n",
" <td>-7.61</td>\n",
" <td>-4.11</td>\n",
" <td>4.44</td>\n",
" <td>4.40</td>\n",
" <td>5.47</td>\n",
" <td>5.87</td>\n",
" <td>9.00</td>\n",
" <td>3.83</td>\n",
" <td>5.43</td>\n",
" <td>4.31</td>\n",
" <td>8.10</td>\n",
" <td>13.34</td>\n",
" <td>8.02</td>\n",
" <td>3.94</td>\n",
" <td>6.60</td>\n",
" <td>5.59</td>\n",
" <td>8.91</td>\n",
" <td>6.23</td>\n",
" <td>14.73</td>\n",
" <td>15.05</td>\n",
" <td>4.75</td>\n",
" <td>-4.37</td>\n",
" <td>9.12</td>\n",
" <td>7.92</td>\n",
" <td>8.43</td>\n",
" <td>6.68</td>\n",
" <td>3.10</td>\n",
" <td>5.37</td>\n",
" <td>5.58</td>\n",
" <td>6.82</td>\n",
" <td>7.93</td>\n",
" <td>4.63</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201502</th>\n",
" <td>4.44</td>\n",
" <td>4.40</td>\n",
" <td>5.47</td>\n",
" <td>5.87</td>\n",
" <td>9.00</td>\n",
" <td>3.83</td>\n",
" <td>5.43</td>\n",
" <td>4.31</td>\n",
" <td>8.10</td>\n",
" <td>13.34</td>\n",
" <td>8.02</td>\n",
" <td>3.94</td>\n",
" <td>6.60</td>\n",
" <td>5.59</td>\n",
" <td>8.91</td>\n",
" <td>6.23</td>\n",
" <td>14.73</td>\n",
" <td>15.05</td>\n",
" <td>4.75</td>\n",
" <td>-4.37</td>\n",
" <td>9.12</td>\n",
" <td>7.92</td>\n",
" <td>8.43</td>\n",
" <td>6.68</td>\n",
" <td>3.10</td>\n",
" <td>5.37</td>\n",
" <td>5.58</td>\n",
" <td>6.82</td>\n",
" <td>7.93</td>\n",
" <td>4.63</td>\n",
" <td>-0.72</td>\n",
" <td>-2.07</td>\n",
" <td>-8.82</td>\n",
" <td>-2.60</td>\n",
" <td>0.56</td>\n",
" <td>-1.98</td>\n",
" <td>1.23</td>\n",
" <td>0.86</td>\n",
" <td>-3.55</td>\n",
" <td>3.33</td>\n",
" <td>1.17</td>\n",
" <td>-2.27</td>\n",
" <td>-3.63</td>\n",
" <td>-0.49</td>\n",
" <td>-0.43</td>\n",
" <td>-1.27</td>\n",
" <td>-6.96</td>\n",
" <td>-18.67</td>\n",
" <td>-2.52</td>\n",
" <td>-0.28</td>\n",
" <td>-2.20</td>\n",
" <td>-1.52</td>\n",
" <td>-3.12</td>\n",
" <td>-1.73</td>\n",
" <td>-3.62</td>\n",
" <td>0.57</td>\n",
" <td>1.00</td>\n",
" <td>-0.29</td>\n",
" <td>0.11</td>\n",
" <td>-1.77</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201503</th>\n",
" <td>-0.72</td>\n",
" <td>-2.07</td>\n",
" <td>-8.82</td>\n",
" <td>-2.60</td>\n",
" <td>0.56</td>\n",
" <td>-1.98</td>\n",
" <td>1.23</td>\n",
" <td>0.86</td>\n",
" <td>-3.55</td>\n",
" <td>3.33</td>\n",
" <td>1.17</td>\n",
" <td>-2.27</td>\n",
" <td>-3.63</td>\n",
" <td>-0.49</td>\n",
" <td>-0.43</td>\n",
" <td>-1.27</td>\n",
" <td>-6.96</td>\n",
" <td>-18.67</td>\n",
" <td>-2.52</td>\n",
" <td>-0.28</td>\n",
" <td>-2.20</td>\n",
" <td>-1.52</td>\n",
" <td>-3.12</td>\n",
" <td>-1.73</td>\n",
" <td>-3.62</td>\n",
" <td>0.57</td>\n",
" <td>1.00</td>\n",
" <td>-0.29</td>\n",
" <td>0.11</td>\n",
" <td>-1.77</td>\n",
" <td>-0.17</td>\n",
" <td>-0.52</td>\n",
" <td>5.94</td>\n",
" <td>3.75</td>\n",
" <td>-4.11</td>\n",
" <td>-2.41</td>\n",
" <td>-1.53</td>\n",
" <td>-1.39</td>\n",
" <td>1.11</td>\n",
" <td>-5.95</td>\n",
" <td>-3.01</td>\n",
" <td>3.19</td>\n",
" <td>2.44</td>\n",
" <td>1.37</td>\n",
" <td>0.21</td>\n",
" <td>-2.85</td>\n",
" <td>12.62</td>\n",
" <td>10.80</td>\n",
" <td>6.92</td>\n",
" <td>0.30</td>\n",
" <td>3.40</td>\n",
" <td>2.25</td>\n",
" <td>0.10</td>\n",
" <td>-2.65</td>\n",
" <td>-1.14</td>\n",
" <td>-1.23</td>\n",
" <td>-2.88</td>\n",
" <td>0.51</td>\n",
" <td>0.76</td>\n",
" <td>-0.23</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201504</th>\n",
" <td>-0.17</td>\n",
" <td>-0.52</td>\n",
" <td>5.94</td>\n",
" <td>3.75</td>\n",
" <td>-4.11</td>\n",
" <td>-2.41</td>\n",
" <td>-1.53</td>\n",
" <td>-1.39</td>\n",
" <td>1.11</td>\n",
" <td>-5.95</td>\n",
" <td>-3.01</td>\n",
" <td>3.19</td>\n",
" <td>2.44</td>\n",
" <td>1.37</td>\n",
" <td>0.21</td>\n",
" <td>-2.85</td>\n",
" <td>12.62</td>\n",
" <td>10.80</td>\n",
" <td>6.92</td>\n",
" <td>0.30</td>\n",
" <td>3.40</td>\n",
" <td>2.25</td>\n",
" <td>0.10</td>\n",
" <td>-2.65</td>\n",
" <td>-1.14</td>\n",
" <td>-1.23</td>\n",
" <td>-2.88</td>\n",
" <td>0.51</td>\n",
" <td>0.76</td>\n",
" <td>-0.23</td>\n",
" <td>2.03</td>\n",
" <td>2.00</td>\n",
" <td>1.28</td>\n",
" <td>0.71</td>\n",
" <td>1.93</td>\n",
" <td>0.39</td>\n",
" <td>0.04</td>\n",
" <td>4.89</td>\n",
" <td>1.24</td>\n",
" <td>4.37</td>\n",
" <td>1.80</td>\n",
" <td>-3.59</td>\n",
" <td>0.32</td>\n",
" <td>2.91</td>\n",
" <td>1.09</td>\n",
" <td>1.75</td>\n",
" <td>-5.30</td>\n",
" <td>-17.11</td>\n",
" <td>-5.02</td>\n",
" <td>-0.50</td>\n",
" <td>0.81</td>\n",
" <td>-0.12</td>\n",
" <td>4.02</td>\n",
" <td>1.32</td>\n",
" <td>-3.06</td>\n",
" <td>1.44</td>\n",
" <td>0.54</td>\n",
" <td>1.56</td>\n",
" <td>3.09</td>\n",
" <td>0.92</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201505</th>\n",
" <td>2.03</td>\n",
" <td>2.00</td>\n",
" <td>1.28</td>\n",
" <td>0.71</td>\n",
" <td>1.93</td>\n",
" <td>0.39</td>\n",
" <td>0.04</td>\n",
" <td>4.89</td>\n",
" <td>1.24</td>\n",
" <td>4.37</td>\n",
" <td>1.80</td>\n",
" <td>-3.59</td>\n",
" <td>0.32</td>\n",
" <td>2.91</td>\n",
" <td>1.09</td>\n",
" <td>1.75</td>\n",
" <td>-5.30</td>\n",
" <td>-17.11</td>\n",
" <td>-5.02</td>\n",
" <td>-0.50</td>\n",
" <td>0.81</td>\n",
" <td>-0.12</td>\n",
" <td>4.02</td>\n",
" <td>1.32</td>\n",
" <td>-3.06</td>\n",
" <td>1.44</td>\n",
" <td>0.54</td>\n",
" <td>1.56</td>\n",
" <td>3.09</td>\n",
" <td>0.92</td>\n",
" <td>-1.95</td>\n",
" <td>-1.71</td>\n",
" <td>-2.57</td>\n",
" <td>1.30</td>\n",
" <td>-0.84</td>\n",
" <td>-0.11</td>\n",
" <td>4.17</td>\n",
" <td>0.07</td>\n",
" <td>-2.72</td>\n",
" <td>4.09</td>\n",
" <td>0.42</td>\n",
" <td>-5.17</td>\n",
" <td>-1.34</td>\n",
" <td>-3.45</td>\n",
" <td>-2.36</td>\n",
" <td>-2.80</td>\n",
" <td>-6.35</td>\n",
" <td>-23.50</td>\n",
" <td>-3.74</td>\n",
" <td>-5.37</td>\n",
" <td>-0.48</td>\n",
" <td>-1.87</td>\n",
" <td>-4.92</td>\n",
" <td>-2.84</td>\n",
" <td>-3.25</td>\n",
" <td>-2.82</td>\n",
" <td>-0.49</td>\n",
" <td>0.29</td>\n",
" <td>1.34</td>\n",
" <td>-3.59</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201506</th>\n",
" <td>-1.95</td>\n",
" <td>-1.71</td>\n",
" <td>-2.57</td>\n",
" <td>1.30</td>\n",
" <td>-0.84</td>\n",
" <td>-0.11</td>\n",
" <td>4.17</td>\n",
" <td>0.07</td>\n",
" <td>-2.72</td>\n",
" <td>4.09</td>\n",
" <td>0.42</td>\n",
" <td>-5.17</td>\n",
" <td>-1.34</td>\n",
" <td>-3.45</td>\n",
" <td>-2.36</td>\n",
" <td>-2.80</td>\n",
" <td>-6.35</td>\n",
" <td>-23.50</td>\n",
" <td>-3.74</td>\n",
" <td>-5.37</td>\n",
" <td>-0.48</td>\n",
" <td>-1.87</td>\n",
" <td>-4.92</td>\n",
" <td>-2.84</td>\n",
" <td>-3.25</td>\n",
" <td>-2.82</td>\n",
" <td>-0.49</td>\n",
" <td>0.29</td>\n",
" <td>1.34</td>\n",
" <td>-3.59</td>\n",
" <td>4.03</td>\n",
" <td>3.51</td>\n",
" <td>9.59</td>\n",
" <td>6.09</td>\n",
" <td>-2.90</td>\n",
" <td>0.71</td>\n",
" <td>5.96</td>\n",
" <td>3.66</td>\n",
" <td>-4.90</td>\n",
" <td>-0.72</td>\n",
" <td>1.16</td>\n",
" <td>-9.19</td>\n",
" <td>-6.00</td>\n",
" <td>-4.29</td>\n",
" <td>-3.11</td>\n",
" <td>-1.49</td>\n",
" <td>-13.10</td>\n",
" <td>-26.30</td>\n",
" <td>-8.93</td>\n",
" <td>2.61</td>\n",
" <td>1.41</td>\n",
" <td>5.22</td>\n",
" <td>-0.91</td>\n",
" <td>-0.54</td>\n",
" <td>3.27</td>\n",
" <td>-1.32</td>\n",
" <td>5.79</td>\n",
" <td>4.17</td>\n",
" <td>1.97</td>\n",
" <td>3.18</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201507</th>\n",
" <td>4.03</td>\n",
" <td>3.51</td>\n",
" <td>9.59</td>\n",
" <td>6.09</td>\n",
" <td>-2.90</td>\n",
" <td>0.71</td>\n",
" <td>5.96</td>\n",
" <td>3.66</td>\n",
" <td>-4.90</td>\n",
" <td>-0.72</td>\n",
" <td>1.16</td>\n",
" <td>-9.19</td>\n",
" <td>-6.00</td>\n",
" <td>-4.29</td>\n",
" <td>-3.11</td>\n",
" <td>-1.49</td>\n",
" <td>-13.10</td>\n",
" <td>-26.30</td>\n",
" <td>-8.93</td>\n",
" <td>2.61</td>\n",
" <td>1.41</td>\n",
" <td>5.22</td>\n",
" <td>-0.91</td>\n",
" <td>-0.54</td>\n",
" <td>3.27</td>\n",
" <td>-1.32</td>\n",
" <td>5.79</td>\n",
" <td>4.17</td>\n",
" <td>1.97</td>\n",
" <td>3.18</td>\n",
" <td>-4.37</td>\n",
" <td>-3.12</td>\n",
" <td>-4.06</td>\n",
" <td>-7.35</td>\n",
" <td>-8.61</td>\n",
" <td>-6.94</td>\n",
" <td>-3.86</td>\n",
" <td>-8.37</td>\n",
" <td>-7.15</td>\n",
" <td>-3.11</td>\n",
" <td>-2.23</td>\n",
" <td>-4.85</td>\n",
" <td>-3.79</td>\n",
" <td>-8.97</td>\n",
" <td>-6.10</td>\n",
" <td>-5.07</td>\n",
" <td>-1.48</td>\n",
" <td>7.86</td>\n",
" <td>-3.70</td>\n",
" <td>-4.01</td>\n",
" <td>-8.42</td>\n",
" <td>-5.29</td>\n",
" <td>-6.50</td>\n",
" <td>-5.69</td>\n",
" <td>-6.37</td>\n",
" <td>-4.13</td>\n",
" <td>-5.44</td>\n",
" <td>-6.48</td>\n",
" <td>-6.54</td>\n",
" <td>-5.20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201508</th>\n",
" <td>-4.37</td>\n",
" <td>-3.12</td>\n",
" <td>-4.06</td>\n",
" <td>-7.35</td>\n",
" <td>-8.61</td>\n",
" <td>-6.94</td>\n",
" <td>-3.86</td>\n",
" <td>-8.37</td>\n",
" <td>-7.15</td>\n",
" <td>-3.11</td>\n",
" <td>-2.23</td>\n",
" <td>-4.85</td>\n",
" <td>-3.79</td>\n",
" <td>-8.97</td>\n",
" <td>-6.10</td>\n",
" <td>-5.07</td>\n",
" <td>-1.48</td>\n",
" <td>7.86</td>\n",
" <td>-3.70</td>\n",
" <td>-4.01</td>\n",
" <td>-8.42</td>\n",
" <td>-5.29</td>\n",
" <td>-6.50</td>\n",
" <td>-5.69</td>\n",
" <td>-6.37</td>\n",
" <td>-4.13</td>\n",
" <td>-5.44</td>\n",
" <td>-6.48</td>\n",
" <td>-6.54</td>\n",
" <td>-5.20</td>\n",
" <td>-1.19</td>\n",
" <td>2.58</td>\n",
" <td>2.37</td>\n",
" <td>-9.94</td>\n",
" <td>-5.32</td>\n",
" <td>-0.53</td>\n",
" <td>1.18</td>\n",
" <td>-7.28</td>\n",
" <td>-8.38</td>\n",
" <td>-5.92</td>\n",
" <td>-6.49</td>\n",
" <td>-10.47</td>\n",
" <td>-9.10</td>\n",
" <td>-8.80</td>\n",
" <td>-2.53</td>\n",
" <td>-2.56</td>\n",
" <td>-6.07</td>\n",
" <td>-36.74</td>\n",
" <td>-5.63</td>\n",
" <td>-0.56</td>\n",
" <td>-2.63</td>\n",
" <td>-1.47</td>\n",
" <td>-1.72</td>\n",
" <td>-2.66</td>\n",
" <td>-0.71</td>\n",
" <td>-6.04</td>\n",
" <td>-1.75</td>\n",
" <td>0.44</td>\n",
" <td>-3.14</td>\n",
" <td>-1.87</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201509</th>\n",
" <td>-1.19</td>\n",
" <td>2.58</td>\n",
" <td>2.37</td>\n",
" <td>-9.94</td>\n",
" <td>-5.32</td>\n",
" <td>-0.53</td>\n",
" <td>1.18</td>\n",
" <td>-7.28</td>\n",
" <td>-8.38</td>\n",
" <td>-5.92</td>\n",
" <td>-6.49</td>\n",
" <td>-10.47</td>\n",
" <td>-9.10</td>\n",
" <td>-8.80</td>\n",
" <td>-2.53</td>\n",
" <td>-2.56</td>\n",
" <td>-6.07</td>\n",
" <td>-36.74</td>\n",
" <td>-5.63</td>\n",
" <td>-0.56</td>\n",
" <td>-2.63</td>\n",
" <td>-1.47</td>\n",
" <td>-1.72</td>\n",
" <td>-2.66</td>\n",
" <td>-0.71</td>\n",
" <td>-6.04</td>\n",
" <td>-1.75</td>\n",
" <td>0.44</td>\n",
" <td>-3.14</td>\n",
" <td>-1.87</td>\n",
" <td>5.81</td>\n",
" <td>8.06</td>\n",
" <td>10.90</td>\n",
" <td>14.61</td>\n",
" <td>12.21</td>\n",
" <td>5.81</td>\n",
" <td>0.98</td>\n",
" <td>7.74</td>\n",
" <td>16.62</td>\n",
" <td>7.96</td>\n",
" <td>5.44</td>\n",
" <td>7.14</td>\n",
" <td>8.69</td>\n",
" <td>7.98</td>\n",
" <td>6.04</td>\n",
" <td>9.30</td>\n",
" <td>8.82</td>\n",
" <td>-30.98</td>\n",
" <td>12.52</td>\n",
" <td>2.07</td>\n",
" <td>8.84</td>\n",
" <td>11.26</td>\n",
" <td>8.16</td>\n",
" <td>10.19</td>\n",
" <td>6.48</td>\n",
" <td>5.07</td>\n",
" <td>4.56</td>\n",
" <td>5.05</td>\n",
" <td>5.90</td>\n",
" <td>6.98</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201510</th>\n",
" <td>5.81</td>\n",
" <td>8.06</td>\n",
" <td>10.90</td>\n",
" <td>14.61</td>\n",
" <td>12.21</td>\n",
" <td>5.81</td>\n",
" <td>0.98</td>\n",
" <td>7.74</td>\n",
" <td>16.62</td>\n",
" <td>7.96</td>\n",
" <td>5.44</td>\n",
" <td>7.14</td>\n",
" <td>8.69</td>\n",
" <td>7.98</td>\n",
" <td>6.04</td>\n",
" <td>9.30</td>\n",
" <td>8.82</td>\n",
" <td>-30.98</td>\n",
" <td>12.52</td>\n",
" <td>2.07</td>\n",
" <td>8.84</td>\n",
" <td>11.26</td>\n",
" <td>8.16</td>\n",
" <td>10.19</td>\n",
" <td>6.48</td>\n",
" <td>5.07</td>\n",
" <td>4.56</td>\n",
" <td>5.05</td>\n",
" <td>5.90</td>\n",
" <td>6.98</td>\n",
" <td>0.11</td>\n",
" <td>-0.71</td>\n",
" <td>-3.00</td>\n",
" <td>-0.41</td>\n",
" <td>-1.17</td>\n",
" <td>-1.10</td>\n",
" <td>-1.08</td>\n",
" <td>0.71</td>\n",
" <td>1.68</td>\n",
" <td>-2.59</td>\n",
" <td>4.65</td>\n",
" <td>-0.94</td>\n",
" <td>2.22</td>\n",
" <td>1.52</td>\n",
" <td>1.94</td>\n",
" <td>-0.41</td>\n",
" <td>-6.06</td>\n",
" <td>10.12</td>\n",
" <td>1.07</td>\n",
" <td>-3.45</td>\n",
" <td>-1.92</td>\n",
" <td>1.99</td>\n",
" <td>0.12</td>\n",
" <td>-0.02</td>\n",
" <td>-1.10</td>\n",
" <td>2.67</td>\n",
" <td>0.61</td>\n",
" <td>-1.01</td>\n",
" <td>2.16</td>\n",
" <td>0.05</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201511</th>\n",
" <td>0.11</td>\n",
" <td>-0.71</td>\n",
" <td>-3.00</td>\n",
" <td>-0.41</td>\n",
" <td>-1.17</td>\n",
" <td>-1.10</td>\n",
" <td>-1.08</td>\n",
" <td>0.71</td>\n",
" <td>1.68</td>\n",
" <td>-2.59</td>\n",
" <td>4.65</td>\n",
" <td>-0.94</td>\n",
" <td>2.22</td>\n",
" <td>1.52</td>\n",
" <td>1.94</td>\n",
" <td>-0.41</td>\n",
" <td>-6.06</td>\n",
" <td>10.12</td>\n",
" <td>1.07</td>\n",
" <td>-3.45</td>\n",
" <td>-1.92</td>\n",
" <td>1.99</td>\n",
" <td>0.12</td>\n",
" <td>-0.02</td>\n",
" <td>-1.10</td>\n",
" <td>2.67</td>\n",
" <td>0.61</td>\n",
" <td>-1.01</td>\n",
" <td>2.16</td>\n",
" <td>0.05</td>\n",
" <td>1.96</td>\n",
" <td>0.30</td>\n",
" <td>1.59</td>\n",
" <td>-1.70</td>\n",
" <td>-6.18</td>\n",
" <td>1.86</td>\n",
" <td>-4.38</td>\n",
" <td>0.39</td>\n",
" <td>-4.82</td>\n",
" <td>-2.65</td>\n",
" <td>-5.25</td>\n",
" <td>-3.75</td>\n",
" <td>-6.10</td>\n",
" <td>-0.37</td>\n",
" <td>-4.14</td>\n",
" <td>-1.81</td>\n",
" <td>-6.47</td>\n",
" <td>-7.35</td>\n",
" <td>-9.74</td>\n",
" <td>-2.37</td>\n",
" <td>-3.03</td>\n",
" <td>-1.19</td>\n",
" <td>-4.64</td>\n",
" <td>-3.75</td>\n",
" <td>-5.02</td>\n",
" <td>-1.88</td>\n",
" <td>0.82</td>\n",
" <td>-0.95</td>\n",
" <td>-2.92</td>\n",
" <td>0.25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201512</th>\n",
" <td>1.96</td>\n",
" <td>0.30</td>\n",
" <td>1.59</td>\n",
" <td>-1.70</td>\n",
" <td>-6.18</td>\n",
" <td>1.86</td>\n",
" <td>-4.38</td>\n",
" <td>0.39</td>\n",
" <td>-4.82</td>\n",
" <td>-2.65</td>\n",
" <td>-5.25</td>\n",
" <td>-3.75</td>\n",
" <td>-6.10</td>\n",
" <td>-0.37</td>\n",
" <td>-4.14</td>\n",
" <td>-1.81</td>\n",
" <td>-6.47</td>\n",
" <td>-7.35</td>\n",
" <td>-9.74</td>\n",
" <td>-2.37</td>\n",
" <td>-3.03</td>\n",
" <td>-1.19</td>\n",
" <td>-4.64</td>\n",
" <td>-3.75</td>\n",
" <td>-5.02</td>\n",
" <td>-1.88</td>\n",
" <td>0.82</td>\n",
" <td>-0.95</td>\n",
" <td>-2.92</td>\n",
" <td>0.25</td>\n",
" <td>-1.67</td>\n",
" <td>-0.23</td>\n",
" <td>4.28</td>\n",
" <td>-8.15</td>\n",
" <td>-5.28</td>\n",
" <td>0.16</td>\n",
" <td>1.52</td>\n",
" <td>-9.43</td>\n",
" <td>-11.10</td>\n",
" <td>-5.33</td>\n",
" <td>-8.63</td>\n",
" <td>-9.69</td>\n",
" <td>-4.79</td>\n",
" <td>-8.21</td>\n",
" <td>-13.24</td>\n",
" <td>-9.69</td>\n",
" <td>-5.35</td>\n",
" <td>-3.32</td>\n",
" <td>-4.64</td>\n",
" <td>4.61</td>\n",
" <td>-0.36</td>\n",
" <td>-5.09</td>\n",
" <td>-7.95</td>\n",
" <td>-5.27</td>\n",
" <td>-8.53</td>\n",
" <td>-8.68</td>\n",
" <td>-4.45</td>\n",
" <td>-0.94</td>\n",
" <td>-9.63</td>\n",
" <td>-3.20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201601</th>\n",
" <td>-1.67</td>\n",
" <td>-0.23</td>\n",
" <td>4.28</td>\n",
" <td>-8.15</td>\n",
" <td>-5.28</td>\n",
" <td>0.16</td>\n",
" <td>1.52</td>\n",
" <td>-9.43</td>\n",
" <td>-11.10</td>\n",
" <td>-5.33</td>\n",
" <td>-8.63</td>\n",
" <td>-9.69</td>\n",
" <td>-4.79</td>\n",
" <td>-8.21</td>\n",
" <td>-13.24</td>\n",
" <td>-9.69</td>\n",
" <td>-5.35</td>\n",
" <td>-3.32</td>\n",
" <td>-4.64</td>\n",
" <td>4.61</td>\n",
" <td>-0.36</td>\n",
" <td>-5.09</td>\n",
" <td>-7.95</td>\n",
" <td>-5.27</td>\n",
" <td>-8.53</td>\n",
" <td>-8.68</td>\n",
" <td>-4.45</td>\n",
" <td>-0.94</td>\n",
" <td>-9.63</td>\n",
" <td>-3.20</td>\n",
" <td>0.95</td>\n",
" <td>-2.34</td>\n",
" <td>0.93</td>\n",
" <td>4.25</td>\n",
" <td>-0.96</td>\n",
" <td>0.34</td>\n",
" <td>0.81</td>\n",
" <td>-1.09</td>\n",
" <td>6.79</td>\n",
" <td>0.63</td>\n",
" <td>2.09</td>\n",
" <td>8.19</td>\n",
" <td>5.35</td>\n",
" <td>3.64</td>\n",
" <td>4.05</td>\n",
" <td>3.49</td>\n",
" <td>12.21</td>\n",
" <td>6.26</td>\n",
" <td>-3.00</td>\n",
" <td>1.70</td>\n",
" <td>1.15</td>\n",
" <td>-2.45</td>\n",
" <td>1.45</td>\n",
" <td>2.99</td>\n",
" <td>6.89</td>\n",
" <td>3.85</td>\n",
" <td>-0.36</td>\n",
" <td>1.03</td>\n",
" <td>-2.85</td>\n",
" <td>2.71</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201602</th>\n",
" <td>0.95</td>\n",
" <td>-2.34</td>\n",
" <td>0.93</td>\n",
" <td>4.25</td>\n",
" <td>-0.96</td>\n",
" <td>0.34</td>\n",
" <td>0.81</td>\n",
" <td>-1.09</td>\n",
" <td>6.79</td>\n",
" <td>0.63</td>\n",
" <td>2.09</td>\n",
" <td>8.19</td>\n",
" <td>5.35</td>\n",
" <td>3.64</td>\n",
" <td>4.05</td>\n",
" <td>3.49</td>\n",
" <td>12.21</td>\n",
" <td>6.26</td>\n",
" <td>-3.00</td>\n",
" <td>1.70</td>\n",
" <td>1.15</td>\n",
" <td>-2.45</td>\n",
" <td>1.45</td>\n",
" <td>2.99</td>\n",
" <td>6.89</td>\n",
" <td>3.85</td>\n",
" <td>-0.36</td>\n",
" <td>1.03</td>\n",
" <td>-2.85</td>\n",
" <td>2.71</td>\n",
" <td>4.69</td>\n",
" <td>5.61</td>\n",
" <td>5.04</td>\n",
" <td>8.61</td>\n",
" <td>6.88</td>\n",
" <td>4.65</td>\n",
" <td>2.30</td>\n",
" <td>2.90</td>\n",
" <td>8.33</td>\n",
" <td>3.58</td>\n",
" <td>11.41</td>\n",
" <td>17.46</td>\n",
" <td>9.68</td>\n",
" <td>9.03</td>\n",
" <td>10.57</td>\n",
" <td>4.05</td>\n",
" <td>13.30</td>\n",
" <td>25.45</td>\n",
" <td>10.83</td>\n",
" <td>7.90</td>\n",
" <td>6.00</td>\n",
" <td>7.76</td>\n",
" <td>8.86</td>\n",
" <td>8.18</td>\n",
" <td>6.86</td>\n",
" <td>6.18</td>\n",
" <td>5.99</td>\n",
" <td>5.36</td>\n",
" <td>6.65</td>\n",
" <td>6.68</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201603</th>\n",
" <td>4.69</td>\n",
" <td>5.61</td>\n",
" <td>5.04</td>\n",
" <td>8.61</td>\n",
" <td>6.88</td>\n",
" <td>4.65</td>\n",
" <td>2.30</td>\n",
" <td>2.90</td>\n",
" <td>8.33</td>\n",
" <td>3.58</td>\n",
" <td>11.41</td>\n",
" <td>17.46</td>\n",
" <td>9.68</td>\n",
" <td>9.03</td>\n",
" <td>10.57</td>\n",
" <td>4.05</td>\n",
" <td>13.30</td>\n",
" <td>25.45</td>\n",
" <td>10.83</td>\n",
" <td>7.90</td>\n",
" <td>6.00</td>\n",
" <td>7.76</td>\n",
" <td>8.86</td>\n",
" <td>8.18</td>\n",
" <td>6.86</td>\n",
" <td>6.18</td>\n",
" <td>5.99</td>\n",
" <td>5.36</td>\n",
" <td>6.65</td>\n",
" <td>6.68</td>\n",
" <td>0.63</td>\n",
" <td>0.31</td>\n",
" <td>-0.25</td>\n",
" <td>-6.30</td>\n",
" <td>1.82</td>\n",
" <td>-0.42</td>\n",
" <td>-2.27</td>\n",
" <td>3.55</td>\n",
" <td>3.77</td>\n",
" <td>1.55</td>\n",
" <td>0.49</td>\n",
" <td>9.53</td>\n",
" <td>3.49</td>\n",
" <td>2.33</td>\n",
" <td>1.59</td>\n",
" <td>5.10</td>\n",
" <td>15.76</td>\n",
" <td>29.72</td>\n",
" <td>9.07</td>\n",
" <td>-0.79</td>\n",
" <td>0.59</td>\n",
" <td>-2.55</td>\n",
" <td>-5.46</td>\n",
" <td>0.80</td>\n",
" <td>-1.08</td>\n",
" <td>0.49</td>\n",
" <td>-0.38</td>\n",
" <td>-2.38</td>\n",
" <td>3.96</td>\n",
" <td>0.67</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201604</th>\n",
" <td>0.63</td>\n",
" <td>0.31</td>\n",
" <td>-0.25</td>\n",
" <td>-6.30</td>\n",
" <td>1.82</td>\n",
" <td>-0.42</td>\n",
" <td>-2.27</td>\n",
" <td>3.55</td>\n",
" <td>3.77</td>\n",
" <td>1.55</td>\n",
" <td>0.49</td>\n",
" <td>9.53</td>\n",
" <td>3.49</td>\n",
" <td>2.33</td>\n",
" <td>1.59</td>\n",
" <td>5.10</td>\n",
" <td>15.76</td>\n",
" <td>29.72</td>\n",
" <td>9.07</td>\n",
" <td>-0.79</td>\n",
" <td>0.59</td>\n",
" <td>-2.55</td>\n",
" <td>-5.46</td>\n",
" <td>0.80</td>\n",
" <td>-1.08</td>\n",
" <td>0.49</td>\n",
" <td>-0.38</td>\n",
" <td>-2.38</td>\n",
" <td>3.96</td>\n",
" <td>0.67</td>\n",
" <td>2.06</td>\n",
" <td>-0.91</td>\n",
" <td>0.83</td>\n",
" <td>5.42</td>\n",
" <td>-0.53</td>\n",
" <td>-0.09</td>\n",
" <td>-4.96</td>\n",
" <td>2.46</td>\n",
" <td>-1.42</td>\n",
" <td>-1.70</td>\n",
" <td>3.44</td>\n",
" <td>-8.04</td>\n",
" <td>0.14</td>\n",
" <td>-1.00</td>\n",
" <td>-2.50</td>\n",
" <td>-1.81</td>\n",
" <td>-5.12</td>\n",
" <td>1.54</td>\n",
" <td>-0.94</td>\n",
" <td>2.23</td>\n",
" <td>0.30</td>\n",
" <td>4.67</td>\n",
" <td>5.64</td>\n",
" <td>1.79</td>\n",
" <td>-2.18</td>\n",
" <td>1.78</td>\n",
" <td>1.19</td>\n",
" <td>-1.48</td>\n",
" <td>2.15</td>\n",
" <td>-2.02</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201605</th>\n",
" <td>2.06</td>\n",
" <td>-0.91</td>\n",
" <td>0.83</td>\n",
" <td>5.42</td>\n",
" <td>-0.53</td>\n",
" <td>-0.09</td>\n",
" <td>-4.96</td>\n",
" <td>2.46</td>\n",
" <td>-1.42</td>\n",
" <td>-1.70</td>\n",
" <td>3.44</td>\n",
" <td>-8.04</td>\n",
" <td>0.14</td>\n",
" <td>-1.00</td>\n",
" <td>-2.50</td>\n",
" <td>-1.81</td>\n",
" <td>-5.12</td>\n",
" <td>1.54</td>\n",
" <td>-0.94</td>\n",
" <td>2.23</td>\n",
" <td>0.30</td>\n",
" <td>4.67</td>\n",
" <td>5.64</td>\n",
" <td>1.79</td>\n",
" <td>-2.18</td>\n",
" <td>1.78</td>\n",
" <td>1.19</td>\n",
" <td>-1.48</td>\n",
" <td>2.15</td>\n",
" <td>-2.02</td>\n",
" <td>4.75</td>\n",
" <td>5.31</td>\n",
" <td>6.87</td>\n",
" <td>-4.43</td>\n",
" <td>-0.34</td>\n",
" <td>3.16</td>\n",
" <td>1.63</td>\n",
" <td>0.11</td>\n",
" <td>-1.14</td>\n",
" <td>-4.67</td>\n",
" <td>-1.28</td>\n",
" <td>2.10</td>\n",
" <td>-0.84</td>\n",
" <td>-0.21</td>\n",
" <td>-7.00</td>\n",
" <td>0.77</td>\n",
" <td>7.97</td>\n",
" <td>5.22</td>\n",
" <td>2.64</td>\n",
" <td>7.35</td>\n",
" <td>3.10</td>\n",
" <td>-2.12</td>\n",
" <td>-1.63</td>\n",
" <td>2.06</td>\n",
" <td>-2.53</td>\n",
" <td>1.81</td>\n",
" <td>0.71</td>\n",
" <td>1.16</td>\n",
" <td>-5.30</td>\n",
" <td>3.61</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201606</th>\n",
" <td>4.75</td>\n",
" <td>5.31</td>\n",
" <td>6.87</td>\n",
" <td>-4.43</td>\n",
" <td>-0.34</td>\n",
" <td>3.16</td>\n",
" <td>1.63</td>\n",
" <td>0.11</td>\n",
" <td>-1.14</td>\n",
" <td>-4.67</td>\n",
" <td>-1.28</td>\n",
" <td>2.10</td>\n",
" <td>-0.84</td>\n",
" <td>-0.21</td>\n",
" <td>-7.00</td>\n",
" <td>0.77</td>\n",
" <td>7.97</td>\n",
" <td>5.22</td>\n",
" <td>2.64</td>\n",
" <td>7.35</td>\n",
" <td>3.10</td>\n",
" <td>-2.12</td>\n",
" <td>-1.63</td>\n",
" <td>2.06</td>\n",
" <td>-2.53</td>\n",
" <td>1.81</td>\n",
" <td>0.71</td>\n",
" <td>1.16</td>\n",
" <td>-5.30</td>\n",
" <td>3.61</td>\n",
" <td>-0.51</td>\n",
" <td>1.82</td>\n",
" <td>-2.79</td>\n",
" <td>6.15</td>\n",
" <td>7.38</td>\n",
" <td>2.58</td>\n",
" <td>1.62</td>\n",
" <td>6.00</td>\n",
" <td>4.29</td>\n",
" <td>8.39</td>\n",
" <td>5.65</td>\n",
" <td>13.90</td>\n",
" <td>6.51</td>\n",
" <td>5.35</td>\n",
" <td>8.83</td>\n",
" <td>4.11</td>\n",
" <td>7.48</td>\n",
" <td>20.92</td>\n",
" <td>-2.90</td>\n",
" <td>-0.24</td>\n",
" <td>2.27</td>\n",
" <td>7.33</td>\n",
" <td>8.20</td>\n",
" <td>2.52</td>\n",
" <td>5.39</td>\n",
" <td>3.65</td>\n",
" <td>3.78</td>\n",
" <td>2.19</td>\n",
" <td>4.04</td>\n",
" <td>-0.21</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201607</th>\n",
" <td>-0.51</td>\n",
" <td>1.82</td>\n",
" <td>-2.79</td>\n",
" <td>6.15</td>\n",
" <td>7.38</td>\n",
" <td>2.58</td>\n",
" <td>1.62</td>\n",
" <td>6.00</td>\n",
" <td>4.29</td>\n",
" <td>8.39</td>\n",
" <td>5.65</td>\n",
" <td>13.90</td>\n",
" <td>6.51</td>\n",
" <td>5.35</td>\n",
" <td>8.83</td>\n",
" <td>4.11</td>\n",
" <td>7.48</td>\n",
" <td>20.92</td>\n",
" <td>-2.90</td>\n",
" <td>-0.24</td>\n",
" <td>2.27</td>\n",
" <td>7.33</td>\n",
" <td>8.20</td>\n",
" <td>2.52</td>\n",
" <td>5.39</td>\n",
" <td>3.65</td>\n",
" <td>3.78</td>\n",
" <td>2.19</td>\n",
" <td>4.04</td>\n",
" <td>-0.21</td>\n",
" <td>-0.52</td>\n",
" <td>-0.90</td>\n",
" <td>-1.22</td>\n",
" <td>0.94</td>\n",
" <td>0.29</td>\n",
" <td>1.24</td>\n",
" <td>1.37</td>\n",
" <td>-3.24</td>\n",
" <td>2.48</td>\n",
" <td>1.03</td>\n",
" <td>0.80</td>\n",
" <td>-7.10</td>\n",
" <td>3.83</td>\n",
" <td>1.34</td>\n",
" <td>-0.32</td>\n",
" <td>0.29</td>\n",
" <td>-9.79</td>\n",
" <td>-4.54</td>\n",
" <td>1.39</td>\n",
" <td>-3.94</td>\n",
" <td>-3.56</td>\n",
" <td>1.19</td>\n",
" <td>2.38</td>\n",
" <td>2.46</td>\n",
" <td>1.09</td>\n",
" <td>-1.03</td>\n",
" <td>-1.69</td>\n",
" <td>-0.24</td>\n",
" <td>4.88</td>\n",
" <td>2.24</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201608</th>\n",
" <td>-0.52</td>\n",
" <td>-0.90</td>\n",
" <td>-1.22</td>\n",
" <td>0.94</td>\n",
" <td>0.29</td>\n",
" <td>1.24</td>\n",
" <td>1.37</td>\n",
" <td>-3.24</td>\n",
" <td>2.48</td>\n",
" <td>1.03</td>\n",
" <td>0.80</td>\n",
" <td>-7.10</td>\n",
" <td>3.83</td>\n",
" <td>1.34</td>\n",
" <td>-0.32</td>\n",
" <td>0.29</td>\n",
" <td>-9.79</td>\n",
" <td>-4.54</td>\n",
" <td>1.39</td>\n",
" <td>-3.94</td>\n",
" <td>-3.56</td>\n",
" <td>1.19</td>\n",
" <td>2.38</td>\n",
" <td>2.46</td>\n",
" <td>1.09</td>\n",
" <td>-1.03</td>\n",
" <td>-1.69</td>\n",
" <td>-0.24</td>\n",
" <td>4.88</td>\n",
" <td>2.24</td>\n",
" <td>-2.92</td>\n",
" <td>1.63</td>\n",
" <td>-2.78</td>\n",
" <td>4.62</td>\n",
" <td>-3.95</td>\n",
" <td>0.00</td>\n",
" <td>-6.92</td>\n",
" <td>0.35</td>\n",
" <td>-1.76</td>\n",
" <td>-4.87</td>\n",
" <td>-2.42</td>\n",
" <td>1.91</td>\n",
" <td>2.54</td>\n",
" <td>0.98</td>\n",
" <td>-0.25</td>\n",
" <td>-0.61</td>\n",
" <td>2.14</td>\n",
" <td>7.66</td>\n",
" <td>2.92</td>\n",
" <td>1.73</td>\n",
" <td>0.52</td>\n",
" <td>0.82</td>\n",
" <td>4.33</td>\n",
" <td>-0.64</td>\n",
" <td>2.86</td>\n",
" <td>-2.56</td>\n",
" <td>-0.18</td>\n",
" <td>-2.25</td>\n",
" <td>-1.45</td>\n",
" <td>-3.48</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201609</th>\n",
" <td>-2.92</td>\n",
" <td>1.63</td>\n",
" <td>-2.78</td>\n",
" <td>4.62</td>\n",
" <td>-3.95</td>\n",
" <td>0.00</td>\n",
" <td>-6.92</td>\n",
" <td>0.35</td>\n",
" <td>-1.76</td>\n",
" <td>-4.87</td>\n",
" <td>-2.42</td>\n",
" <td>1.91</td>\n",
" <td>2.54</td>\n",
" <td>0.98</td>\n",
" <td>-0.25</td>\n",
" <td>-0.61</td>\n",
" <td>2.14</td>\n",
" <td>7.66</td>\n",
" <td>2.92</td>\n",
" <td>1.73</td>\n",
" <td>0.52</td>\n",
" <td>0.82</td>\n",
" <td>4.33</td>\n",
" <td>-0.64</td>\n",
" <td>2.86</td>\n",
" <td>-2.56</td>\n",
" <td>-0.18</td>\n",
" <td>-2.25</td>\n",
" <td>-1.45</td>\n",
" <td>-3.48</td>\n",
" <td>-0.33</td>\n",
" <td>-1.65</td>\n",
" <td>4.59</td>\n",
" <td>5.59</td>\n",
" <td>-10.28</td>\n",
" <td>-2.96</td>\n",
" <td>-5.76</td>\n",
" <td>-7.45</td>\n",
" <td>-1.95</td>\n",
" <td>-4.17</td>\n",
" <td>-3.93</td>\n",
" <td>-3.14</td>\n",
" <td>-4.10</td>\n",
" <td>-4.99</td>\n",
" <td>-3.29</td>\n",
" <td>2.21</td>\n",
" <td>0.78</td>\n",
" <td>-8.69</td>\n",
" <td>-2.92</td>\n",
" <td>-0.63</td>\n",
" <td>-2.85</td>\n",
" <td>-0.55</td>\n",
" <td>-2.24</td>\n",
" <td>-5.49</td>\n",
" <td>-0.64</td>\n",
" <td>-8.18</td>\n",
" <td>-3.59</td>\n",
" <td>-1.96</td>\n",
" <td>1.40</td>\n",
" <td>-0.53</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201610</th>\n",
" <td>-0.33</td>\n",
" <td>-1.65</td>\n",
" <td>4.59</td>\n",
" <td>5.59</td>\n",
" <td>-10.28</td>\n",
" <td>-2.96</td>\n",
" <td>-5.76</td>\n",
" <td>-7.45</td>\n",
" <td>-1.95</td>\n",
" <td>-4.17</td>\n",
" <td>-3.93</td>\n",
" <td>-3.14</td>\n",
" <td>-4.10</td>\n",
" <td>-4.99</td>\n",
" <td>-3.29</td>\n",
" <td>2.21</td>\n",
" <td>0.78</td>\n",
" <td>-8.69</td>\n",
" <td>-2.92</td>\n",
" <td>-0.63</td>\n",
" <td>-2.85</td>\n",
" <td>-0.55</td>\n",
" <td>-2.24</td>\n",
" <td>-5.49</td>\n",
" <td>-0.64</td>\n",
" <td>-8.18</td>\n",
" <td>-3.59</td>\n",
" <td>-1.96</td>\n",
" <td>1.40</td>\n",
" <td>-0.53</td>\n",
" <td>-4.41</td>\n",
" <td>-5.76</td>\n",
" <td>-5.12</td>\n",
" <td>3.87</td>\n",
" <td>8.15</td>\n",
" <td>-4.18</td>\n",
" <td>1.80</td>\n",
" <td>1.37</td>\n",
" <td>7.55</td>\n",
" <td>1.58</td>\n",
" <td>9.77</td>\n",
" <td>21.01</td>\n",
" <td>12.44</td>\n",
" <td>8.57</td>\n",
" <td>6.89</td>\n",
" <td>8.79</td>\n",
" <td>11.59</td>\n",
" <td>20.78</td>\n",
" <td>9.52</td>\n",
" <td>-2.85</td>\n",
" <td>6.25</td>\n",
" <td>-0.01</td>\n",
" <td>2.39</td>\n",
" <td>4.21</td>\n",
" <td>12.75</td>\n",
" <td>9.29</td>\n",
" <td>2.99</td>\n",
" <td>8.47</td>\n",
" <td>12.84</td>\n",
" <td>8.29</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201611</th>\n",
" <td>-4.41</td>\n",
" <td>-5.76</td>\n",
" <td>-5.12</td>\n",
" <td>3.87</td>\n",
" <td>8.15</td>\n",
" <td>-4.18</td>\n",
" <td>1.80</td>\n",
" <td>1.37</td>\n",
" <td>7.55</td>\n",
" <td>1.58</td>\n",
" <td>9.77</td>\n",
" <td>21.01</td>\n",
" <td>12.44</td>\n",
" <td>8.57</td>\n",
" <td>6.89</td>\n",
" <td>8.79</td>\n",
" <td>11.59</td>\n",
" <td>20.78</td>\n",
" <td>9.52</td>\n",
" <td>-2.85</td>\n",
" <td>6.25</td>\n",
" <td>-0.01</td>\n",
" <td>2.39</td>\n",
" <td>4.21</td>\n",
" <td>12.75</td>\n",
" <td>9.29</td>\n",
" <td>2.99</td>\n",
" <td>8.47</td>\n",
" <td>12.84</td>\n",
" <td>8.29</td>\n",
" <td>4.43</td>\n",
" <td>3.00</td>\n",
" <td>5.39</td>\n",
" <td>-3.36</td>\n",
" <td>1.98</td>\n",
" <td>1.43</td>\n",
" <td>-0.44</td>\n",
" <td>0.82</td>\n",
" <td>0.32</td>\n",
" <td>-1.27</td>\n",
" <td>0.16</td>\n",
" <td>-2.14</td>\n",
" <td>-0.15</td>\n",
" <td>-0.40</td>\n",
" <td>4.16</td>\n",
" <td>1.40</td>\n",
" <td>-1.80</td>\n",
" <td>-9.68</td>\n",
" <td>2.17</td>\n",
" <td>3.61</td>\n",
" <td>4.65</td>\n",
" <td>-0.19</td>\n",
" <td>2.07</td>\n",
" <td>1.86</td>\n",
" <td>0.84</td>\n",
" <td>2.34</td>\n",
" <td>-0.98</td>\n",
" <td>0.58</td>\n",
" <td>3.80</td>\n",
" <td>2.57</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201612</th>\n",
" <td>4.43</td>\n",
" <td>3.00</td>\n",
" <td>5.39</td>\n",
" <td>-3.36</td>\n",
" <td>1.98</td>\n",
" <td>1.43</td>\n",
" <td>-0.44</td>\n",
" <td>0.82</td>\n",
" <td>0.32</td>\n",
" <td>-1.27</td>\n",
" <td>0.16</td>\n",
" <td>-2.14</td>\n",
" <td>-0.15</td>\n",
" <td>-0.40</td>\n",
" <td>4.16</td>\n",
" <td>1.40</td>\n",
" <td>-1.80</td>\n",
" <td>-9.68</td>\n",
" <td>2.17</td>\n",
" <td>3.61</td>\n",
" <td>4.65</td>\n",
" <td>-0.19</td>\n",
" <td>2.07</td>\n",
" <td>1.86</td>\n",
" <td>0.84</td>\n",
" <td>2.34</td>\n",
" <td>-0.98</td>\n",
" <td>0.58</td>\n",
" <td>3.80</td>\n",
" <td>2.57</td>\n",
" <td>0.95</td>\n",
" <td>-1.02</td>\n",
" <td>5.61</td>\n",
" <td>4.84</td>\n",
" <td>1.60</td>\n",
" <td>2.72</td>\n",
" <td>-0.01</td>\n",
" <td>2.17</td>\n",
" <td>3.79</td>\n",
" <td>6.90</td>\n",
" <td>3.85</td>\n",
" <td>3.60</td>\n",
" <td>4.64</td>\n",
" <td>4.35</td>\n",
" <td>5.18</td>\n",
" <td>1.95</td>\n",
" <td>12.37</td>\n",
" <td>-5.36</td>\n",
" <td>-4.37</td>\n",
" <td>1.05</td>\n",
" <td>3.36</td>\n",
" <td>5.45</td>\n",
" <td>3.20</td>\n",
" <td>2.28</td>\n",
" <td>1.70</td>\n",
" <td>1.69</td>\n",
" <td>0.93</td>\n",
" <td>0.71</td>\n",
" <td>0.56</td>\n",
" <td>-0.87</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>685 rows × 60 columns</p>\n",
"</div>"
],
"text/plain": [
" Food Beer Smoke Games ... Rtail.lead Meals.lead Fin.lead Other.lead\n",
"yyyymm ... \n",
"195912 2.01 0.35 -3.02 1.64 ... -6.09 -10.08 -4.68 -3.98\n",
"196001 -4.49 -5.71 -2.05 1.21 ... 4.00 1.81 -0.98 6.32\n",
"196002 3.35 -2.14 2.27 4.23 ... -0.13 -3.88 0.05 -2.43\n",
"196003 -1.67 -2.94 -0.18 -0.65 ... -0.53 8.86 -0.64 0.55\n",
"196004 1.17 -2.16 1.35 6.46 ... 3.11 0.80 -0.45 1.02\n",
"196005 8.20 -0.52 2.44 7.28 ... 3.41 1.03 3.72 6.41\n",
"196006 5.39 0.47 4.73 2.24 ... -2.99 -1.25 0.09 -5.95\n",
"196007 -2.11 -0.79 4.60 -4.72 ... 2.85 2.05 3.47 3.48\n",
"196008 4.57 3.24 5.20 7.16 ... -8.57 -1.90 -5.78 -4.21\n",
"196009 -3.88 -5.00 -2.09 -2.33 ... 0.31 -4.54 -0.40 0.38\n",
"196010 1.02 0.54 3.87 0.11 ... 6.50 4.40 7.71 4.01\n",
"196011 9.46 6.57 5.44 13.91 ... 2.05 2.08 5.56 3.80\n",
"196012 4.51 -0.31 3.54 7.77 ... 2.28 4.08 7.12 8.23\n",
"196101 4.70 5.23 8.77 0.56 ... 4.82 8.23 7.00 6.00\n",
"196102 4.21 8.16 5.41 22.33 ... 5.76 4.06 4.34 7.08\n",
"196103 4.64 2.55 5.60 7.18 ... 0.22 4.23 1.38 -3.67\n",
"196104 -1.39 1.40 -0.23 -2.21 ... 4.31 -1.90 4.00 3.32\n",
"196105 4.20 5.38 3.39 -3.91 ... 0.80 -5.63 -2.88 0.37\n",
"196106 -2.17 -3.12 3.97 -5.87 ... 2.45 2.69 3.35 5.37\n",
"196107 2.72 0.88 5.95 -1.21 ... 3.03 0.46 8.65 1.64\n",
"196108 4.92 3.20 7.74 0.89 ... 0.66 -6.21 -0.40 3.14\n",
"196109 -0.62 -1.48 -0.07 1.24 ... 9.35 0.71 2.02 0.39\n",
"196110 3.73 -0.84 7.05 -5.26 ... 4.90 1.08 7.22 1.69\n",
"196111 5.28 4.47 8.03 0.25 ... -0.63 -2.21 -4.44 -0.77\n",
"196112 -3.69 1.41 -6.12 1.97 ... -9.56 -3.90 -4.99 -3.62\n",
"196201 -6.67 -3.45 -4.28 -13.23 ... 1.58 -0.59 3.59 4.20\n",
"196202 -0.25 0.28 0.68 -2.02 ... 0.90 -4.07 -2.13 -1.83\n",
"196203 0.98 -0.34 -6.67 -5.34 ... -4.61 -9.09 -7.69 -2.12\n",
"196204 -4.59 -3.59 -12.99 -11.04 ... -9.09 -7.46 -10.02 -11.83\n",
"196205 -11.25 -9.05 -14.14 -11.39 ... -10.43 -12.90 -11.01 -14.25\n",
"... ... ... ... ... ... ... ... ... ...\n",
"201407 -5.83 -2.92 -3.48 -3.70 ... 5.71 3.32 3.81 7.19\n",
"201408 6.38 5.46 5.08 -1.80 ... -1.50 -0.60 -0.59 0.16\n",
"201409 -0.53 0.83 2.15 -4.38 ... 3.32 1.28 3.87 1.58\n",
"201410 1.70 3.28 6.13 0.58 ... 8.91 5.57 1.93 4.55\n",
"201411 5.68 4.35 0.76 -0.40 ... 2.25 -0.43 2.08 0.17\n",
"201412 -2.48 -4.30 -3.11 -4.60 ... -0.29 0.66 -7.61 -4.11\n",
"201501 -1.64 0.90 2.95 0.25 ... 5.58 6.82 7.93 4.63\n",
"201502 4.44 4.40 5.47 5.87 ... 1.00 -0.29 0.11 -1.77\n",
"201503 -0.72 -2.07 -8.82 -2.60 ... -2.88 0.51 0.76 -0.23\n",
"201504 -0.17 -0.52 5.94 3.75 ... 0.54 1.56 3.09 0.92\n",
"201505 2.03 2.00 1.28 0.71 ... -0.49 0.29 1.34 -3.59\n",
"201506 -1.95 -1.71 -2.57 1.30 ... 5.79 4.17 1.97 3.18\n",
"201507 4.03 3.51 9.59 6.09 ... -5.44 -6.48 -6.54 -5.20\n",
"201508 -4.37 -3.12 -4.06 -7.35 ... -1.75 0.44 -3.14 -1.87\n",
"201509 -1.19 2.58 2.37 -9.94 ... 4.56 5.05 5.90 6.98\n",
"201510 5.81 8.06 10.90 14.61 ... 0.61 -1.01 2.16 0.05\n",
"201511 0.11 -0.71 -3.00 -0.41 ... 0.82 -0.95 -2.92 0.25\n",
"201512 1.96 0.30 1.59 -1.70 ... -4.45 -0.94 -9.63 -3.20\n",
"201601 -1.67 -0.23 4.28 -8.15 ... -0.36 1.03 -2.85 2.71\n",
"201602 0.95 -2.34 0.93 4.25 ... 5.99 5.36 6.65 6.68\n",
"201603 4.69 5.61 5.04 8.61 ... -0.38 -2.38 3.96 0.67\n",
"201604 0.63 0.31 -0.25 -6.30 ... 1.19 -1.48 2.15 -2.02\n",
"201605 2.06 -0.91 0.83 5.42 ... 0.71 1.16 -5.30 3.61\n",
"201606 4.75 5.31 6.87 -4.43 ... 3.78 2.19 4.04 -0.21\n",
"201607 -0.51 1.82 -2.79 6.15 ... -1.69 -0.24 4.88 2.24\n",
"201608 -0.52 -0.90 -1.22 0.94 ... -0.18 -2.25 -1.45 -3.48\n",
"201609 -2.92 1.63 -2.78 4.62 ... -3.59 -1.96 1.40 -0.53\n",
"201610 -0.33 -1.65 4.59 5.59 ... 2.99 8.47 12.84 8.29\n",
"201611 -4.41 -5.76 -5.12 3.87 ... -0.98 0.58 3.80 2.57\n",
"201612 4.43 3.00 5.39 -3.36 ... 0.93 0.71 0.56 -0.87\n",
"\n",
"[685 rows x 60 columns]"
]
},
"metadata": {
"tags": []
},
"execution_count": 7
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "D8_fqeR-fkX7",
"outputId": "500b9d06-2d11-4313-eeb0-08855faa08dc",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 314
}
},
"source": [
"data.to_csv(\"output/data.csv\")\n",
"desc = data.describe()\n",
"desc\n",
"# min, max line up with Table 1"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Food</th>\n",
" <th>Beer</th>\n",
" <th>Smoke</th>\n",
" <th>Games</th>\n",
" <th>Books</th>\n",
" <th>Hshld</th>\n",
" <th>Clths</th>\n",
" <th>Hlth</th>\n",
" <th>Chems</th>\n",
" <th>Txtls</th>\n",
" <th>Cnstr</th>\n",
" <th>Steel</th>\n",
" <th>FabPr</th>\n",
" <th>ElcEq</th>\n",
" <th>Autos</th>\n",
" <th>Carry</th>\n",
" <th>Mines</th>\n",
" <th>Coal</th>\n",
" <th>Oil</th>\n",
" <th>Util</th>\n",
" <th>Telcm</th>\n",
" <th>Servs</th>\n",
" <th>BusEq</th>\n",
" <th>Paper</th>\n",
" <th>Trans</th>\n",
" <th>Whlsl</th>\n",
" <th>Rtail</th>\n",
" <th>Meals</th>\n",
" <th>Fin</th>\n",
" <th>Other</th>\n",
" <th>Food.lead</th>\n",
" <th>Beer.lead</th>\n",
" <th>Smoke.lead</th>\n",
" <th>Games.lead</th>\n",
" <th>Books.lead</th>\n",
" <th>Hshld.lead</th>\n",
" <th>Clths.lead</th>\n",
" <th>Hlth.lead</th>\n",
" <th>Chems.lead</th>\n",
" <th>Txtls.lead</th>\n",
" <th>Cnstr.lead</th>\n",
" <th>Steel.lead</th>\n",
" <th>FabPr.lead</th>\n",
" <th>ElcEq.lead</th>\n",
" <th>Autos.lead</th>\n",
" <th>Carry.lead</th>\n",
" <th>Mines.lead</th>\n",
" <th>Coal.lead</th>\n",
" <th>Oil.lead</th>\n",
" <th>Util.lead</th>\n",
" <th>Telcm.lead</th>\n",
" <th>Servs.lead</th>\n",
" <th>BusEq.lead</th>\n",
" <th>Paper.lead</th>\n",
" <th>Trans.lead</th>\n",
" <th>Whlsl.lead</th>\n",
" <th>Rtail.lead</th>\n",
" <th>Meals.lead</th>\n",
" <th>Fin.lead</th>\n",
" <th>Other.lead</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>count</th>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.00000</td>\n",
" <td>685.00000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" <td>685.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>mean</th>\n",
" <td>0.690715</td>\n",
" <td>0.710613</td>\n",
" <td>0.982321</td>\n",
" <td>0.701708</td>\n",
" <td>0.528277</td>\n",
" <td>0.554190</td>\n",
" <td>0.669460</td>\n",
" <td>0.650905</td>\n",
" <td>0.519781</td>\n",
" <td>0.667416</td>\n",
" <td>0.523460</td>\n",
" <td>0.293810</td>\n",
" <td>0.562584</td>\n",
" <td>0.704219</td>\n",
" <td>0.453985</td>\n",
" <td>0.718730</td>\n",
" <td>0.548657</td>\n",
" <td>0.735547</td>\n",
" <td>0.650978</td>\n",
" <td>0.483606</td>\n",
" <td>0.521737</td>\n",
" <td>0.683416</td>\n",
" <td>0.580482</td>\n",
" <td>0.510044</td>\n",
" <td>0.582569</td>\n",
" <td>0.622657</td>\n",
" <td>0.664380</td>\n",
" <td>0.705650</td>\n",
" <td>0.609212</td>\n",
" <td>0.377401</td>\n",
" <td>0.689168</td>\n",
" <td>0.708613</td>\n",
" <td>0.99492</td>\n",
" <td>0.70638</td>\n",
" <td>0.519971</td>\n",
" <td>0.557182</td>\n",
" <td>0.666715</td>\n",
" <td>0.656949</td>\n",
" <td>0.520818</td>\n",
" <td>0.676409</td>\n",
" <td>0.528029</td>\n",
" <td>0.295883</td>\n",
" <td>0.564818</td>\n",
" <td>0.702496</td>\n",
" <td>0.453839</td>\n",
" <td>0.728701</td>\n",
" <td>0.560292</td>\n",
" <td>0.724701</td>\n",
" <td>0.638861</td>\n",
" <td>0.482526</td>\n",
" <td>0.520847</td>\n",
" <td>0.694234</td>\n",
" <td>0.584175</td>\n",
" <td>0.511241</td>\n",
" <td>0.582088</td>\n",
" <td>0.625562</td>\n",
" <td>0.662219</td>\n",
" <td>0.702730</td>\n",
" <td>0.609810</td>\n",
" <td>0.385620</td>\n",
" </tr>\n",
" <tr>\n",
" <th>std</th>\n",
" <td>4.339811</td>\n",
" <td>5.090215</td>\n",
" <td>6.061582</td>\n",
" <td>7.180918</td>\n",
" <td>5.809314</td>\n",
" <td>4.759874</td>\n",
" <td>6.386027</td>\n",
" <td>4.928072</td>\n",
" <td>5.518477</td>\n",
" <td>7.022552</td>\n",
" <td>5.991354</td>\n",
" <td>7.294629</td>\n",
" <td>6.114140</td>\n",
" <td>6.211516</td>\n",
" <td>6.689082</td>\n",
" <td>6.292859</td>\n",
" <td>7.452882</td>\n",
" <td>10.193399</td>\n",
" <td>5.348388</td>\n",
" <td>3.991419</td>\n",
" <td>4.629125</td>\n",
" <td>6.526231</td>\n",
" <td>6.738237</td>\n",
" <td>5.054992</td>\n",
" <td>5.739414</td>\n",
" <td>5.605280</td>\n",
" <td>5.349748</td>\n",
" <td>6.104997</td>\n",
" <td>5.411795</td>\n",
" <td>5.821199</td>\n",
" <td>4.339528</td>\n",
" <td>5.090626</td>\n",
" <td>6.06222</td>\n",
" <td>7.18257</td>\n",
" <td>5.803697</td>\n",
" <td>4.760591</td>\n",
" <td>6.385915</td>\n",
" <td>4.927392</td>\n",
" <td>5.519025</td>\n",
" <td>7.026588</td>\n",
" <td>5.992697</td>\n",
" <td>7.295367</td>\n",
" <td>6.115352</td>\n",
" <td>6.210339</td>\n",
" <td>6.688977</td>\n",
" <td>6.289385</td>\n",
" <td>7.465115</td>\n",
" <td>10.195930</td>\n",
" <td>5.350350</td>\n",
" <td>3.991165</td>\n",
" <td>4.628520</td>\n",
" <td>6.527984</td>\n",
" <td>6.738979</td>\n",
" <td>5.055314</td>\n",
" <td>5.739306</td>\n",
" <td>5.605317</td>\n",
" <td>5.349341</td>\n",
" <td>6.104515</td>\n",
" <td>5.411766</td>\n",
" <td>5.815446</td>\n",
" </tr>\n",
" <tr>\n",
" <th>min</th>\n",
" <td>-18.150000</td>\n",
" <td>-20.190000</td>\n",
" <td>-25.320000</td>\n",
" <td>-33.400000</td>\n",
" <td>-26.560000</td>\n",
" <td>-22.240000</td>\n",
" <td>-31.500000</td>\n",
" <td>-21.060000</td>\n",
" <td>-28.600000</td>\n",
" <td>-33.110000</td>\n",
" <td>-28.740000</td>\n",
" <td>-32.990000</td>\n",
" <td>-31.630000</td>\n",
" <td>-32.800000</td>\n",
" <td>-36.490000</td>\n",
" <td>-31.100000</td>\n",
" <td>-34.550000</td>\n",
" <td>-38.090000</td>\n",
" <td>-18.960000</td>\n",
" <td>-12.940000</td>\n",
" <td>-16.440000</td>\n",
" <td>-28.670000</td>\n",
" <td>-32.070000</td>\n",
" <td>-27.740000</td>\n",
" <td>-28.500000</td>\n",
" <td>-29.250000</td>\n",
" <td>-29.740000</td>\n",
" <td>-31.890000</td>\n",
" <td>-22.530000</td>\n",
" <td>-28.090000</td>\n",
" <td>-18.150000</td>\n",
" <td>-20.190000</td>\n",
" <td>-25.32000</td>\n",
" <td>-33.40000</td>\n",
" <td>-26.560000</td>\n",
" <td>-22.240000</td>\n",
" <td>-31.500000</td>\n",
" <td>-21.060000</td>\n",
" <td>-28.600000</td>\n",
" <td>-33.110000</td>\n",
" <td>-28.740000</td>\n",
" <td>-32.990000</td>\n",
" <td>-31.630000</td>\n",
" <td>-32.800000</td>\n",
" <td>-36.490000</td>\n",
" <td>-31.100000</td>\n",
" <td>-34.550000</td>\n",
" <td>-38.090000</td>\n",
" <td>-18.960000</td>\n",
" <td>-12.940000</td>\n",
" <td>-16.440000</td>\n",
" <td>-28.670000</td>\n",
" <td>-32.070000</td>\n",
" <td>-27.740000</td>\n",
" <td>-28.500000</td>\n",
" <td>-29.250000</td>\n",
" <td>-29.740000</td>\n",
" <td>-31.890000</td>\n",
" <td>-22.530000</td>\n",
" <td>-28.090000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25%</th>\n",
" <td>-1.640000</td>\n",
" <td>-2.100000</td>\n",
" <td>-2.780000</td>\n",
" <td>-3.490000</td>\n",
" <td>-2.690000</td>\n",
" <td>-2.110000</td>\n",
" <td>-2.810000</td>\n",
" <td>-2.240000</td>\n",
" <td>-2.800000</td>\n",
" <td>-3.200000</td>\n",
" <td>-2.880000</td>\n",
" <td>-4.120000</td>\n",
" <td>-3.050000</td>\n",
" <td>-2.990000</td>\n",
" <td>-3.350000</td>\n",
" <td>-3.220000</td>\n",
" <td>-3.980000</td>\n",
" <td>-5.050000</td>\n",
" <td>-2.660000</td>\n",
" <td>-1.860000</td>\n",
" <td>-2.110000</td>\n",
" <td>-3.090000</td>\n",
" <td>-3.290000</td>\n",
" <td>-2.430000</td>\n",
" <td>-2.780000</td>\n",
" <td>-2.570000</td>\n",
" <td>-2.430000</td>\n",
" <td>-2.940000</td>\n",
" <td>-2.420000</td>\n",
" <td>-3.010000</td>\n",
" <td>-1.640000</td>\n",
" <td>-2.100000</td>\n",
" <td>-2.74000</td>\n",
" <td>-3.49000</td>\n",
" <td>-2.690000</td>\n",
" <td>-2.110000</td>\n",
" <td>-2.810000</td>\n",
" <td>-2.240000</td>\n",
" <td>-2.800000</td>\n",
" <td>-3.200000</td>\n",
" <td>-2.880000</td>\n",
" <td>-4.120000</td>\n",
" <td>-3.050000</td>\n",
" <td>-2.990000</td>\n",
" <td>-3.350000</td>\n",
" <td>-3.200000</td>\n",
" <td>-3.980000</td>\n",
" <td>-5.050000</td>\n",
" <td>-2.670000</td>\n",
" <td>-1.860000</td>\n",
" <td>-2.110000</td>\n",
" <td>-3.090000</td>\n",
" <td>-3.290000</td>\n",
" <td>-2.430000</td>\n",
" <td>-2.780000</td>\n",
" <td>-2.570000</td>\n",
" <td>-2.430000</td>\n",
" <td>-2.940000</td>\n",
" <td>-2.420000</td>\n",
" <td>-2.990000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50%</th>\n",
" <td>0.740000</td>\n",
" <td>0.710000</td>\n",
" <td>1.280000</td>\n",
" <td>0.890000</td>\n",
" <td>0.510000</td>\n",
" <td>0.750000</td>\n",
" <td>0.690000</td>\n",
" <td>0.750000</td>\n",
" <td>0.670000</td>\n",
" <td>0.630000</td>\n",
" <td>0.610000</td>\n",
" <td>0.220000</td>\n",
" <td>0.860000</td>\n",
" <td>0.550000</td>\n",
" <td>0.260000</td>\n",
" <td>0.930000</td>\n",
" <td>0.600000</td>\n",
" <td>0.400000</td>\n",
" <td>0.650000</td>\n",
" <td>0.620000</td>\n",
" <td>0.610000</td>\n",
" <td>0.960000</td>\n",
" <td>0.560000</td>\n",
" <td>0.690000</td>\n",
" <td>0.860000</td>\n",
" <td>0.900000</td>\n",
" <td>0.470000</td>\n",
" <td>1.040000</td>\n",
" <td>0.820000</td>\n",
" <td>0.470000</td>\n",
" <td>0.740000</td>\n",
" <td>0.710000</td>\n",
" <td>1.29000</td>\n",
" <td>0.89000</td>\n",
" <td>0.510000</td>\n",
" <td>0.780000</td>\n",
" <td>0.680000</td>\n",
" <td>0.760000</td>\n",
" <td>0.670000</td>\n",
" <td>0.630000</td>\n",
" <td>0.610000</td>\n",
" <td>0.220000</td>\n",
" <td>0.860000</td>\n",
" <td>0.550000</td>\n",
" <td>0.260000</td>\n",
" <td>0.950000</td>\n",
" <td>0.600000</td>\n",
" <td>0.380000</td>\n",
" <td>0.630000</td>\n",
" <td>0.620000</td>\n",
" <td>0.610000</td>\n",
" <td>0.970000</td>\n",
" <td>0.560000</td>\n",
" <td>0.690000</td>\n",
" <td>0.860000</td>\n",
" <td>0.940000</td>\n",
" <td>0.470000</td>\n",
" <td>1.030000</td>\n",
" <td>0.820000</td>\n",
" <td>0.470000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75%</th>\n",
" <td>3.120000</td>\n",
" <td>3.660000</td>\n",
" <td>4.640000</td>\n",
" <td>5.310000</td>\n",
" <td>3.720000</td>\n",
" <td>3.550000</td>\n",
" <td>4.310000</td>\n",
" <td>3.560000</td>\n",
" <td>3.760000</td>\n",
" <td>4.490000</td>\n",
" <td>4.080000</td>\n",
" <td>4.470000</td>\n",
" <td>4.230000</td>\n",
" <td>4.640000</td>\n",
" <td>4.230000</td>\n",
" <td>4.660000</td>\n",
" <td>5.300000</td>\n",
" <td>6.090000</td>\n",
" <td>3.930000</td>\n",
" <td>2.930000</td>\n",
" <td>3.360000</td>\n",
" <td>4.260000</td>\n",
" <td>4.590000</td>\n",
" <td>3.460000</td>\n",
" <td>4.060000</td>\n",
" <td>3.880000</td>\n",
" <td>4.000000</td>\n",
" <td>4.330000</td>\n",
" <td>4.000000</td>\n",
" <td>4.200000</td>\n",
" <td>3.120000</td>\n",
" <td>3.660000</td>\n",
" <td>4.66000</td>\n",
" <td>5.31000</td>\n",
" <td>3.680000</td>\n",
" <td>3.550000</td>\n",
" <td>4.310000</td>\n",
" <td>3.560000</td>\n",
" <td>3.760000</td>\n",
" <td>4.510000</td>\n",
" <td>4.080000</td>\n",
" <td>4.470000</td>\n",
" <td>4.240000</td>\n",
" <td>4.550000</td>\n",
" <td>4.230000</td>\n",
" <td>4.660000</td>\n",
" <td>5.310000</td>\n",
" <td>6.090000</td>\n",
" <td>3.930000</td>\n",
" <td>2.930000</td>\n",
" <td>3.360000</td>\n",
" <td>4.290000</td>\n",
" <td>4.590000</td>\n",
" <td>3.460000</td>\n",
" <td>4.060000</td>\n",
" <td>3.880000</td>\n",
" <td>4.000000</td>\n",
" <td>4.330000</td>\n",
" <td>4.000000</td>\n",
" <td>4.200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>max</th>\n",
" <td>19.890000</td>\n",
" <td>25.510000</td>\n",
" <td>32.380000</td>\n",
" <td>34.520000</td>\n",
" <td>33.130000</td>\n",
" <td>18.220000</td>\n",
" <td>31.790000</td>\n",
" <td>29.010000</td>\n",
" <td>21.680000</td>\n",
" <td>59.030000</td>\n",
" <td>25.020000</td>\n",
" <td>30.300000</td>\n",
" <td>22.910000</td>\n",
" <td>23.210000</td>\n",
" <td>49.560000</td>\n",
" <td>23.390000</td>\n",
" <td>35.150000</td>\n",
" <td>45.550000</td>\n",
" <td>23.700000</td>\n",
" <td>18.260000</td>\n",
" <td>21.220000</td>\n",
" <td>23.380000</td>\n",
" <td>24.660000</td>\n",
" <td>21.000000</td>\n",
" <td>18.500000</td>\n",
" <td>17.530000</td>\n",
" <td>26.490000</td>\n",
" <td>27.380000</td>\n",
" <td>20.590000</td>\n",
" <td>19.960000</td>\n",
" <td>19.890000</td>\n",
" <td>25.510000</td>\n",
" <td>32.38000</td>\n",
" <td>34.52000</td>\n",
" <td>33.130000</td>\n",
" <td>18.220000</td>\n",
" <td>31.790000</td>\n",
" <td>29.010000</td>\n",
" <td>21.680000</td>\n",
" <td>59.030000</td>\n",
" <td>25.020000</td>\n",
" <td>30.300000</td>\n",
" <td>22.910000</td>\n",
" <td>23.210000</td>\n",
" <td>49.560000</td>\n",
" <td>23.390000</td>\n",
" <td>35.150000</td>\n",
" <td>45.550000</td>\n",
" <td>23.700000</td>\n",
" <td>18.260000</td>\n",
" <td>21.220000</td>\n",
" <td>23.380000</td>\n",
" <td>24.660000</td>\n",
" <td>21.000000</td>\n",
" <td>18.500000</td>\n",
" <td>17.530000</td>\n",
" <td>26.490000</td>\n",
" <td>27.380000</td>\n",
" <td>20.590000</td>\n",
" <td>19.960000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Food Beer Smoke ... Meals.lead Fin.lead Other.lead\n",
"count 685.000000 685.000000 685.000000 ... 685.000000 685.000000 685.000000\n",
"mean 0.690715 0.710613 0.982321 ... 0.702730 0.609810 0.385620\n",
"std 4.339811 5.090215 6.061582 ... 6.104515 5.411766 5.815446\n",
"min -18.150000 -20.190000 -25.320000 ... -31.890000 -22.530000 -28.090000\n",
"25% -1.640000 -2.100000 -2.780000 ... -2.940000 -2.420000 -2.990000\n",
"50% 0.740000 0.710000 1.280000 ... 1.030000 0.820000 0.470000\n",
"75% 3.120000 3.660000 4.640000 ... 4.330000 4.000000 4.200000\n",
"max 19.890000 25.510000 32.380000 ... 27.380000 20.590000 19.960000\n",
"\n",
"[8 rows x 60 columns]"
]
},
"metadata": {
"tags": []
},
"execution_count": 8
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "Im6K_dwCfkYA",
"outputId": "75930d86-c3ee-4009-8dc3-66af1486172e",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 969
}
},
"source": [
"# annualized returns don't match Table 1, oddly\n",
"# geometric mean, annualized\n",
"pd.DataFrame((np.prod(data/100 + 1)**(12.0/len(data))-1)[:30], columns=['Mean Ann. Return'])"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Mean Ann. Return</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Food</th>\n",
" <td>0.074020</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Beer</th>\n",
" <td>0.072005</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Smoke</th>\n",
" <td>0.100147</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Games</th>\n",
" <td>0.054031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Books</th>\n",
" <td>0.043953</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Hshld</th>\n",
" <td>0.054098</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Clths</th>\n",
" <td>0.057170</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Hlth</th>\n",
" <td>0.065463</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Chems</th>\n",
" <td>0.044917</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Txtls</th>\n",
" <td>0.051888</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Cnstr</th>\n",
" <td>0.041836</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Steel</th>\n",
" <td>0.002802</td>\n",
" </tr>\n",
" <tr>\n",
" <th>FabPr</th>\n",
" <td>0.045615</td>\n",
" </tr>\n",
" <tr>\n",
" <th>ElcEq</th>\n",
" <td>0.062927</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Autos</th>\n",
" <td>0.027963</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Carry</th>\n",
" <td>0.063991</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mines</th>\n",
" <td>0.032527</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Coal</th>\n",
" <td>0.026075</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Oil</th>\n",
" <td>0.062748</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Util</th>\n",
" <td>0.049564</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Telcm</th>\n",
" <td>0.050868</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Servs</th>\n",
" <td>0.057776</td>\n",
" </tr>\n",
" <tr>\n",
" <th>BusEq</th>\n",
" <td>0.042774</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Paper</th>\n",
" <td>0.046776</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Trans</th>\n",
" <td>0.051138</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Whlsl</th>\n",
" <td>0.057056</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Rtail</th>\n",
" <td>0.064258</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Meals</th>\n",
" <td>0.063630</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Fin</th>\n",
" <td>0.056748</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Other</th>\n",
" <td>0.024894</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Mean Ann. Return\n",
"Food 0.074020\n",
"Beer 0.072005\n",
"Smoke 0.100147\n",
"Games 0.054031\n",
"Books 0.043953\n",
"Hshld 0.054098\n",
"Clths 0.057170\n",
"Hlth 0.065463\n",
"Chems 0.044917\n",
"Txtls 0.051888\n",
"Cnstr 0.041836\n",
"Steel 0.002802\n",
"FabPr 0.045615\n",
"ElcEq 0.062927\n",
"Autos 0.027963\n",
"Carry 0.063991\n",
"Mines 0.032527\n",
"Coal 0.026075\n",
"Oil 0.062748\n",
"Util 0.049564\n",
"Telcm 0.050868\n",
"Servs 0.057776\n",
"BusEq 0.042774\n",
"Paper 0.046776\n",
"Trans 0.051138\n",
"Whlsl 0.057056\n",
"Rtail 0.064258\n",
"Meals 0.063630\n",
"Fin 0.056748\n",
"Other 0.024894"
]
},
"metadata": {
"tags": []
},
"execution_count": 9
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "J-8ZJm63fkYE",
"outputId": "d0d38fda-2acf-4ae6-c5aa-6cf545b6abc4",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 969
}
},
"source": [
"# try this way, arithmetic mean then annualize (not very correct)\n",
"#print(pd.DataFrame(((desc.loc['mean']/100+1)**12-1)[:30]))\n",
"#nope\n",
"\n",
"# same\n",
"pd.DataFrame(((1 + np.mean(data, axis=0)/100)**12 -1)[:30], columns=['Mean Ann. Return'])"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Mean Ann. Return</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Food</th>\n",
" <td>0.086108</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Beer</th>\n",
" <td>0.088687</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Smoke</th>\n",
" <td>0.124460</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Games</th>\n",
" <td>0.087532</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Books</th>\n",
" <td>0.065268</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Hshld</th>\n",
" <td>0.068568</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Clths</th>\n",
" <td>0.083360</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Hlth</th>\n",
" <td>0.080966</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Chems</th>\n",
" <td>0.064188</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Txtls</th>\n",
" <td>0.083096</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Cnstr</th>\n",
" <td>0.064656</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Steel</th>\n",
" <td>0.035833</td>\n",
" </tr>\n",
" <tr>\n",
" <th>FabPr</th>\n",
" <td>0.069639</td>\n",
" </tr>\n",
" <tr>\n",
" <th>ElcEq</th>\n",
" <td>0.087857</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Autos</th>\n",
" <td>0.055859</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Carry</th>\n",
" <td>0.089740</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mines</th>\n",
" <td>0.067862</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Coal</th>\n",
" <td>0.091926</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Oil</th>\n",
" <td>0.080976</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Util</th>\n",
" <td>0.059601</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Telcm</th>\n",
" <td>0.064437</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Servs</th>\n",
" <td>0.085164</td>\n",
" </tr>\n",
" <tr>\n",
" <th>BusEq</th>\n",
" <td>0.071925</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Paper</th>\n",
" <td>0.062952</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Trans</th>\n",
" <td>0.072192</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Whlsl</th>\n",
" <td>0.077332</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Rtail</th>\n",
" <td>0.082704</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Meals</th>\n",
" <td>0.088043</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Fin</th>\n",
" <td>0.075605</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Other</th>\n",
" <td>0.046240</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Mean Ann. Return\n",
"Food 0.086108\n",
"Beer 0.088687\n",
"Smoke 0.124460\n",
"Games 0.087532\n",
"Books 0.065268\n",
"Hshld 0.068568\n",
"Clths 0.083360\n",
"Hlth 0.080966\n",
"Chems 0.064188\n",
"Txtls 0.083096\n",
"Cnstr 0.064656\n",
"Steel 0.035833\n",
"FabPr 0.069639\n",
"ElcEq 0.087857\n",
"Autos 0.055859\n",
"Carry 0.089740\n",
"Mines 0.067862\n",
"Coal 0.091926\n",
"Oil 0.080976\n",
"Util 0.059601\n",
"Telcm 0.064437\n",
"Servs 0.085164\n",
"BusEq 0.071925\n",
"Paper 0.062952\n",
"Trans 0.072192\n",
"Whlsl 0.077332\n",
"Rtail 0.082704\n",
"Meals 0.088043\n",
"Fin 0.075605\n",
"Other 0.046240"
]
},
"metadata": {
"tags": []
},
"execution_count": 10
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "hhElRHePfkYL",
"outputId": "b08e2950-695c-4c44-f3c7-249080fc04f3",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 969
}
},
"source": [
"#annualized volatility \n",
"pd.DataFrame((desc.loc['std']*np.sqrt(12))[:30].round(2))\n",
"# lines up with table 1"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>std</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>Food</th>\n",
" <td>15.03</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Beer</th>\n",
" <td>17.63</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Smoke</th>\n",
" <td>21.00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Games</th>\n",
" <td>24.88</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Books</th>\n",
" <td>20.12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Hshld</th>\n",
" <td>16.49</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Clths</th>\n",
" <td>22.12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Hlth</th>\n",
" <td>17.07</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Chems</th>\n",
" <td>19.12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Txtls</th>\n",
" <td>24.33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Cnstr</th>\n",
" <td>20.75</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Steel</th>\n",
" <td>25.27</td>\n",
" </tr>\n",
" <tr>\n",
" <th>FabPr</th>\n",
" <td>21.18</td>\n",
" </tr>\n",
" <tr>\n",
" <th>ElcEq</th>\n",
" <td>21.52</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Autos</th>\n",
" <td>23.17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Carry</th>\n",
" <td>21.80</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Mines</th>\n",
" <td>25.82</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Coal</th>\n",
" <td>35.31</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Oil</th>\n",
" <td>18.53</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Util</th>\n",
" <td>13.83</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Telcm</th>\n",
" <td>16.04</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Servs</th>\n",
" <td>22.61</td>\n",
" </tr>\n",
" <tr>\n",
" <th>BusEq</th>\n",
" <td>23.34</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Paper</th>\n",
" <td>17.51</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Trans</th>\n",
" <td>19.88</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Whlsl</th>\n",
" <td>19.42</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Rtail</th>\n",
" <td>18.53</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Meals</th>\n",
" <td>21.15</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Fin</th>\n",
" <td>18.75</td>\n",
" </tr>\n",
" <tr>\n",
" <th>Other</th>\n",
" <td>20.17</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" std\n",
"Food 15.03\n",
"Beer 17.63\n",
"Smoke 21.00\n",
"Games 24.88\n",
"Books 20.12\n",
"Hshld 16.49\n",
"Clths 22.12\n",
"Hlth 17.07\n",
"Chems 19.12\n",
"Txtls 24.33\n",
"Cnstr 20.75\n",
"Steel 25.27\n",
"FabPr 21.18\n",
"ElcEq 21.52\n",
"Autos 23.17\n",
"Carry 21.80\n",
"Mines 25.82\n",
"Coal 35.31\n",
"Oil 18.53\n",
"Util 13.83\n",
"Telcm 16.04\n",
"Servs 22.61\n",
"BusEq 23.34\n",
"Paper 17.51\n",
"Trans 19.88\n",
"Whlsl 19.42\n",
"Rtail 18.53\n",
"Meals 21.15\n",
"Fin 18.75\n",
"Other 20.17"
]
},
"metadata": {
"tags": []
},
"execution_count": 11
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "yX5HPyuR5M2E",
"outputId": "3d3d4074-b530-461a-b530-6899a11f17ef",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"npredictors"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"30"
]
},
"metadata": {
"tags": []
},
"execution_count": 12
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "5vs1PCfIfkYP",
"outputId": "c421ea44-0531-4cfe-83be-bd51f80be586",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"# Run LASSO, then OLS on selected variables\n",
"\n",
"# skip last row to better match published r-squared\n",
"# looks like they forecast actuals 1960-2016 using 1959m12 to 2016m11\n",
"# not exact matches to Table 2 R-squared but almost within rounding error \n",
"X = data.values[:-1,:npredictors]\n",
"Y = data.values[:-1,-nresponses:] # Predict leads\n",
"nrows = X.shape[0]\n",
"X.shape"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"(684, 30)"
]
},
"metadata": {
"tags": []
},
"execution_count": 13
}
]
},
{
"cell_type": "code",
"metadata": {
"scrolled": false,
"id": "EdmjvklBfkYV",
"outputId": "fc7b9e8e-92c5-47e4-a7cc-4ca773022f84",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"def subset_selection(X, Y, model_aic, verbose=False, responses=responses, predictors=predictors):\n",
" # For each response variable run AIC \n",
" nrows, npreds = X.shape\n",
" nows, nresps = Y.shape\n",
" coef_dict = []\n",
" \n",
" for response_index in range(nresps):\n",
" y = Y[:,response_index]\n",
" model_aic.fit(X, y)\n",
" predcols = [i for i in range(npreds) if model_aic.coef_[i] !=0]\n",
"\n",
" #y_response = model_aic.predict(X)\n",
" # print (\"In-sample LASSO R-squared: %.6f\" % r2_score(y, y_response))\n",
" if verbose and responses:\n",
" print(\"LASSO variables selected for %s: \" % responses[response_index])\n",
" print([predictors[i] for i in predcols])\n",
" \n",
" if not predcols:\n",
" if verbose and responses:\n",
" print(\"No coefs selected for \" + responses[response_index] + \", using all\")\n",
" print(\"---\")\n",
" predcols = list(range(npreds)) \n",
" \n",
" # fit OLS vs. selected vars, better fit w/o LASSO penalties\n",
" # in-sample R-squared using LASSO coeffs\n",
" coef_dict.append(predcols)\n",
" if verbose and responses and predictors:\n",
" print(\"Running OLS for \" + responses[response_index] + \" against \" + str([predictors[i] for i in predcols]))\n",
" # col nums of selected responses\n",
" model_ols = LinearRegression()\n",
" model_ols.fit(X[:, predcols], y)\n",
" y_pred = model_ols.predict(X[:, predcols])\n",
" print (\"In-sample OLS R-squared: %.2f%%\" % (100 * r2_score(y, y_pred)))\n",
" print(\"---\")\n",
" \n",
" return coef_dict\n",
"\n",
"#coef_dict = subset_selection(X, Y, LassoLarsIC(criterion='aic'))\n",
"coef_dict = subset_selection(X, Y, LassoLarsIC(criterion='aic'), verbose=True, responses=responses, predictors=predictors)\n",
"print(coef_dict)\n",
"# These subsets line up closely with Table 2\n",
"# except Clths, Whlsl, we get different responses"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"LASSO variables selected for Food.lead: \n",
"['Clths', 'Coal', 'Util', 'Rtail']\n",
"Running OLS for Food.lead against ['Clths', 'Coal', 'Util', 'Rtail']\n",
"In-sample OLS R-squared: 2.24%\n",
"---\n",
"LASSO variables selected for Beer.lead: \n",
"['Food', 'Clths', 'Coal']\n",
"Running OLS for Beer.lead against ['Food', 'Clths', 'Coal']\n",
"In-sample OLS R-squared: 2.52%\n",
"---\n",
"LASSO variables selected for Smoke.lead: \n",
"['Txtls', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'Paper', 'Trans', 'Fin']\n",
"Running OLS for Smoke.lead against ['Txtls', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'Paper', 'Trans', 'Fin']\n",
"In-sample OLS R-squared: 6.55%\n",
"---\n",
"LASSO variables selected for Games.lead: \n",
"['Books', 'Clths', 'Coal', 'Fin']\n",
"Running OLS for Games.lead against ['Books', 'Clths', 'Coal', 'Fin']\n",
"In-sample OLS R-squared: 5.05%\n",
"---\n",
"LASSO variables selected for Books.lead: \n",
"['Games', 'Books', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Fin']\n",
"Running OLS for Books.lead against ['Games', 'Books', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Fin']\n",
"In-sample OLS R-squared: 6.30%\n",
"---\n",
"LASSO variables selected for Hshld.lead: \n",
"['Clths', 'Coal', 'Rtail']\n",
"Running OLS for Hshld.lead against ['Clths', 'Coal', 'Rtail']\n",
"In-sample OLS R-squared: 2.97%\n",
"---\n",
"LASSO variables selected for Clths.lead: \n",
"['Clths', 'Coal', 'Oil', 'Servs', 'Rtail']\n",
"Running OLS for Clths.lead against ['Clths', 'Coal', 'Oil', 'Servs', 'Rtail']\n",
"In-sample OLS R-squared: 4.73%\n",
"---\n",
"LASSO variables selected for Hlth.lead: \n",
"['Books', 'Mines', 'Coal', 'Util']\n",
"Running OLS for Hlth.lead against ['Books', 'Mines', 'Coal', 'Util']\n",
"In-sample OLS R-squared: 2.68%\n",
"---\n",
"LASSO variables selected for Chems.lead: \n",
"['Clths']\n",
"Running OLS for Chems.lead against ['Clths']\n",
"In-sample OLS R-squared: 0.78%\n",
"---\n",
"LASSO variables selected for Txtls.lead: \n",
"['Clths', 'Autos', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"Running OLS for Txtls.lead against ['Clths', 'Autos', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"In-sample OLS R-squared: 7.91%\n",
"---\n",
"LASSO variables selected for Cnstr.lead: \n",
"['Clths', 'Coal', 'Oil', 'Util', 'Trans', 'Rtail', 'Fin']\n",
"Running OLS for Cnstr.lead against ['Clths', 'Coal', 'Oil', 'Util', 'Trans', 'Rtail', 'Fin']\n",
"In-sample OLS R-squared: 5.15%\n",
"---\n",
"LASSO variables selected for Steel.lead: \n",
"['Fin']\n",
"Running OLS for Steel.lead against ['Fin']\n",
"In-sample OLS R-squared: 1.28%\n",
"---\n",
"LASSO variables selected for FabPr.lead: \n",
"['Trans', 'Fin']\n",
"Running OLS for FabPr.lead against ['Trans', 'Fin']\n",
"In-sample OLS R-squared: 1.57%\n",
"---\n",
"LASSO variables selected for ElcEq.lead: \n",
"['Fin']\n",
"Running OLS for ElcEq.lead against ['Fin']\n",
"In-sample OLS R-squared: 0.80%\n",
"---\n",
"LASSO variables selected for Autos.lead: \n",
"['Hshld', 'Clths', 'Coal', 'Oil', 'Util', 'BusEq', 'Rtail', 'Fin']\n",
"Running OLS for Autos.lead against ['Hshld', 'Clths', 'Coal', 'Oil', 'Util', 'BusEq', 'Rtail', 'Fin']\n",
"In-sample OLS R-squared: 6.13%\n",
"---\n",
"LASSO variables selected for Carry.lead: \n",
"['Trans']\n",
"Running OLS for Carry.lead against ['Trans']\n",
"In-sample OLS R-squared: 2.32%\n",
"---\n",
"LASSO variables selected for Mines.lead: \n",
"[]\n",
"No coefs selected for Mines.lead, using all\n",
"---\n",
"Running OLS for Mines.lead against ['Food', 'Beer', 'Smoke', 'Games', 'Books', 'Hshld', 'Clths', 'Hlth', 'Chems', 'Txtls', 'Cnstr', 'Steel', 'FabPr', 'ElcEq', 'Autos', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'BusEq', 'Paper', 'Trans', 'Whlsl', 'Rtail', 'Meals', 'Fin', 'Other']\n",
"In-sample OLS R-squared: 5.62%\n",
"---\n",
"LASSO variables selected for Coal.lead: \n",
"['Beer', 'Smoke', 'Books', 'Autos', 'Coal', 'Oil', 'Paper', 'Rtail']\n",
"Running OLS for Coal.lead against ['Beer', 'Smoke', 'Books', 'Autos', 'Coal', 'Oil', 'Paper', 'Rtail']\n",
"In-sample OLS R-squared: 2.84%\n",
"---\n",
"LASSO variables selected for Oil.lead: \n",
"['Beer', 'Hlth', 'Carry']\n",
"Running OLS for Oil.lead against ['Beer', 'Hlth', 'Carry']\n",
"In-sample OLS R-squared: 2.52%\n",
"---\n",
"LASSO variables selected for Util.lead: \n",
"['Food', 'Beer', 'Smoke', 'Hshld', 'Hlth', 'Cnstr', 'FabPr', 'Carry', 'Mines', 'Oil', 'Util', 'Telcm', 'BusEq', 'Whlsl', 'Fin', 'Other']\n",
"Running OLS for Util.lead against ['Food', 'Beer', 'Smoke', 'Hshld', 'Hlth', 'Cnstr', 'FabPr', 'Carry', 'Mines', 'Oil', 'Util', 'Telcm', 'BusEq', 'Whlsl', 'Fin', 'Other']\n",
"In-sample OLS R-squared: 7.86%\n",
"---\n",
"LASSO variables selected for Telcm.lead: \n",
"['Beer', 'Smoke', 'Books', 'Hshld', 'Cnstr', 'Autos', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Meals', 'Fin']\n",
"Running OLS for Telcm.lead against ['Beer', 'Smoke', 'Books', 'Hshld', 'Cnstr', 'Autos', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Meals', 'Fin']\n",
"In-sample OLS R-squared: 5.18%\n",
"---\n",
"LASSO variables selected for Servs.lead: \n",
"['Smoke', 'Books', 'Steel', 'Oil', 'Util', 'Fin']\n",
"Running OLS for Servs.lead against ['Smoke', 'Books', 'Steel', 'Oil', 'Util', 'Fin']\n",
"In-sample OLS R-squared: 2.87%\n",
"---\n",
"LASSO variables selected for BusEq.lead: \n",
"['Smoke', 'Books', 'Util']\n",
"Running OLS for BusEq.lead against ['Smoke', 'Books', 'Util']\n",
"In-sample OLS R-squared: 2.75%\n",
"---\n",
"LASSO variables selected for Paper.lead: \n",
"['Clths', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"Running OLS for Paper.lead against ['Clths', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"In-sample OLS R-squared: 3.24%\n",
"---\n",
"LASSO variables selected for Trans.lead: \n",
"['Fin']\n",
"Running OLS for Trans.lead against ['Fin']\n",
"In-sample OLS R-squared: 1.32%\n",
"---\n",
"LASSO variables selected for Whlsl.lead: \n",
"['Food', 'Smoke', 'Books', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'Fin', 'Other']\n",
"Running OLS for Whlsl.lead against ['Food', 'Smoke', 'Books', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'Fin', 'Other']\n",
"In-sample OLS R-squared: 6.79%\n",
"---\n",
"LASSO variables selected for Rtail.lead: \n",
"['Rtail']\n",
"Running OLS for Rtail.lead against ['Rtail']\n",
"In-sample OLS R-squared: 1.61%\n",
"---\n",
"LASSO variables selected for Meals.lead: \n",
"['Smoke', 'Books', 'Clths', 'Steel', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Meals', 'Fin']\n",
"Running OLS for Meals.lead against ['Smoke', 'Books', 'Clths', 'Steel', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Meals', 'Fin']\n",
"In-sample OLS R-squared: 7.90%\n",
"---\n",
"LASSO variables selected for Fin.lead: \n",
"['Fin']\n",
"Running OLS for Fin.lead against ['Fin']\n",
"In-sample OLS R-squared: 1.70%\n",
"---\n",
"LASSO variables selected for Other.lead: \n",
"['Clths', 'Fin']\n",
"Running OLS for Other.lead against ['Clths', 'Fin']\n",
"In-sample OLS R-squared: 2.69%\n",
"---\n",
"[[6, 17, 19, 26], [0, 6, 17], [9, 15, 16, 17, 18, 19, 20, 21, 23, 24, 28], [4, 6, 17, 28], [3, 4, 17, 18, 19, 21, 22, 26, 28], [6, 17, 26], [6, 17, 18, 21, 26], [4, 16, 17, 19], [6], [6, 14, 17, 18, 26, 28], [6, 17, 18, 19, 24, 26, 28], [28], [24, 28], [28], [5, 6, 17, 18, 19, 22, 26, 28], [24], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [1, 2, 4, 14, 17, 18, 23, 26], [1, 7, 15], [0, 1, 2, 5, 7, 10, 12, 15, 16, 18, 19, 20, 22, 25, 28, 29], [1, 2, 4, 5, 10, 14, 15, 16, 17, 18, 19, 21, 22, 26, 27, 28], [2, 4, 11, 18, 19, 28], [2, 4, 19], [6, 17, 18, 26, 28], [28], [0, 2, 4, 15, 17, 18, 19, 21, 28, 29], [26], [2, 4, 6, 11, 15, 17, 18, 19, 21, 22, 27, 28], [28], [6, 28]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "OspHxwFlfkYa",
"outputId": "1fd0b6be-5755-437b-bd04-3cccb96dac54",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 574
}
},
"source": [
"# same predictors selected for all but 2 response vars\n",
"# Differences might be due to small mechanical differences in the mstatistical tools applied. \n",
"# use predictors from paper to match results\n",
"if True: # turn off/on\n",
" coef_dict_temp = {}\n",
" coef_dict_temp['Food.lead'] = ['Clths', 'Coal', 'Util', 'Rtail']\n",
" coef_dict_temp['Beer.lead'] = ['Food', 'Clths', 'Coal']\n",
" coef_dict_temp['Smoke.lead'] = ['Txtls', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'Paper', 'Trans', 'Fin']\n",
" coef_dict_temp['Games.lead'] = ['Books', 'Clths', 'Coal', 'Fin']\n",
" coef_dict_temp['Books.lead'] = ['Games', 'Books', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Fin']\n",
" coef_dict_temp['Hshld.lead'] = ['Clths', 'Coal', 'Rtail']\n",
" coef_dict_temp['Clths.lead'] = ['Books', 'Clths', 'Chems', 'Steel', 'ElcEq', 'Carry', 'Coal', 'Oil', 'Util','Telcm', 'Servs', 'BusEq', 'Rtail']\n",
" # Running OLS for Clths against ['Clths', 'Coal', 'Oil', 'Servs', 'Rtail']\n",
" coef_dict_temp['Hlth.lead'] = ['Books', 'Mines', 'Coal', 'Util']\n",
" coef_dict_temp['Chems.lead'] = ['Clths']\n",
" coef_dict_temp['Txtls.lead'] = ['Clths', 'Autos', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
" coef_dict_temp['Cnstr.lead'] = ['Clths', 'Coal', 'Oil', 'Util', 'Trans', 'Rtail', 'Fin']\n",
" coef_dict_temp['Steel.lead'] = ['Fin']\n",
" coef_dict_temp['FabPr.lead'] = ['Trans', 'Fin']\n",
" coef_dict_temp['ElcEq.lead'] = ['Fin']\n",
" coef_dict_temp['Autos.lead'] = ['Hshld', 'Clths', 'Coal', 'Oil', 'Util', 'BusEq', 'Rtail', 'Fin']\n",
" coef_dict_temp['Carry.lead'] = ['Trans']\n",
" coef_dict_temp['Mines.lead'] = []\n",
" coef_dict_temp['Coal.lead'] = ['Beer', 'Smoke', 'Books', 'Autos', 'Coal', 'Oil', 'Paper', 'Rtail']\n",
" coef_dict_temp['Oil.lead'] = ['Beer', 'Hlth', 'Carry']\n",
" coef_dict_temp['Util.lead'] = ['Food', 'Beer', 'Smoke', 'Hshld', 'Hlth', 'Cnstr', 'FabPr', 'Carry', 'Mines', 'Oil', 'Util', 'Telcm', 'BusEq', 'Whlsl', 'Fin', 'Other']\n",
" coef_dict_temp['Telcm.lead'] = ['Beer', 'Smoke', 'Books', 'Hshld', 'Cnstr', 'Autos', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Meals', 'Fin']\n",
" coef_dict_temp['Servs.lead'] = ['Smoke', 'Books', 'Steel', 'Oil', 'Util', 'Fin']\n",
" coef_dict_temp['BusEq.lead'] = ['Smoke', 'Books', 'Util']\n",
" coef_dict_temp['Paper.lead'] = ['Clths', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
" coef_dict_temp['Trans.lead'] = ['Fin']\n",
" coef_dict_temp['Whlsl.lead'] = ['Food', 'Beer', 'Smoke', 'Books', 'Hlth', 'Carry', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'BusEq', 'Fin', 'Other']\n",
" # Running OLS for Whlsl against ['Food', 'Smoke', 'Books', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'Fin', 'Other']\n",
" coef_dict_temp['Rtail.lead'] = ['Rtail']\n",
" coef_dict_temp['Meals.lead'] = ['Smoke', 'Books', 'Clths', 'Steel', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Meals', 'Fin']\n",
" coef_dict_temp['Fin.lead'] = ['Fin']\n",
" coef_dict_temp['Other.lead'] = ['Clths', 'Fin']\n",
" \n",
"coef_dict_paper = []\n",
"for response in responses:\n",
" print(response, \" -> \", coef_dict_temp[response])\n",
" coef_dict_paper.append([predictor_reverse_dict[jstr] for jstr in coef_dict_temp[response]])\n",
"print(coef_dict_paper)"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Food.lead -> ['Clths', 'Coal', 'Util', 'Rtail']\n",
"Beer.lead -> ['Food', 'Clths', 'Coal']\n",
"Smoke.lead -> ['Txtls', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'Paper', 'Trans', 'Fin']\n",
"Games.lead -> ['Books', 'Clths', 'Coal', 'Fin']\n",
"Books.lead -> ['Games', 'Books', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Fin']\n",
"Hshld.lead -> ['Clths', 'Coal', 'Rtail']\n",
"Clths.lead -> ['Books', 'Clths', 'Chems', 'Steel', 'ElcEq', 'Carry', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'BusEq', 'Rtail']\n",
"Hlth.lead -> ['Books', 'Mines', 'Coal', 'Util']\n",
"Chems.lead -> ['Clths']\n",
"Txtls.lead -> ['Clths', 'Autos', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"Cnstr.lead -> ['Clths', 'Coal', 'Oil', 'Util', 'Trans', 'Rtail', 'Fin']\n",
"Steel.lead -> ['Fin']\n",
"FabPr.lead -> ['Trans', 'Fin']\n",
"ElcEq.lead -> ['Fin']\n",
"Autos.lead -> ['Hshld', 'Clths', 'Coal', 'Oil', 'Util', 'BusEq', 'Rtail', 'Fin']\n",
"Carry.lead -> ['Trans']\n",
"Mines.lead -> []\n",
"Coal.lead -> ['Beer', 'Smoke', 'Books', 'Autos', 'Coal', 'Oil', 'Paper', 'Rtail']\n",
"Oil.lead -> ['Beer', 'Hlth', 'Carry']\n",
"Util.lead -> ['Food', 'Beer', 'Smoke', 'Hshld', 'Hlth', 'Cnstr', 'FabPr', 'Carry', 'Mines', 'Oil', 'Util', 'Telcm', 'BusEq', 'Whlsl', 'Fin', 'Other']\n",
"Telcm.lead -> ['Beer', 'Smoke', 'Books', 'Hshld', 'Cnstr', 'Autos', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Meals', 'Fin']\n",
"Servs.lead -> ['Smoke', 'Books', 'Steel', 'Oil', 'Util', 'Fin']\n",
"BusEq.lead -> ['Smoke', 'Books', 'Util']\n",
"Paper.lead -> ['Clths', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"Trans.lead -> ['Fin']\n",
"Whlsl.lead -> ['Food', 'Beer', 'Smoke', 'Books', 'Hlth', 'Carry', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'BusEq', 'Fin', 'Other']\n",
"Rtail.lead -> ['Rtail']\n",
"Meals.lead -> ['Smoke', 'Books', 'Clths', 'Steel', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Meals', 'Fin']\n",
"Fin.lead -> ['Fin']\n",
"Other.lead -> ['Clths', 'Fin']\n",
"[[6, 17, 19, 26], [0, 6, 17], [9, 15, 16, 17, 18, 19, 20, 21, 23, 24, 28], [4, 6, 17, 28], [3, 4, 17, 18, 19, 21, 22, 26, 28], [6, 17, 26], [4, 6, 8, 11, 13, 15, 17, 18, 19, 20, 21, 22, 26], [4, 16, 17, 19], [6], [6, 14, 17, 18, 26, 28], [6, 17, 18, 19, 24, 26, 28], [28], [24, 28], [28], [5, 6, 17, 18, 19, 22, 26, 28], [24], [], [1, 2, 4, 14, 17, 18, 23, 26], [1, 7, 15], [0, 1, 2, 5, 7, 10, 12, 15, 16, 18, 19, 20, 22, 25, 28, 29], [1, 2, 4, 5, 10, 14, 15, 16, 17, 18, 19, 21, 22, 26, 27, 28], [2, 4, 11, 18, 19, 28], [2, 4, 19], [6, 17, 18, 26, 28], [28], [0, 1, 2, 4, 7, 15, 17, 18, 19, 20, 21, 22, 28, 29], [26], [2, 4, 6, 11, 15, 17, 18, 19, 21, 22, 27, 28], [28], [6, 28]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "01Vojt0-fkYe",
"outputId": "86c6596f-28fd-4893-89d3-2cb3b3074b0d",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 592
}
},
"source": [
"# Now just try a simple linear regression on selected features, the idea here is to obtain the same lasso results as the paper\n",
"def predict_with_subsets(X, Y, create_model, coef_dict, verbose=False):\n",
" \"\"\"evaluate subset selection, pass a model function and subsets, compute avg R-squared\"\"\"\n",
" global responses\n",
"\n",
" nrows, ncols = Y.shape\n",
" model = create_model()\n",
" \n",
" scores = []\n",
" for response_col in range(ncols):\n",
" y = Y[:,response_col]\n",
"\n",
" \n",
" if not coef_dict[response_col]:\n",
" if verbose:\n",
" print(\"No coefs selected for \" + responses[response_col])\n",
" # print(\"---\")\n",
" continue\n",
"\n",
" predcols = coef_dict[response_col]\n",
" model.fit(X[:, predcols], y)\n",
" y_pred = model.predict(X[:, predcols])\n",
" score = r2_score(y, y_pred)\n",
" scores.append(score)\n",
" if verbose:\n",
" print (\"In-sample R-squared: %.2f%% for %s against %s\" % (score*100, responses[response_col], \n",
" str([predictors[i] for i in coef_dict[response_col]])))\n",
"# print(\"---\")\n",
" \n",
" if verbose:\n",
" print(\"Mean R-squared: %.2f%%\" % (100 * np.mean(np.array(scores))))\n",
" return np.mean(np.array(scores))\n",
" \n",
"predict_with_subsets(X, Y, LinearRegression, coef_dict_paper, verbose=True)\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"In-sample R-squared: 2.24% for Food.lead against ['Clths', 'Coal', 'Util', 'Rtail']\n",
"In-sample R-squared: 2.52% for Beer.lead against ['Food', 'Clths', 'Coal']\n",
"In-sample R-squared: 6.55% for Smoke.lead against ['Txtls', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'Paper', 'Trans', 'Fin']\n",
"In-sample R-squared: 5.05% for Games.lead against ['Books', 'Clths', 'Coal', 'Fin']\n",
"In-sample R-squared: 6.30% for Books.lead against ['Games', 'Books', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Fin']\n",
"In-sample R-squared: 2.97% for Hshld.lead against ['Clths', 'Coal', 'Rtail']\n",
"In-sample R-squared: 7.82% for Clths.lead against ['Books', 'Clths', 'Chems', 'Steel', 'ElcEq', 'Carry', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'BusEq', 'Rtail']\n",
"In-sample R-squared: 2.68% for Hlth.lead against ['Books', 'Mines', 'Coal', 'Util']\n",
"In-sample R-squared: 0.78% for Chems.lead against ['Clths']\n",
"In-sample R-squared: 7.91% for Txtls.lead against ['Clths', 'Autos', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"In-sample R-squared: 5.15% for Cnstr.lead against ['Clths', 'Coal', 'Oil', 'Util', 'Trans', 'Rtail', 'Fin']\n",
"In-sample R-squared: 1.28% for Steel.lead against ['Fin']\n",
"In-sample R-squared: 1.57% for FabPr.lead against ['Trans', 'Fin']\n",
"In-sample R-squared: 0.80% for ElcEq.lead against ['Fin']\n",
"In-sample R-squared: 6.13% for Autos.lead against ['Hshld', 'Clths', 'Coal', 'Oil', 'Util', 'BusEq', 'Rtail', 'Fin']\n",
"In-sample R-squared: 2.32% for Carry.lead against ['Trans']\n",
"No coefs selected for Mines.lead\n",
"In-sample R-squared: 2.84% for Coal.lead against ['Beer', 'Smoke', 'Books', 'Autos', 'Coal', 'Oil', 'Paper', 'Rtail']\n",
"In-sample R-squared: 2.52% for Oil.lead against ['Beer', 'Hlth', 'Carry']\n",
"In-sample R-squared: 7.86% for Util.lead against ['Food', 'Beer', 'Smoke', 'Hshld', 'Hlth', 'Cnstr', 'FabPr', 'Carry', 'Mines', 'Oil', 'Util', 'Telcm', 'BusEq', 'Whlsl', 'Fin', 'Other']\n",
"In-sample R-squared: 5.18% for Telcm.lead against ['Beer', 'Smoke', 'Books', 'Hshld', 'Cnstr', 'Autos', 'Carry', 'Mines', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Rtail', 'Meals', 'Fin']\n",
"In-sample R-squared: 2.87% for Servs.lead against ['Smoke', 'Books', 'Steel', 'Oil', 'Util', 'Fin']\n",
"In-sample R-squared: 2.75% for BusEq.lead against ['Smoke', 'Books', 'Util']\n",
"In-sample R-squared: 3.24% for Paper.lead against ['Clths', 'Coal', 'Oil', 'Rtail', 'Fin']\n",
"In-sample R-squared: 1.32% for Trans.lead against ['Fin']\n",
"In-sample R-squared: 7.43% for Whlsl.lead against ['Food', 'Beer', 'Smoke', 'Books', 'Hlth', 'Carry', 'Coal', 'Oil', 'Util', 'Telcm', 'Servs', 'BusEq', 'Fin', 'Other']\n",
"In-sample R-squared: 1.61% for Rtail.lead against ['Rtail']\n",
"In-sample R-squared: 7.90% for Meals.lead against ['Smoke', 'Books', 'Clths', 'Steel', 'Carry', 'Coal', 'Oil', 'Util', 'Servs', 'BusEq', 'Meals', 'Fin']\n",
"In-sample R-squared: 1.70% for Fin.lead against ['Fin']\n",
"In-sample R-squared: 2.69% for Other.lead against ['Clths', 'Fin']\n",
"Mean R-squared: 3.86%\n"
],
"name": "stdout"
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"0.03862278631691254"
]
},
"metadata": {
"tags": []
},
"execution_count": 16
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "eJqE_OyzfkYj",
"outputId": "b8705050-4f39-4e3e-ba07-9c4521a97ee2",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"# use all predictors - higher in-sample R-squared (almost a universal)\n",
"coef_dict_all = []\n",
"for _ in responses:\n",
" coef_dict_all.append(range(len(predictors)))\n",
"predict_with_subsets(X, Y, LinearRegression, coef_dict_all, verbose=False)\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"0.0663748688823735"
]
},
"metadata": {
"tags": []
},
"execution_count": 17
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "xlRxXibmfkYn",
"outputId": "5bf8514c-f254-4c4b-e0fe-48bc7a4a139b",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 606
}
},
"source": [
"# first iteration will train up to including 196911\n",
"# will use 196912 to predict 197001\n",
"# 1970101 will be first month of performance to use\n",
"# train on first 121 months up to 196912 (0:120), put first prediction in P[121] (122nd row)\n",
"# first month of performance will be 197002\n",
"FIRST_TRAIN_MONTHS = 121\n",
"FIRST_PREDICT_MONTH = FIRST_TRAIN_MONTHS # This is stupid but keeps my head straight\n",
"\n",
"print(X[FIRST_TRAIN_MONTHS])\n",
"print(data.iloc[FIRST_TRAIN_MONTHS][:30])"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"[ -3.34 -1.95 -7.59 -7.76 -12.05 -7.5 -5.69 -7.71 -7.37 -5.26\n",
" -9.84 -6.31 -7.15 -6.89 -9.35 -12.49 -2.34 -0.77 -12.16 -4.83\n",
" -3.16 -11.17 -9.73 -8.89 -8.17 -8.28 -6.31 -13.12 -9.78 -6.2 ]\n",
"Food -3.34\n",
"Beer -1.95\n",
"Smoke -7.59\n",
"Games -7.76\n",
"Books -12.05\n",
"Hshld -7.50\n",
"Clths -5.69\n",
"Hlth -7.71\n",
"Chems -7.37\n",
"Txtls -5.26\n",
"Cnstr -9.84\n",
"Steel -6.31\n",
"FabPr -7.15\n",
"ElcEq -6.89\n",
"Autos -9.35\n",
"Carry -12.49\n",
"Mines -2.34\n",
"Coal -0.77\n",
"Oil -12.16\n",
"Util -4.83\n",
"Telcm -3.16\n",
"Servs -11.17\n",
"BusEq -9.73\n",
"Paper -8.89\n",
"Trans -8.17\n",
"Whlsl -8.28\n",
"Rtail -6.31\n",
"Meals -13.12\n",
"Fin -9.78\n",
"Other -6.20\n",
"Name: 197001, dtype: float64\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "GnbBd49wfkYt"
},
"source": [
"class PredictWrapper():\n",
" \"\"\"Wrap an sklearn model e.g. LinearRegression to fit, predict all vars as a vector, \n",
" match the way our Keras model will do it\"\"\"\n",
"\n",
" def __init__(self, create_model, coef_dict, fit_missing=None):\n",
" self.create_model = create_model \n",
" self.coef_dict = coef_dict\n",
" self.fit_missing = fit_missing\n",
" self.models = []\n",
" \n",
" def fit(self, X_fit, Y_fit, verbose=False):\n",
" \n",
" self.nrows, self.ycols = Y_fit.shape\n",
" self.models = []\n",
" # fit model for each column\n",
" for responsecol in range(self.ycols):\n",
" if self.coef_dict[responsecol]:\n",
" # column indexes to fit against each other\n",
" predcols = self.coef_dict[responsecol]\n",
" else: # no columns selected\n",
" if not self.fit_missing:\n",
" # default: don't fit if no predictors selected\n",
" self.models.append(None)\n",
" #print(self.models[-1])\n",
" continue\n",
" elif self.fit_missing == \"mean\":\n",
" # append a numeric value to use\n",
" self.models.append(np.mean(Y_fit[:,responsecol]))\n",
" #print(self.models[-1])\n",
" continue\n",
" elif self.fit_missing == \"all\":\n",
" # predcols = all columns\n",
" predcols = range(X_fit.shape[1])\n",
"\n",
" model = self.create_model() # create 1 sklearn model for each column\n",
" model.fit(X_fit[:, predcols], Y_fit[:,responsecol])\n",
" if verbose:\n",
" print(\"fit on \" + str(X_fit[:, predcols].shape) + str(predcols))\n",
" print(model.coef_)\n",
" \n",
" self.models.append(model)\n",
" \n",
" #debug\n",
" #print(responsecol)\n",
" #print(X_fit[:, predcols])\n",
" #print(\"=====\")\n",
" #print(Y_fit[:,responsecol])\n",
" #print(\"=====\")\n",
" #print(self.model.coef_)\n",
" #print(self.model.intercept_)\n",
" #print(\"=====\") \n",
"\n",
" def predict(self, X_predict, verbose=False):\n",
"\n",
" predictions = []\n",
" nrows = X_predict.shape[0]\n",
"\n",
" for responsecol in range(self.ycols):\n",
" #print (type(self.models[responsecol]))\n",
" if type(self.models[responsecol]) == np.float64:\n",
" pred = np.array([self.models[responsecol]] * nrows).reshape(nrows,1)\n",
" predictions.append(pred)\n",
" sys.stdout.write('\\010#')\n",
" elif not self.models[responsecol]: \n",
" # don't predict\n",
" predictions.append(np.array([np.nan] * nrows ).reshape(nrows,1))\n",
" sys.stdout.write('\\010N')\n",
" else:\n",
" predcols = self.coef_dict[responsecol]\n",
" y_pred = self.models[responsecol].predict(X_predict[:,predcols])\n",
" if verbose:\n",
" print(\"predict on\" + str(X_predict[:, predcols].shape) + str(predcols))\n",
" print(y_pred)\n",
" predictions.append(y_pred.reshape(nrows,1))\n",
" \n",
" return np.hstack(predictions)\n",
" \n",
" "
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "CnUxMdcdfkYw"
},
"source": [
"### BacktestModel class to abstract walk-forward validation and backtesting workflow from modeling, portfolio construction, reporting"
]
},
{
"cell_type": "code",
"metadata": {
"id": "2yXXF1cUfkYx"
},
"source": [
"# typical pipeline\n",
"# backtestmodel = BacktestModel(X, # predictors\n",
"# Y, # responses\n",
"# create_model=LinearRegression, # create_model which returns a model (needed for 'timestep' which creates different model each timestep)\n",
"# # or model = someKerasModel, # initialized model that supports fit(X,Y), predict(X) , predicts an entire row,\n",
"# coef_dict_param=coef_dict_paper, # how to map predictors to responses (\"all\", \"timestep\", or a list of lists)\n",
"# startindex=FIRST_TRAIN_MONTHS, # initial training for backtest\n",
"# fit_missing='mean', # what to do when no predictors are selected in coef_dict_param - use all predictors, use historical mean, use np.nan\n",
"# scaler = None) # scaling function like MinMaxScaler\n",
"\n",
"# backtestmodel.gen_predictions(verbose=False) # starting from startindex, step through X,Y month by month, fit up to current month, predict next month, store prediction in self.P\n",
"# backtestmodel.walkforward_xval(n_splits=5, verbose=True) # calls gen_predictions with a large step, fits and predicts one large fold at a time (useful to cross-validate quickly)\n",
"# backtestmodel.evaluate_predictions() # report metrics on prediction : MSE etc. #TODO: support custom calcs before/after/instead of default calcs\n",
"# backtestmodel.gen_returns(calc_returns, verbose=True) # takes a function that returns portfolio returns based on self.P, stores in self.R\n",
"# backtestmodel.report_returns(start_date=start_date_str, freq='M') # calc cumulative perf and report (TODO: allow it to take a reporting function to run before/after/in place of default report)\n",
"# backtestmodel.evaluate_quantiles(chart=True, verbose=True) # report quantile metrics # TODO: make this a custom calc passed into evaluate_predictions\n",
"\n",
"class BacktestModel():\n",
" \n",
" def __init__(self, \n",
" X, # predictors\n",
" Y, # responses\n",
" model=None, # model that supports fit(X,Y), predict(X) , predicts an entire row,\n",
" create_model=None, # or create_model which returns a model (needed for 'timestep' but slows down so pass model if dynamic not needed)\n",
" coef_dict_param=\"all\", # mapping of predictors to responses (\"all\", \"timestep\", or a list of lists)\n",
" startindex=FIRST_TRAIN_MONTHS,\n",
" scaler=None,\n",
" fit_missing=None):\n",
" \n",
" self.Xrows, self.Xcols = X.shape\n",
" self.Yrows, self.Ycols = Y.shape\n",
" \n",
" if self.Xrows != self.Yrows:\n",
" raise(ValueError, \"Shapes differ: X %s, Y %s\" % (str(X.shape), str(Y.shape))) \n",
" \n",
" self.X = X\n",
" self.Y = Y\n",
" self.Xscale = X.copy()\n",
" self.Yscale = Y.copy()\n",
"\n",
" if scaler:\n",
" print(\"scaler: %s \" %str(scaler))\n",
" # by rows\n",
" # MinMaxScaler: each row (min->0, max->1) \n",
" # StandardScaler: each row (mean->0, SD->1) \n",
" # self.Xscale = scaler().fit_transform(self.Xscale.transpose()).transpose()\n",
" # self.Yscale = scaler().fit_transform(self.Yscale.transpose()).transpose()\n",
" # by cols\n",
" # MinMaxScaler: each col (min->0, max->1) \n",
" # StandardScaler: each col (mean->0, SD->1) \n",
" self.Xscale = scaler().fit_transform(self.Xscale)\n",
" self.Yscale = scaler().fit_transform(self.Yscale)\n",
" \n",
" self.model = model\n",
" self.create_model = create_model\n",
" self.coef_dict_param = coef_dict_param\n",
" self.startindex = startindex\n",
" self.fit_missing = fit_missing\n",
"\n",
" def fit_predict(self, ntrain, npredict=1, verbose=False):\n",
" \"\"\"for backtest, train model using Y v. X \n",
" train on first ntrain rows. if ntrain=121, fit 0:120\n",
" predict following npredict rows \n",
" if npredict=1, predict row 121\n",
" if npredict=12, predict rows 121-132\n",
" \"\"\"\n",
" \n",
" # fit first ntrain rows\n",
" X_fit = self.Xscale[:ntrain] # e.g. 0:120\n",
" Y_fit = self.Yscale[:ntrain]\n",
" # predict npredict rows\n",
" X_predict = self.Xscale[ntrain:ntrain+npredict] # 121-122\n",
" X_predict = X_predict.reshape(npredict,self.Xcols)\n",
" \n",
" # if no coef_dict select predictors into coef_dict\n",
" if self.coef_dict_param == \"timestep\":\n",
" msg = \"Performing subset selection\"\n",
" coef_dict = subset_selection(X_fit, Y_fit, LassoLarsIC(criterion='aic'))\n",
" # if coef_dict == \"all\" use all predictors for each response \n",
" elif self.coef_dict_param == 'all':\n",
" msg = \"Using all predictors\"\n",
" coef_dict = [range(self.Xcols) for _ in range(self.ycols)]\n",
" else: # should check valid dict\n",
" msg = \"Using coef_dict predictors\"\n",
" coef_dict = self.coef_dict_param\n",
" if verbose: \n",
" print(msg)\n",
"\n",
" if self.create_model:\n",
" self.model = PredictWrapper(self.create_model, coef_dict, fit_missing=self.fit_missing)\n",
" \n",
" self.model.fit(X_fit, Y_fit, verbose=verbose)\n",
" return self.model.predict(X_predict, verbose=verbose)\n",
"\n",
" # predict all months\n",
" # initial train_months = 120 -> train first model on 120 rows\n",
" # first prediction will be in P[120] (121st row)\n",
" # step = 6 -> predict following 6 rows, then step forward 6 months at a time\n",
" # initialize predictions matrix self.P\n",
" \n",
" # use either step or folds\n",
" # step, do range(self.startindex, nrows, step)\n",
" # folds, at each fold train 0:startfold, predict startfold+1:endfold\n",
" # store only out-of-sample predictions in P, calc out-of-sample MSE\n",
" \n",
" # using a step > 1 or folds is quicker, for quicker xval, or to speed up by not estimating model at each timestep\n",
"\n",
" def gen_predictions(self,\n",
" step=1, \n",
" splits=None,\n",
" verbose=False):\n",
"\n",
" self.P = np.zeros_like(self.Y)\n",
"\n",
" progress_i = 0\n",
" self.nrows, self.ycols = Y.shape\n",
" \n",
" if splits:\n",
" month_indexes = splits[:-1] # last index is nrows\n",
" else:\n",
" # create list of steps\n",
" month_indexes = list(range(self.startindex, nrows, step))\n",
" steps = [month_indexes[i+1]-month_indexes[i] for i in range(len(month_indexes)-1)]\n",
" # last step -> end\n",
" steps.append(self.nrows - month_indexes[-1])\n",
" \n",
" if verbose:\n",
" print (\"Steps: \" + str(month_indexes))\n",
"\n",
" for month_index, forecast_rows in zip(month_indexes, steps):\n",
" if verbose:\n",
" print(\"Training on first %d rows (%d:%d), putting predictions in rows %s\" % (month_index, \n",
" 0, month_index-1, \n",
" str(range(month_index,month_index+forecast_rows))))\n",
" predictions = self.fit_predict(month_index, forecast_rows, verbose=False)\n",
" \n",
" first_pred_row = month_index\n",
" for row_index in range(forecast_rows):\n",
" self.P[first_pred_row+row_index] = predictions[row_index]\n",
" sys.stdout.write('.')\n",
" progress_i += 1\n",
" if progress_i % 80 == 0:\n",
" print(\"\")\n",
" print(\"%s Still training step %d of %d\" % (time.strftime(\"%H:%M:%S\"), progress_i, len(month_indexes)))\n",
" sys.stdout.flush()\n",
" print(\"\")\n",
" \n",
"\n",
" def evaluate_predictions(self):\n",
" \n",
" # evaluate prediction (can move to separate function)\n",
" msetemp = (self.P[self.startindex:]-self.Yscale[self.startindex:])**2\n",
" #remove nans\n",
" msetemp = msetemp[~np.isnan(msetemp)]\n",
" self.mse = np.mean(msetemp)\n",
" print(\"OOS MSE across all predictions: %.4f\" % self.mse)\n",
" self.model.fit(self.Xscale, self.Yscale)\n",
" Y_pred = self.model.predict(self.Xscale)\n",
" self.in_sample_mse = np.mean((Y_pred - self.Yscale) ** 2)\n",
" print(\"In-sample MSE: %.4f\" % self.in_sample_mse)\n",
"\n",
" # force unpredicted ys to be nans, then remove nans\n",
" vartemp = self.Yscale[self.startindex:] - self.P[self.startindex:] + self.P[self.startindex:]\n",
" vartemp = vartemp[~np.isnan(vartemp)]\n",
" y_variance = np.var(vartemp[self.startindex:])\n",
" print(\"Variance: %.4f\" % (y_variance))\n",
" print(\"R-squared: %.4f\" % (1- self.mse/y_variance))\n",
" \n",
" return(self.mse)\n",
"\n",
" def evaluate_quantiles(self, chart=False, verbose=False):\n",
" \n",
" self.P_quantiles = np.zeros_like(self.P)\n",
" self.Y_quantiles = np.zeros_like(self.Y)\n",
" self.kendalltaus = []\n",
" self.ktpvals = []\n",
" # compute score for predicted quantiles vs. actual (expected) quantiles\n",
" N_QUANTILES=5\n",
" for row in range(self.startindex, self.P_quantiles.shape[0]):\n",
" #print(self.P[row])\n",
" self.P_quantiles[row] = pd.qcut(self.P[row], N_QUANTILES, range(N_QUANTILES))\n",
" self.Y_quantiles[row] = pd.qcut(self.Y[row], N_QUANTILES, range(N_QUANTILES))\n",
" kt, p_val = kendalltau(self.P[row], self.Y[row])\n",
" self.kendalltaus.append(kt)\n",
" self.ktpvals.append(p_val)\n",
"\n",
" self.kendalltau = np.mean(self.kendalltaus)\n",
" self.kendalltau_pvalue = np.mean(self.ktpvals) \n",
" print(\"Avg rank correlation (Kendall's tau): %.4f (Expected: 0)\" % (self.kendalltau))\n",
" pred_quantiles = self.P_quantiles[self.startindex:]\n",
" true_quantiles = self.Y_quantiles[self.startindex:]\n",
"\n",
" nrows, ncols = pred_quantiles.shape\n",
"\n",
" pred_quantiles = pred_quantiles.reshape(nrows*ncols)\n",
" true_quantiles = true_quantiles.reshape(nrows*ncols)\n",
" self.quintile_accuracy = accuracy_score(pred_quantiles, true_quantiles)\n",
" print(\"5-quintile accuracy: %.4f (Expected: 0.2)\" % (self.quintile_accuracy))\n",
" \n",
" pred_direction = np.zeros(nrows*ncols)\n",
" true_direction = np.zeros(nrows*ncols)\n",
" for i in range(nrows*ncols):\n",
" if pred_quantiles[i] == 4:\n",
" pred_direction[i] = 1\n",
" elif pred_quantiles[i] == 0:\n",
" pred_direction[i] = -1\n",
" if true_quantiles[i] == 4:\n",
" true_direction[i] = 1\n",
" elif true_quantiles[i] == 0:\n",
" true_direction[i] = -1\n",
" self.directional_accuracy = accuracy_score(pred_direction, true_direction)\n",
" print(\"Long/short/flat accuracy: %.4f (Expected: 0.44)\" % (self.directional_accuracy))\n",
" \n",
" nrows = nrows * ncols\n",
" \n",
" conf_mat_expected = np.array([[0.64, 0.16],[0.16, 0.04]])*nrows\n",
"\n",
" myscores = []\n",
" for q in range(5):\n",
" temp_pred = pred_quantiles == q\n",
" temp_actual = true_quantiles == q\n",
" conf_mat5 = confusion_matrix(temp_pred, temp_actual)\n",
" diff_mat = conf_mat5 - conf_mat_expected\n",
" if verbose:\n",
" print(\"Confusion matrix for quantile %d\" % q)\n",
" print(conf_mat5)\n",
" cstmp, cspvtmp = chisquare(conf_mat5.reshape(4), conf_mat_expected.reshape(4))\n",
" print(\"Chi-square: %.4f (p-value: %.8f)\" % (cstmp, cspvtmp))\n",
"\n",
" # probably no valid statistical interpretation but \n",
" # average of improvement in true positive % and true negative %\n",
" myscore = diff_mat[1][1]\n",
" myscores.append(myscore)\n",
"\n",
" # sum of true positive for top and bottom quintiles\n",
" self.excess_tp = myscores[0] + myscores[4]\n",
" print(\"Excess true positive in quintiles 1 + 5: %f\" % (self.excess_tp))\n",
"\n",
" conf_mat = confusion_matrix(pred_quantiles, true_quantiles)\n",
" if chart:\n",
" fig, ax = plt.subplots(figsize=(10,10))\n",
" sns.heatmap(conf_mat, annot=True, fmt='d')\n",
" plt.ylabel('Actual Quintile')\n",
" plt.xlabel('Predicted Quintile')\n",
" plt.show()\n",
" \n",
" return None\n",
"\n",
" def walkforward_xval (self, n_splits=5, verbose=False):\n",
" \"\"\"quick and dirty genreturns, with a step\"\"\"\n",
" # generate k-folds\n",
" kf = KFold(n_splits=n_splits)\n",
" kf.get_n_splits(X)\n",
" last_indexes = []\n",
" for train_index, test_index in kf.split(X):\n",
" # use test_index as last index to train\n",
" last_index = test_index[-1] + 1\n",
" last_indexes.append(last_index)\n",
" print(\"%s Generate splits %s\" % (time.strftime(\"%H:%M:%S\"), str([i for i in last_indexes])))\n",
" #override startindex\n",
" self.startindex = last_indexes[0]\n",
" return self.gen_predictions(splits=last_indexes, verbose=verbose)\n",
" \n",
" def gen_returns(self, port_returns_func, verbose=False):\n",
"\n",
" self.R = np.zeros(self.P.shape[0])\n",
" first_pred_month=self.startindex\n",
" \n",
" indcount = [0] * self.ycols\n",
" longcount = [0] * self.ycols\n",
" shortcount = [0] * self.ycols\n",
" \n",
" for month_index in range(first_pred_month, nrows-1):\n",
" return_month = month_index + 1\n",
" port_return, long_indexes, short_indexes = port_returns_func(self.P[month_index], \n",
" self.X[return_month])\n",
" self.R[return_month] = port_return\n",
" \n",
" for i in long_indexes:\n",
" indcount[i] += 1\n",
" longcount[i] += 1\n",
" for i in short_indexes:\n",
" indcount[i] += 1\n",
" shortcount[i] += 1\n",
" if verbose:\n",
" for i in range(len(responses)):\n",
" print(\"%s: long %d times, short %d times, total %d times\" % (predictors[i], \n",
" longcount[i], \n",
" shortcount[i], \n",
" indcount[i]))\n",
" return self.R\n",
"\n",
" def report_returns(self, start_date='01/01/1970', freq='M'):\n",
"\n",
" first_pred_month=self.startindex \n",
" self.results = self.R[first_pred_month:]\n",
" nmonths = self.results.shape[0]\n",
" nyears = nmonths/12.0\n",
" index = pd.date_range(start_date,periods=nmonths, freq=freq)\n",
" perfdata = pd.DataFrame(self.results,index=index,columns=['Returns'])\n",
" perfdata['Equity'] = 100 * np.cumprod(1 + self.results / 100)\n",
" self.cumulative_return = perfdata['Equity']\n",
" self.mean_monthly_return_annualized = np.mean(1 + self.results/100) ** 12 - 1\n",
" self.mean_return = (self.cumulative_return[-1]/100) ** (1.0/nyears) - 1\n",
" self.annualized_vol = np.std(self.results/100) * np.sqrt(12.0)\n",
" self.sharpe = self.mean_monthly_return_annualized/self.annualized_vol\n",
" print(\"Mean return: %.3f%%\" % (self.mean_return * 100 ))\n",
" #print(\"Mean monthly annualized return: %.3f%%\" % (self.mean_monthly_return_annualized * 100 ))\n",
" #print(\"Monthly annualized volatility: %.3f%%\" % (self.annualized_vol * 100))\n",
" print(\"Monthly Sharpe ratio: %.3f\" % (self.sharpe))\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "tdXQ-om1fkY0"
},
"source": [
"# return calculation passed to gen_returns\n",
"# which 6 (40/5) portfolios to go long on and which to go short on.\n",
"\n",
"NUMSTOCKS = 6 # top quintile (and bottom)\n",
"\n",
"def calc_returns(prediction_row, return_row, numstocks=NUMSTOCKS, verbose=False):\n",
"\n",
" # ensure nan sorts to top for shorts\n",
" short_sort_array = [999999 if np.isnan(x) else x for x in prediction_row]\n",
" # pick bottom numstocks\n",
" select_array = np.argsort(short_sort_array)\n",
" short_indexes = select_array[:numstocks]\n",
"\n",
" # ensure nan sorts to bottom for longs\n",
" long_sort_array = [-999999 if np.isnan(x) else x for x in prediction_row]\n",
" # pick top numstocks\n",
" select_array = np.argsort(long_sort_array)\n",
" long_indexes = select_array[-numstocks:]\n",
" \n",
" if verbose:\n",
" print(\"Longs: %s\" %(str([(i,prediction_row[i]) for i in long_indexes])))\n",
" print(\"Shorts: %s\" %(str([(i,prediction_row[i]) for i in short_indexes])))\n",
"\n",
" # compute equal weighted long/short return\n",
" return np.mean(return_row[long_indexes])/2 - np.mean(return_row[short_indexes])/2, long_indexes, short_indexes\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "Co4uzjyNfkY3",
"outputId": "d932a53c-9bfe-4217-856a-716864c98c84",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"start_date_int = data.index[FIRST_TRAIN_MONTHS]\n",
"start_year, start_month = start_date_int // 100, start_date_int % 100\n",
"start_date_str = \"%02d/%02d/%d\" % (start_month, 1, start_year)\n",
"start_date_str"
],
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"'01/01/1970'"
]
},
"metadata": {
"tags": []
},
"execution_count": 22
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "Vu609zIpfkY8",
"outputId": "a8c5bf5d-6ac1-4e05-f6eb-d8c732cd1755",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 329
}
},
"source": [
"# test fit_predict\n",
"backtestmodel = BacktestModel(X, Y, create_model=LinearRegression, coef_dict_param=coef_dict_all, startindex=FIRST_TRAIN_MONTHS)\n",
"print(backtestmodel.fit_predict(121, npredict=3, verbose=False))\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"[[ -4.70219919 -5.3073358 -3.72029191 -12.42448745 -6.62775756\n",
" -2.90316148 -6.79960146 -2.23172984 -5.75101181 -6.66276641\n",
" -5.75265368 -7.71979359 -6.57864566 -4.32124795 -5.0355927\n",
" -5.92230241 -4.76675177 -1.96315925 -3.43369206 -2.30343164\n",
" -3.72794445 -2.91917105 -5.27753906 -6.40474001 -6.85223288\n",
" -10.16508667 -4.69016977 -8.8042513 -5.4481542 -6.40122815]\n",
" [ -1.09819574 0.33751522 1.47276575 -7.65291563 -0.40550754\n",
" -4.96855817 -1.82873168 -3.4663124 -2.05857985 -0.68158685\n",
" -1.54307573 -2.74859589 -2.04412571 -1.77673237 -3.39612781\n",
" -4.76047089 -0.65055072 -5.08513341 1.95082965 -2.60578312\n",
" -5.09137205 -1.72203771 -3.31591182 -1.94755286 -1.38046013\n",
" -2.75841651 -0.96353404 -6.81674253 1.34059086 -1.59466739]\n",
" [ -1.96144894 -0.87682739 -3.02833064 0.58137733 -0.02056567\n",
" 1.67143038 -0.44895783 -1.70395859 -0.63283007 -0.4731534\n",
" -0.71228211 -3.61106494 -1.93572984 -0.64937617 -1.09751999\n",
" 0.24726352 -0.37303973 -1.04141371 2.1679461 -0.55736749\n",
" 0.76975122 0.67561178 1.62692312 -1.12079845 -1.07373008\n",
" -0.27905898 1.55099516 -3.06722504 -0.32196075 0.5859896 ]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"scrolled": false,
"id": "vmVhPVxyfkZB",
"outputId": "52ecb385-ca77-472e-e187-5aa127947733",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 156
}
},
"source": [
"# test model on our calculated coef_dict\n",
"# bad methodology, introduces snooping\n",
"# selects LASSO vars over whole timespan\n",
"# uses selected vars to do OLS backtest\n",
"# included as an example of what not to do\n",
"backtestmodel = BacktestModel(X, Y, \n",
" create_model=LinearRegression, \n",
" coef_dict_param=coef_dict_paper, # Feed paper predictors\n",
" startindex=FIRST_TRAIN_MONTHS,\n",
" fit_missing='mean',\n",
" scaler = None)\n",
"backtestmodel.gen_predictions(verbose=False)\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\n",
"14:47:21 Still training step 80 of 563\n",
"\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\n",
"14:47:22 Still training step 160 of 563\n",
"\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\n",
"14:47:24 Still training step 240 of 563\n",
"\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\n",
"14:47:25 Still training step 320 of 563\n",
"\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\n",
"14:47:27 Still training step 400 of 563\n",
"\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\n",
"14:47:28 Still training step 480 of 563\n",
"\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\b#.\n",
"14:47:30 Still training step 560 of 563\n",
"\b#.\b#.\b#.\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "exH4YgZyct8k"
},
"source": [
""
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "zvlA7Ea0CqGA",
"outputId": "2a4d6b22-b1c5-4d29-8f99-2de1b356a289",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"\n",
"backtestmodel.gen_returns(calc_returns, verbose=True)\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Food: long 93 times, short 37 times, total 130 times\n",
"Beer: long 122 times, short 94 times, total 216 times\n",
"Smoke: long 211 times, short 112 times, total 323 times\n",
"Games: long 147 times, short 125 times, total 272 times\n",
"Books: long 126 times, short 107 times, total 233 times\n",
"Hshld: long 81 times, short 72 times, total 153 times\n",
"Clths: long 195 times, short 172 times, total 367 times\n",
"Hlth: long 126 times, short 110 times, total 236 times\n",
"Chems: long 26 times, short 125 times, total 151 times\n",
"Txtls: long 160 times, short 128 times, total 288 times\n",
"Cnstr: long 92 times, short 124 times, total 216 times\n",
"Steel: long 4 times, short 180 times, total 184 times\n",
"FabPr: long 33 times, short 62 times, total 95 times\n",
"ElcEq: long 45 times, short 16 times, total 61 times\n",
"Autos: long 87 times, short 117 times, total 204 times\n",
"Carry: long 106 times, short 76 times, total 182 times\n",
"Mines: long 132 times, short 102 times, total 234 times\n",
"Coal: long 226 times, short 183 times, total 409 times\n",
"Oil: long 160 times, short 137 times, total 297 times\n",
"Util: long 161 times, short 182 times, total 343 times\n",
"Telcm: long 118 times, short 163 times, total 281 times\n",
"Servs: long 149 times, short 137 times, total 286 times\n",
"BusEq: long 106 times, short 123 times, total 229 times\n",
"Paper: long 50 times, short 107 times, total 157 times\n",
"Trans: long 39 times, short 56 times, total 95 times\n",
"Whlsl: long 168 times, short 147 times, total 315 times\n",
"Rtail: long 72 times, short 62 times, total 134 times\n",
"Meals: long 220 times, short 178 times, total 398 times\n",
"Fin: long 56 times, short 21 times, total 77 times\n",
"Other: long 61 times, short 117 times, total 178 times\n"
],
"name": "stdout"
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"array([ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,\n",
" 0.00000000e+00, 0.00000000e+00, 6.60000000e-01, -8.75000000e-01,\n",
" 4.76333333e+00, 3.80833333e+00, 2.68166667e+00, -8.15000000e-01,\n",
" 1.34583333e+00, 2.10583333e+00, -1.06666667e+00, 9.33333333e-02,\n",
" -1.12333333e+00, 2.42333333e+00, 1.16000000e+00, 1.71250000e+00,\n",
" -1.41000000e+00, 6.67500000e-01, 1.54583333e+00, 9.75000000e-01,\n",
" -2.19000000e+00, 6.77500000e-01, 7.33333333e-02, 5.50000000e-01,\n",
" -1.61083333e+00, 1.90666667e+00, -1.94166667e-01, 8.91666667e-02,\n",
" 1.16416667e+00, 5.38333333e-01, 2.58333333e-01, -1.40000000e-01,\n",
" 2.24000000e+00, -9.40000000e-01, 1.36750000e+00, 1.05416667e+00,\n",
" -1.14083333e+00, -1.19750000e+00, 3.91916667e+00, 1.20333333e+00,\n",
" 2.25000000e+00, 1.79666667e+00, 3.38333333e+00, -2.58583333e+00,\n",
" 1.07500000e-01, 1.46750000e+00, 1.60166667e+00, 5.13666667e+00,\n",
" 4.07583333e+00, -2.61750000e+00, 6.66666667e-01, -1.68500000e+00,\n",
" 1.14916667e+00, 9.25000000e-02, -2.63333333e-01, 2.40833333e+00,\n",
" 1.66333333e+00, 1.81666667e+00, 6.46250000e+00, 1.04333333e+00,\n",
" 2.64500000e+00, -7.86333333e+00, 2.74666667e+00, 8.89166667e-01,\n",
" 1.79333333e+00, 3.28750000e+00, -3.71666667e-01, 1.53333333e-01,\n",
" 1.71666667e-01, 7.40833333e-01, -2.32083333e+00, 1.68500000e+00,\n",
" -1.31000000e+00, -9.46666667e-01, 1.10166667e+00, -4.05000000e-01,\n",
" -2.22250000e+00, 2.47500000e+00, 9.20833333e-01, 4.56666667e-01,\n",
" 5.08333333e-01, 3.05833333e-01, -6.41666667e-02, 1.83750000e+00,\n",
" -3.59166667e-01, 3.75000000e-02, 2.98333333e-01, 1.87500000e-01,\n",
" -2.50000000e-01, 2.06666667e-01, 8.08333333e-01, 1.51750000e+00,\n",
" 1.11416667e+00, -3.50000000e-01, 2.49166667e-01, -1.00750000e+00,\n",
" 8.95000000e-01, -4.27500000e-01, 1.54166667e-01, -2.63333333e-01,\n",
" 7.28333333e-01, 9.93333333e-01, 8.44166667e-01, -9.31666667e-01,\n",
" 1.92333333e+00, -1.17250000e+00, 2.12416667e+00, -6.11666667e-01,\n",
" 5.02500000e-01, 8.18333333e-01, 2.71666667e-01, 7.45833333e-01,\n",
" -4.00833333e-01, -7.36666667e-01, 1.74250000e+00, 1.66250000e+00,\n",
" 1.16166667e+00, -2.36666667e-01, -6.58333333e-01, 1.76000000e+00,\n",
" -4.64166667e-01, 4.73000000e+00, 1.26916667e+00, -2.37583333e+00,\n",
" 3.05583333e+00, -1.76583333e+00, -3.77500000e-01, 2.62500000e+00,\n",
" 9.06666667e-01, 1.50083333e+00, 6.71666667e-01, 4.01416667e+00,\n",
" -5.13333333e-01, -3.23333333e-01, 1.66916667e+00, 1.66333333e+00,\n",
" 2.60833333e-01, 5.07500000e-01, -5.68333333e-01, 2.74083333e+00,\n",
" 5.92500000e-01, -9.00000000e-02, 2.11666667e-01, -1.19916667e+00,\n",
" 7.90833333e-01, 8.24166667e-01, 1.14000000e+00, 1.28166667e+00,\n",
" 1.32750000e+00, 4.60000000e-01, 5.00000000e-03, 1.55166667e+00,\n",
" -4.04166667e-01, 1.83500000e+00, 2.47583333e+00, 2.69916667e+00,\n",
" -2.95000000e+00, 1.26083333e+00, -2.27000000e+00, -2.30000000e-01,\n",
" 6.33333333e-01, 9.92500000e-01, -4.57500000e-01, -1.52750000e+00,\n",
" 2.76000000e+00, -1.01666667e+00, 5.05833333e-01, -9.43333333e-01,\n",
" -1.00833333e-01, 3.22833333e+00, 1.53583333e+00, -5.95833333e-01,\n",
" -3.65833333e-01, 7.60833333e-01, -2.00000000e-02, 6.33333333e-02,\n",
" -1.30583333e+00, -7.70833333e-01, 9.77500000e-01, 3.77500000e-01,\n",
" -2.04166667e-01, -2.41666667e-02, -5.10000000e-01, 3.15166667e+00,\n",
" 7.45833333e-01, -5.10000000e-01, 1.25000000e+00, -1.76000000e+00,\n",
" 4.62500000e-01, -5.05833333e-01, -8.15833333e-01, 1.80166667e+00,\n",
" 1.79583333e+00, 3.25833333e-01, 3.08333333e+00, 9.95000000e-01,\n",
" 8.03333333e-01, 8.91666667e-02, 1.28916667e+00, 1.04833333e+00,\n",
" 8.80833333e-01, 1.54000000e+00, -1.99166667e+00, 1.64166667e-01,\n",
" -5.48333333e-01, -5.75000000e-01, 3.62416667e+00, -2.28083333e+00,\n",
" 1.19333333e+00, 3.77500000e-01, -5.95000000e-01, -2.85583333e+00,\n",
" -1.10416667e+00, 1.07916667e+00, 7.53333333e-01, 9.65833333e-01,\n",
" -1.23666667e+00, -8.00833333e-01, -1.40750000e+00, 5.86666667e-01,\n",
" 1.03500000e+00, 7.19166667e-01, -1.01750000e+00, -6.96666667e-01,\n",
" 1.05083333e+00, -2.45833333e-01, -4.28333333e-01, 6.88333333e-01,\n",
" -1.47166667e+00, 1.19166667e-01, -2.18333333e-01, 6.41666667e-02,\n",
" 8.50000000e-01, 1.24833333e+00, 1.79833333e+00, -3.89166667e-01,\n",
" -1.37166667e+00, -1.21916667e+00, 2.30833333e-01, 1.06500000e+00,\n",
" -1.01666667e-01, 2.39500000e+00, 4.45000000e-01, 4.85000000e-01,\n",
" 1.17083333e+00, -1.14333333e+00, 1.78083333e+00, 9.57500000e-01,\n",
" 1.71250000e+00, 4.44500000e+00, 8.21666667e-01, 1.37333333e+00,\n",
" 9.40833333e-01, 1.12833333e+00, 1.32750000e+00, 2.48333333e-01,\n",
" -1.73583333e+00, -1.31000000e+00, -1.19916667e+00, -7.10833333e-01,\n",
" 1.77916667e+00, 2.21666667e-01, -1.11250000e+00, -1.24666667e+00,\n",
" 1.32416667e+00, 3.96083333e+00, 6.97500000e-01, 5.29166667e-01,\n",
" 1.21666667e-01, 6.04166667e-01, 1.73500000e+00, -5.50000000e-01,\n",
" 7.73333333e-01, 1.66666667e-02, -2.19166667e-01, 2.89000000e+00,\n",
" -6.23333333e-01, 1.00916667e+00, 5.84166667e-01, -2.25000000e-02,\n",
" -9.71666667e-01, 1.54250000e+00, 1.30000000e-01, 1.87500000e-01,\n",
" -2.20833333e-01, 3.88333333e-01, 2.68333333e-01, 1.48333333e-01,\n",
" -8.49166667e-01, -5.95000000e-01, -2.10000000e-01, -3.84166667e-01,\n",
" 6.09166667e-01, -8.55833333e-01, -6.41666667e-02, 3.49166667e-01,\n",
" -3.18333333e-01, -4.62500000e-01, -1.66666667e+00, 1.61666667e+00,\n",
" -1.25500000e+00, 1.48000000e+00, 3.24166667e-01, -1.19333333e+00,\n",
" 7.41666667e-02, 7.85000000e-01, -6.83333333e-02, -1.16666667e+00,\n",
" -1.46583333e+00, -6.95833333e-01, 2.95416667e+00, 6.43333333e-01,\n",
" -2.35416667e+00, 1.31333333e+00, 8.03333333e-01, 1.71250000e+00,\n",
" 1.86666667e-01, 1.53500000e+00, -6.60833333e-01, 3.54166667e-01,\n",
" -1.95083333e+00, 1.81500000e+00, -6.46666667e-01, 1.58583333e+00,\n",
" -1.54833333e+00, -1.86666667e-01, 1.42416667e+00, -7.13333333e-01,\n",
" 8.98333333e-01, 1.59833333e+00, 6.43333333e-01, 2.95833333e-01,\n",
" 1.62500000e+00, -3.67500000e-01, 1.79333333e+00, 3.00000000e+00,\n",
" 1.75416667e+00, 1.71166667e+00, 5.79166667e-01, -7.65833333e-01,\n",
" 1.09000000e+00, -5.67500000e-01, 2.22333333e+00, 1.18333333e+00,\n",
" 2.51000000e+00, 2.92500000e+00, 1.82166667e+00, 1.77083333e+00,\n",
" 4.38083333e+00, 4.69583333e+00, -1.97083333e+00, 3.80166667e+00,\n",
" -6.34166667e-01, -8.08333333e-01, -1.31666667e-01, 3.34166667e-01,\n",
" 2.87916667e+00, 7.60833333e-01, 4.09000000e+00, 2.05333333e+00,\n",
" -4.91666667e-02, 7.51916667e+00, 6.36583333e+00, -2.30583333e+00,\n",
" 2.74000000e+00, 6.76666667e+00, -7.55000000e-01, -4.43333333e-01,\n",
" 3.37166667e+00, 2.03750000e+00, 3.15416667e+00, 3.41833333e+00,\n",
" 2.74916667e+00, 7.64166667e-01, -1.89166667e-01, 2.48833333e+00,\n",
" 2.22500000e+00, -1.16333333e+00, 2.29333333e+00, 4.00750000e+00,\n",
" 3.94166667e+00, 2.69500000e+00, -2.14583333e+00, -1.91000000e+00,\n",
" 1.30083333e+00, -5.90833333e-01, 4.39750000e+00, -1.15416667e+00,\n",
" -2.04833333e+00, 5.81666667e-01, 3.13000000e+00, 7.50000000e-01,\n",
" 8.96666667e-01, 4.72500000e-01, 1.92916667e+00, 7.29166667e-01,\n",
" -4.98333333e-01, -1.07083333e+00, 9.63333333e-01, -1.66416667e+00,\n",
" -1.02750000e+00, -2.19583333e+00, 7.95000000e-01, -1.78833333e+00,\n",
" 4.95000000e-01, -6.09166667e-01, 2.73333333e-01, 2.92500000e-01,\n",
" -9.83333333e-01, 1.38833333e+00, 2.05000000e-01, -4.50000000e-02,\n",
" -2.71666667e-01, -2.16666667e-02, 1.23916667e+00, 1.28000000e+00,\n",
" 2.95000000e-01, -1.08750000e+00, -9.63333333e-01, 2.34166667e-01,\n",
" -1.00583333e+00, -2.16666667e-01, 3.71416667e+00, 3.04166667e-01,\n",
" 1.44333333e+00, 1.15000000e-01, 6.65000000e-01, 3.73333333e-01,\n",
" 9.60000000e-01, 2.93916667e+00, -1.05416667e+00, 3.58333333e-01,\n",
" 1.08333333e-02, 1.14000000e+00, -2.86666667e-01, -2.33000000e+00,\n",
" 2.64833333e+00, 6.33333333e-02, 7.77500000e-01, 3.79250000e+00,\n",
" 1.35416667e+00, 1.78833333e+00, -7.75000000e-01, 6.62500000e-01,\n",
" 7.00000000e-02, 1.06583333e+00, 4.80833333e-01, 1.31666667e-01,\n",
" -2.77500000e-01, 2.85000000e-01, 1.17416667e+00, 1.37500000e+00,\n",
" 1.05000000e+00, -1.67083333e+00, -1.37250000e+00, -1.90250000e+00,\n",
" 2.39166667e+00, -2.74166667e+00, 3.90833333e-01, -4.33333333e-01,\n",
" -2.97583333e+00, 6.60000000e-01, 4.77750000e+00, -2.47750000e+00,\n",
" 2.75833333e+00, 4.04583333e+00, 2.25833333e-01, 3.00583333e+00,\n",
" 6.80000000e-01, -3.28333333e-01, 4.85750000e+00, -2.07166667e+00,\n",
" 1.30683333e+01, 4.25833333e-01, -1.15500000e+00, -7.86666667e-01,\n",
" 9.09166667e-01, 4.15833333e-01, 5.75000000e-02, 1.37916667e+00,\n",
" 2.76916667e+00, 4.57500000e-01, -5.66666667e-02, -9.73333333e-01,\n",
" 2.81666667e+00, -7.67500000e-01, 3.27083333e+00, -1.52166667e+00,\n",
" -8.75833333e-01, -1.18000000e+00, 2.89166667e-01, 2.40083333e+00,\n",
" 1.03916667e+00, 1.99416667e+00, -5.55000000e-01, -3.72500000e-01,\n",
" -9.40833333e-01, 2.56916667e+00, 2.91666667e-02, 1.96250000e+00,\n",
" 2.88250000e+00, 6.37083333e+00, -4.72666667e+00, -6.77500000e-01,\n",
" 2.19666667e+00, -1.38333333e-01, 4.23333333e-01, 1.52833333e+00,\n",
" -5.43333333e-01, -1.03750000e+00, -1.19750000e+00, 3.70833333e-01,\n",
" -9.00000000e-02, 2.33333333e-01, 1.13750000e+00, -1.38833333e+00,\n",
" -1.11666667e+00, -1.69166667e-01, 1.27416667e+00, 7.15000000e-01,\n",
" 2.51666667e+00, -2.21666667e+00, -2.63750000e+00, -3.15833333e-01,\n",
" 6.12500000e-01, -1.19916667e+00, -2.45833333e-01, -3.55000000e-01,\n",
" -6.21666667e-01, 9.66666667e-01, -1.81666667e-01, -1.12833333e+00,\n",
" 2.47500000e-01, -4.89166667e-01, -1.55000000e-01, 4.10833333e-01,\n",
" -3.64166667e-01, 2.38833333e+00, 1.02666667e+00, 1.27583333e+00,\n",
" -2.60000000e-01, 2.06500000e+00, -4.89166667e-01, -1.17333333e+00,\n",
" -3.01666667e-01, 4.90000000e-01, 2.56416667e+00, 4.78583333e+00,\n",
" -1.27916667e+00, -2.12916667e+00, 2.23583333e+00, -4.37500000e-01,\n",
" -1.16666667e-01, 3.02083333e+00, -2.29583333e+00, 9.46666667e-01,\n",
" 3.38666667e+00, -6.16666667e-02, -1.62333333e+00, -3.78250000e+00,\n",
" 3.65833333e-01, -5.03333333e-01, 5.98333333e-01, -1.39000000e+00])"
]
},
"metadata": {
"tags": []
},
"execution_count": 25
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "4YGCSmw9CyAc",
"outputId": "5578c362-a700-46a5-b69b-34f20cc14ffa",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
}
},
"source": [
"backtestmodel.report_returns(start_date=start_date_str, freq='M')\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Mean return: 6.667%\n",
"Monthly Sharpe ratio: 1.123\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "zyoWNsP_C1iO",
"outputId": "8c0f325d-aeee-4c78-b5f4-c15b1ef8eb91",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 86
}
},
"source": [
"backtestmodel.evaluate_predictions()\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"OOS MSE across all predictions: 39.4986\n",
"\b#In-sample MSE: 35.8279\n",
"Variance: 39.4097\n",
"R-squared: -0.0023\n"
],
"name": "stdout"
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"39.498593093893305"
]
},
"metadata": {
"tags": []
},
"execution_count": 27
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "8YDisSj-X_b9",
"outputId": "41b901a2-10a3-4774-bff2-4ec56268ba52",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"\n",
"backtestmodel.evaluate_quantiles(chart=True, verbose=True)\n",
"\n",
"## There is clearly some signal here. "
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Avg rank correlation (Kendall's tau): 0.0589 (Expected: 0)\n",
"5-quintile accuracy: 0.2287 (Expected: 0.2)\n",
"Long/short/flat accuracy: 0.4706 (Expected: 0.44)\n",
"Confusion matrix for quantile 0\n",
"[[10953 2559]\n",
" [ 2555 823]]\n",
"Chi-square: 49.7107 (p-value: 0.00000000)\n",
"Confusion matrix for quantile 1\n",
"[[10884 2628]\n",
" [ 2628 750]]\n",
"Chi-square: 12.8020 (p-value: 0.00508507)\n",
"Confusion matrix for quantile 2\n",
"[[10850 2662]\n",
" [ 2656 722]]\n",
"Chi-square: 4.7384 (p-value: 0.19198761)\n",
"Confusion matrix for quantile 3\n",
"[[10851 2661]\n",
" [ 2666 712]]\n",
"Chi-square: 3.2442 (p-value: 0.35547827)\n",
"Confusion matrix for quantile 4\n",
"[[10994 2518]\n",
" [ 2523 855]]\n",
"Chi-square: 75.2761 (p-value: 0.00000000)\n",
"Excess true positive in quintiles 1 + 5: 326.800000\n"
],
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 720x720 with 2 Axes>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PrKpbS8XfkZE"
},
"source": [
"### Functions using Plotly to generate charts for performance, scatters, heatmaps"
]
},
{
"cell_type": "code",
"metadata": {
"id": "HVCS5RFDoeZG",
"outputId": "a71cda06-bbec-41f5-fe45-7103f3aa51d5",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 156
}
},
"source": [
"!pip install plotly==2.0.0"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"text": [
"Requirement already satisfied: plotly==2.0.0 in /usr/local/lib/python3.6/dist-packages (2.0.0)\n",
"Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from plotly==2.0.0) (1.12.0)\n",
"Requirement already satisfied: requests in /usr/local/lib/python3.6/dist-packages (from plotly==2.0.0) (2.21.0)\n",
"Requirement already satisfied: pytz in /usr/local/lib/python3.6/dist-packages (from plotly==2.0.0) (2018.9)\n",
"Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests->plotly==2.0.0) (2019.6.16)\n",
"Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests->plotly==2.0.0) (3.0.4)\n",
"Requirement already satisfied: idna<2.9,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests->plotly==2.0.0) (2.8)\n",
"Requirement already satisfied: urllib3<1.25,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests->plotly==2.0.0) (1.24.3)\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "8eAe0A8KfkZM"
},
"source": [
"# chart performance\n",
"\n",
"def mychart(args, names=None, title=\"\"):\n",
" x_coords = np.linspace(1970, 2016, args[0].shape[0])\n",
" plotdata = []\n",
" for i in range(len(args)):\n",
" tracelabel = \"Trace %d\" % i\n",
" if names:\n",
" tracelabel=names[i]\n",
" plotdata.append(Scatter(x=x_coords,\n",
" y=args[i].values.reshape(-1),\n",
" mode = 'line',\n",
" name=tracelabel)) \n",
"\n",
" layout = Layout(\n",
" title = title,\n",
" autosize=False,\n",
" width=900,\n",
" height=600,\n",
" yaxis=dict(\n",
" type='log',\n",
" autorange=True\n",
" )\n",
" )\n",
" \n",
" fig = Figure(data=plotdata, layout=layout)\n",
" \n",
" return iplot(fig)\n",
" \n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "m5l3PH6SfkZP"
},
"source": [
"def myscatter(arg1, arg2, names=None, title=\"\"):\n",
" \n",
" plotdata = []\n",
" \n",
" plotdata.append(Scatter(\n",
" x = arg1,\n",
" y = arg2,\n",
" mode = 'markers'\n",
" ))\n",
"\n",
" layout = dict(\n",
" title=title,\n",
" autosize=False,\n",
" width=\"600\",\n",
" height=\"480\",\n",
" yaxis=dict(\n",
"# type='log',\n",
" autorange=True\n",
" )\n",
" )\n",
" \n",
"# py.iplot(data, filename='basic-scatter')\n",
"\n",
" fig = Figure(data=plotdata, layout=layout)\n",
" \n",
" return iplot(fig)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "kTX6zsSwfkZT"
},
"source": [
"def plot_matrix(lossframe, x_labels, y_labels, x_suffix=\"\", y_suffix=\"\"):\n",
"\n",
" pivot = lossframe.pivot_table(index=[y_labels], columns=[x_labels], values=['mse'])\n",
"# print(pivot)\n",
" # specify labels as strings, to force plotly to use a discrete axis\n",
"# print(pivot.columns.levels[1]).values\n",
"# print(lossframe[x_labels].dtype)\n",
" \n",
" if lossframe[x_labels].dtype == np.float64 or lossframe[x_labels].dtype == np.float32:\n",
" xaxis = [\"%f %s\" % (i, x_suffix) for i in pivot.columns.levels[1].values]\n",
" else:\n",
" xaxis = [\"%d %s\" % (i, x_suffix) for i in pivot.columns.levels[1].values]\n",
" if lossframe[y_labels].dtype == np.float64 or lossframe[y_labels].dtype == np.float32:\n",
" yaxis = [\"%f %s\" % (i, y_suffix) for i in pivot.index.values]\n",
" else:\n",
" yaxis = [\"%d %s\" % (i, y_suffix) for i in pivot.index.values]\n",
" \n",
"# print(xaxis, yaxis)\n",
" \"\"\"plot a heat map of a matrix\"\"\"\n",
" chart_width=640\n",
" chart_height=480\n",
" \n",
" layout = dict(\n",
" title=\"%s v. %s\" % (x_labels, y_labels),\n",
" height=chart_height,\n",
" width=chart_width, \n",
" margin=dict(\n",
" l=150,\n",
" r=30,\n",
" b=120,\n",
" t=100,\n",
" ),\n",
" xaxis=dict(\n",
" title=x_labels,\n",
" tickfont=dict(\n",
" family='Arial, sans-serif',\n",
" size=10,\n",
" color='black'\n",
" ),\n",
" ),\n",
" yaxis=dict(\n",
" title=y_labels,\n",
" tickfont=dict(\n",
" family='Arial, sans-serif',\n",
" size=10,\n",
" color='black'\n",
" ),\n",
" ),\n",
" )\n",
" \n",
" data = [Heatmap(z=pivot.values,\n",
" x=xaxis,\n",
" y=yaxis,\n",
" colorscale=[[0, 'rgb(0,0,255)', [1, 'rgb(255,0,0)']]],\n",
" )\n",
" ]\n",
"\n",
" fig = Figure(data=data, layout=layout)\n",
" return iplot(fig, link_text=\"\")"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "39PVdCojfkZW"
},
"source": [
"### Compare LASSO, OLS models"
]
},
{
"cell_type": "code",
"metadata": {
"id": "C5UHu6uEb-gF"
},
"source": [
"def configure_plotly_browser_state():\n",
" import IPython\n",
" display(IPython.core.display.HTML('''\n",
" <script src=\"/static/components/requirejs/require.js\"></script>\n",
" <script>\n",
" requirejs.config({\n",
" paths: {\n",
" base: '/static/base',\n",
" plotly: 'https://cdn.plot.ly/plotly-latest.min.js?noext',\n",
" },\n",
" });\n",
" </script>\n",
" '''))"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "gWUefasJfkZX",
"outputId": "39e57e7c-b9ce-4a06-c3a4-81a2d702f98c",
"colab": {
"resources": {
"http://localhost:8080/static/components/requirejs/require.js": {
"data": "LyoqIHZpbTogZXQ6dHM9NDpzdz00OnN0cz00CiAqIEBsaWNlbnNlIFJlcXVpcmVKUyAyLjEuMjIgQ29weXJpZ2h0IChjKSAyMDEwLTIwMTUsIFRoZSBEb2pvIEZvdW5kYXRpb24gQWxsIFJpZ2h0cyBSZXNlcnZlZC4KICogQXZhaWxhYmxlIHZpYSB0aGUgTUlUIG9yIG5ldyBCU0QgbGljZW5zZS4KICogc2VlOiBodHRwOi8vZ2l0aHViLmNvbS9qcmJ1cmtlL3JlcXVpcmVqcyBmb3IgZGV0YWlscwogKi8KLy9Ob3QgdXNpbmcgc3RyaWN0OiB1bmV2ZW4gc3RyaWN0IHN1cHBvcnQgaW4gYnJvd3NlcnMsICMzOTIsIGFuZCBjYXVzZXMKLy9wcm9ibGVtcyB3aXRoIHJlcXVpcmVqcy5leGVjKCkvdHJhbnNwaWxlciBwbHVnaW5zIHRoYXQgbWF5IG5vdCBiZSBzdHJpY3QuCi8qanNsaW50IHJlZ2V4cDogdHJ1ZSwgbm9tZW46IHRydWUsIHNsb3BweTogdHJ1ZSAqLwovKmdsb2JhbCB3aW5kb3csIG5hdmlnYXRvciwgZG9jdW1lbnQsIGltcG9ydFNjcmlwdHMsIHNldFRpbWVvdXQsIG9wZXJhICovCgp2YXIgcmVxdWlyZWpzLCByZXF1aXJlLCBkZWZpbmU7CihmdW5jdGlvbiAoZ2xvYmFsKSB7CiAgICB2YXIgcmVxLCBzLCBoZWFkLCBiYXNlRWxlbWVudCwgZGF0YU1haW4sIHNyYywKICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCwgY3VycmVudGx5QWRkaW5nU2NyaXB0LCBtYWluU2NyaXB0LCBzdWJQYXRoLAogICAgICAgIHZlcnNpb24gPSAnMi4xLjIyJywKICAgICAgICBjb21tZW50UmVnRXhwID0gLyhcL1wqKFtcc1xTXSo/KVwqXC98KFteOl18XilcL1wvKC4qKSQpL21nLAogICAgICAgIGNqc1JlcXVpcmVSZWdFeHAgPSAvW14uXVxzKnJlcXVpcmVccypcKFxzKlsiJ10oW14nIlxzXSspWyInXVxzKlwpL2csCiAgICAgICAganNTdWZmaXhSZWdFeHAgPSAvXC5qcyQvLAogICAgICAgIGN1cnJEaXJSZWdFeHAgPSAvXlwuXC8vLAogICAgICAgIG9wID0gT2JqZWN0LnByb3RvdHlwZSwKICAgICAgICBvc3RyaW5nID0gb3AudG9TdHJpbmcsCiAgICAgICAgaGFzT3duID0gb3AuaGFzT3duUHJvcGVydHksCiAgICAgICAgYXAgPSBBcnJheS5wcm90b3R5cGUsCiAgICAgICAgaXNCcm93c2VyID0gISEodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmRvY3VtZW50KSwKICAgICAgICBpc1dlYldvcmtlciA9ICFpc0Jyb3dzZXIgJiYgdHlwZW9mIGltcG9ydFNjcmlwdHMgIT09ICd1bmRlZmluZWQnLAogICAgICAgIC8vUFMzIGluZGljYXRlcyBsb2FkZWQgYW5kIGNvbXBsZXRlLCBidXQgbmVlZCB0byB3YWl0IGZvciBjb21wbGV0ZQogICAgICAgIC8vc3BlY2lmaWNhbGx5LiBTZXF1ZW5jZSBpcyAnbG9hZGluZycsICdsb2FkZWQnLCBleGVjdXRpb24sCiAgICAgICAgLy8gdGhlbiAnY29tcGxldGUnLiBUaGUgVUEgY2hlY2sgaXMgdW5mb3J0dW5hdGUsIGJ1dCBub3Qgc3VyZSBob3cKICAgICAgICAvL3RvIGZlYXR1cmUgdGVzdCB3L28gY2F1c2luZyBwZXJmIGlzc3Vlcy4KICAgICAgICByZWFkeVJlZ0V4cCA9IGlzQnJvd3NlciAmJiBuYXZpZ2F0b3IucGxhdGZvcm0gPT09ICdQTEFZU1RBVElPTiAzJyA/CiAgICAgICAgICAgICAgICAgICAgICAvXmNvbXBsZXRlJC8gOiAvXihjb21wbGV0ZXxsb2FkZWQpJC8sCiAgICAgICAgZGVmQ29udGV4dE5hbWUgPSAnXycsCiAgICAgICAgLy9PaCB0aGUgdHJhZ2VkeSwgZGV0ZWN0aW5nIG9wZXJhLiBTZWUgdGhlIHVzYWdlIG9mIGlzT3BlcmEgZm9yIHJlYXNvbi4KICAgICAgICBpc09wZXJhID0gdHlwZW9mIG9wZXJhICE9PSAndW5kZWZpbmVkJyAmJiBvcGVyYS50b1N0cmluZygpID09PSAnW29iamVjdCBPcGVyYV0nLAogICAgICAgIGNvbnRleHRzID0ge30sCiAgICAgICAgY2ZnID0ge30sCiAgICAgICAgZ2xvYmFsRGVmUXVldWUgPSBbXSwKICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwoKICAgIGZ1bmN0aW9uIGlzRnVuY3Rpb24oaXQpIHsKICAgICAgICByZXR1cm4gb3N0cmluZy5jYWxsKGl0KSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJzsKICAgIH0KCiAgICBmdW5jdGlvbiBpc0FycmF5KGl0KSB7CiAgICAgICAgcmV0dXJuIG9zdHJpbmcuY2FsbChpdCkgPT09ICdbb2JqZWN0IEFycmF5XSc7CiAgICB9CgogICAgLyoqCiAgICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIGl0ZXJhdGluZyBvdmVyIGFuIGFycmF5LiBJZiB0aGUgZnVuYyByZXR1cm5zCiAgICAgKiBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoKGFyeSwgZnVuYykgewogICAgICAgIGlmIChhcnkpIHsKICAgICAgICAgICAgdmFyIGk7CiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBhcnkubGVuZ3RoOyBpICs9IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhlbHBlciBmdW5jdGlvbiBmb3IgaXRlcmF0aW5nIG92ZXIgYW4gYXJyYXkgYmFja3dhcmRzLiBJZiB0aGUgZnVuYwogICAgICogcmV0dXJucyBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoUmV2ZXJzZShhcnksIGZ1bmMpIHsKICAgICAgICBpZiAoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpOwogICAgICAgICAgICBmb3IgKGkgPSBhcnkubGVuZ3RoIC0gMTsgaSA+IC0xOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBoYXNQcm9wKG9iaiwgcHJvcCkgewogICAgICAgIHJldHVybiBoYXNPd24uY2FsbChvYmosIHByb3ApOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldE93bihvYmosIHByb3ApIHsKICAgICAgICByZXR1cm4gaGFzUHJvcChvYmosIHByb3ApICYmIG9ialtwcm9wXTsKICAgIH0KCiAgICAvKioKICAgICAqIEN5Y2xlcyBvdmVyIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGFuZCBjYWxscyBhIGZ1bmN0aW9uIGZvciBlYWNoCiAgICAgKiBwcm9wZXJ0eSB2YWx1ZS4gSWYgdGhlIGZ1bmN0aW9uIHJldHVybnMgYSB0cnV0aHkgdmFsdWUsIHRoZW4gdGhlCiAgICAgKiBpdGVyYXRpb24gaXMgc3RvcHBlZC4KICAgICAqLwogICAgZnVuY3Rpb24gZWFjaFByb3Aob2JqLCBmdW5jKSB7CiAgICAgICAgdmFyIHByb3A7CiAgICAgICAgZm9yIChwcm9wIGluIG9iaikgewogICAgICAgICAgICBpZiAoaGFzUHJvcChvYmosIHByb3ApKSB7CiAgICAgICAgICAgICAgICBpZiAoZnVuYyhvYmpbcHJvcF0sIHByb3ApKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBTaW1wbGUgZnVuY3Rpb24gdG8gbWl4IGluIHByb3BlcnRpZXMgZnJvbSBzb3VyY2UgaW50byB0YXJnZXQsCiAgICAgKiBidXQgb25seSBpZiB0YXJnZXQgZG9lcyBub3QgYWxyZWFkeSBoYXZlIGEgcHJvcGVydHkgb2YgdGhlIHNhbWUgbmFtZS4KICAgICAqLwogICAgZnVuY3Rpb24gbWl4aW4odGFyZ2V0LCBzb3VyY2UsIGZvcmNlLCBkZWVwU3RyaW5nTWl4aW4pIHsKICAgICAgICBpZiAoc291cmNlKSB7CiAgICAgICAgICAgIGVhY2hQcm9wKHNvdXJjZSwgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICBpZiAoZm9yY2UgfHwgIWhhc1Byb3AodGFyZ2V0LCBwcm9wKSkgewogICAgICAgICAgICAgICAgICAgIGlmIChkZWVwU3RyaW5nTWl4aW4gJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAhaXNBcnJheSh2YWx1ZSkgJiYgIWlzRnVuY3Rpb24odmFsdWUpICYmCiAgICAgICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApKSB7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRhcmdldFtwcm9wXSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0ge307CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgbWl4aW4odGFyZ2V0W3Byb3BdLCB2YWx1ZSwgZm9yY2UsIGRlZXBTdHJpbmdNaXhpbik7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0gdmFsdWU7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRhcmdldDsKICAgIH0KCiAgICAvL1NpbWlsYXIgdG8gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQsIGJ1dCB0aGUgJ3RoaXMnIG9iamVjdCBpcyBzcGVjaWZpZWQKICAgIC8vZmlyc3QsIHNpbmNlIGl0IGlzIGVhc2llciB0byByZWFkL2ZpZ3VyZSBvdXQgd2hhdCAndGhpcycgd2lsbCBiZS4KICAgIGZ1bmN0aW9uIGJpbmQob2JqLCBmbikgewogICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHJldHVybiBmbi5hcHBseShvYmosIGFyZ3VtZW50cyk7CiAgICAgICAgfTsKICAgIH0KCiAgICBmdW5jdGlvbiBzY3JpcHRzKCkgewogICAgICAgIHJldHVybiBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7CiAgICB9CgogICAgZnVuY3Rpb24gZGVmYXVsdE9uRXJyb3IoZXJyKSB7CiAgICAgICAgdGhyb3cgZXJyOwogICAgfQoKICAgIC8vQWxsb3cgZ2V0dGluZyBhIGdsb2JhbCB0aGF0IGlzIGV4cHJlc3NlZCBpbgogICAgLy9kb3Qgbm90YXRpb24sIGxpa2UgJ2EuYi5jJy4KICAgIGZ1bmN0aW9uIGdldEdsb2JhbCh2YWx1ZSkgewogICAgICAgIGlmICghdmFsdWUpIHsKICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgIH0KICAgICAgICB2YXIgZyA9IGdsb2JhbDsKICAgICAgICBlYWNoKHZhbHVlLnNwbGl0KCcuJyksIGZ1bmN0aW9uIChwYXJ0KSB7CiAgICAgICAgICAgIGcgPSBnW3BhcnRdOwogICAgICAgIH0pOwogICAgICAgIHJldHVybiBnOwogICAgfQoKICAgIC8qKgogICAgICogQ29uc3RydWN0cyBhbiBlcnJvciB3aXRoIGEgcG9pbnRlciB0byBhbiBVUkwgd2l0aCBtb3JlIGluZm9ybWF0aW9uLgogICAgICogQHBhcmFtIHtTdHJpbmd9IGlkIHRoZSBlcnJvciBJRCB0aGF0IG1hcHMgdG8gYW4gSUQgb24gYSB3ZWIgcGFnZS4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGh1bWFuIHJlYWRhYmxlIGVycm9yLgogICAgICogQHBhcmFtIHtFcnJvcn0gW2Vycl0gdGhlIG9yaWdpbmFsIGVycm9yLCBpZiB0aGVyZSBpcyBvbmUuCiAgICAgKgogICAgICogQHJldHVybnMge0Vycm9yfQogICAgICovCiAgICBmdW5jdGlvbiBtYWtlRXJyb3IoaWQsIG1zZywgZXJyLCByZXF1aXJlTW9kdWxlcykgewogICAgICAgIHZhciBlID0gbmV3IEVycm9yKG1zZyArICdcbmh0dHA6Ly9yZXF1aXJlanMub3JnL2RvY3MvZXJyb3JzLmh0bWwjJyArIGlkKTsKICAgICAgICBlLnJlcXVpcmVUeXBlID0gaWQ7CiAgICAgICAgZS5yZXF1aXJlTW9kdWxlcyA9IHJlcXVpcmVNb2R1bGVzOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgZS5vcmlnaW5hbEVycm9yID0gZXJyOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZTsKICAgIH0KCiAgICBpZiAodHlwZW9mIGRlZmluZSAhPT0gJ3VuZGVmaW5lZCcpIHsKICAgICAgICAvL0lmIGEgZGVmaW5lIGlzIGFscmVhZHkgaW4gcGxheSB2aWEgYW5vdGhlciBBTUQgbG9hZGVyLAogICAgICAgIC8vZG8gbm90IG92ZXJ3cml0ZS4KICAgICAgICByZXR1cm47CiAgICB9CgogICAgaWYgKHR5cGVvZiByZXF1aXJlanMgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgaWYgKGlzRnVuY3Rpb24ocmVxdWlyZWpzKSkgewogICAgICAgICAgICAvL0RvIG5vdCBvdmVyd3JpdGUgYW4gZXhpc3RpbmcgcmVxdWlyZWpzIGluc3RhbmNlLgogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNmZyA9IHJlcXVpcmVqczsKICAgICAgICByZXF1aXJlanMgPSB1bmRlZmluZWQ7CiAgICB9CgogICAgLy9BbGxvdyBmb3IgYSByZXF1aXJlIGNvbmZpZyBvYmplY3QKICAgIGlmICh0eXBlb2YgcmVxdWlyZSAhPT0gJ3VuZGVmaW5lZCcgJiYgIWlzRnVuY3Rpb24ocmVxdWlyZSkpIHsKICAgICAgICAvL2Fzc3VtZSBpdCBpcyBhIGNvbmZpZyBvYmplY3QuCiAgICAgICAgY2ZnID0gcmVxdWlyZTsKICAgICAgICByZXF1aXJlID0gdW5kZWZpbmVkOwogICAgfQoKICAgIGZ1bmN0aW9uIG5ld0NvbnRleHQoY29udGV4dE5hbWUpIHsKICAgICAgICB2YXIgaW5DaGVja0xvYWRlZCwgTW9kdWxlLCBjb250ZXh0LCBoYW5kbGVycywKICAgICAgICAgICAgY2hlY2tMb2FkZWRUaW1lb3V0SWQsCiAgICAgICAgICAgIGNvbmZpZyA9IHsKICAgICAgICAgICAgICAgIC8vRGVmYXVsdHMuIERvIG5vdCBzZXQgYSBkZWZhdWx0IGZvciBtYXAKICAgICAgICAgICAgICAgIC8vY29uZmlnIHRvIHNwZWVkIHVwIG5vcm1hbGl6ZSgpLCB3aGljaAogICAgICAgICAgICAgICAgLy93aWxsIHJ1biBmYXN0ZXIgaWYgdGhlcmUgaXMgbm8gZGVmYXVsdC4KICAgICAgICAgICAgICAgIHdhaXRTZWNvbmRzOiA3LAogICAgICAgICAgICAgICAgYmFzZVVybDogJy4vJywKICAgICAgICAgICAgICAgIHBhdGhzOiB7fSwKICAgICAgICAgICAgICAgIGJ1bmRsZXM6IHt9LAogICAgICAgICAgICAgICAgcGtnczoge30sCiAgICAgICAgICAgICAgICBzaGltOiB7fSwKICAgICAgICAgICAgICAgIGNvbmZpZzoge30KICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgLy9yZWdpc3RyeSBvZiBqdXN0IGVuYWJsZWQgbW9kdWxlcywgdG8gc3BlZWQKICAgICAgICAgICAgLy9jeWNsZSBicmVha2luZyBjb2RlIHdoZW4gbG90cyBvZiBtb2R1bGVzCiAgICAgICAgICAgIC8vYXJlIHJlZ2lzdGVyZWQsIGJ1dCBub3QgYWN0aXZhdGVkLgogICAgICAgICAgICBlbmFibGVkUmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgdW5kZWZFdmVudHMgPSB7fSwKICAgICAgICAgICAgZGVmUXVldWUgPSBbXSwKICAgICAgICAgICAgZGVmaW5lZCA9IHt9LAogICAgICAgICAgICB1cmxGZXRjaGVkID0ge30sCiAgICAgICAgICAgIGJ1bmRsZXNNYXAgPSB7fSwKICAgICAgICAgICAgcmVxdWlyZUNvdW50ZXIgPSAxLAogICAgICAgICAgICB1bm5vcm1hbGl6ZWRDb3VudGVyID0gMTsKCiAgICAgICAgLyoqCiAgICAgICAgICogVHJpbXMgdGhlIC4gYW5kIC4uIGZyb20gYW4gYXJyYXkgb2YgcGF0aCBzZWdtZW50cy4KICAgICAgICAgKiBJdCB3aWxsIGtlZXAgYSBsZWFkaW5nIHBhdGggc2VnbWVudCBpZiBhIC4uIHdpbGwgYmVjb21lCiAgICAgICAgICogdGhlIGZpcnN0IHBhdGggc2VnbWVudCwgdG8gaGVscCB3aXRoIG1vZHVsZSBuYW1lIGxvb2t1cHMsCiAgICAgICAgICogd2hpY2ggYWN0IGxpa2UgcGF0aHMsIGJ1dCBjYW4gYmUgcmVtYXBwZWQuIEJ1dCB0aGUgZW5kIHJlc3VsdCwKICAgICAgICAgKiBhbGwgcGF0aHMgdGhhdCB1c2UgdGhpcyBmdW5jdGlvbiBzaG91bGQgbG9vayBub3JtYWxpemVkLgogICAgICAgICAqIE5PVEU6IHRoaXMgbWV0aG9kIE1PRElGSUVTIHRoZSBpbnB1dCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnkgdGhlIGFycmF5IG9mIHBhdGggc2VnbWVudHMuCiAgICAgICAgICovCiAgICAgICAgZnVuY3Rpb24gdHJpbURvdHMoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpLCBwYXJ0OwogICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYXJ5Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBwYXJ0ID0gYXJ5W2ldOwogICAgICAgICAgICAgICAgaWYgKHBhcnQgPT09ICcuJykgewogICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSwgMSk7CiAgICAgICAgICAgICAgICAgICAgaSAtPSAxOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0ID09PSAnLi4nKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gSWYgYXQgdGhlIHN0YXJ0LCBvciBwcmV2aW91cyB2YWx1ZSBpcyBzdGlsbCAuLiwKICAgICAgICAgICAgICAgICAgICAvLyBrZWVwIHRoZW0gc28gdGhhdCB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGggaXQgbWF5CiAgICAgICAgICAgICAgICAgICAgLy8gc3RpbGwgd29yayB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGgsIGV2ZW4gdGhvdWdoCiAgICAgICAgICAgICAgICAgICAgLy8gYXMgYW4gSUQgaXQgaXMgbGVzcyB0aGFuIGlkZWFsLiBJbiBsYXJnZXIgcG9pbnQKICAgICAgICAgICAgICAgICAgICAvLyByZWxlYXNlcywgbWF5IGJlIGJldHRlciB0byBqdXN0IGtpY2sgb3V0IGFuIGVycm9yLgogICAgICAgICAgICAgICAgICAgIGlmIChpID09PSAwIHx8IChpID09PSAxICYmIGFyeVsyXSA9PT0gJy4uJykgfHwgYXJ5W2kgLSAxXSA9PT0gJy4uJykgewogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSAtIDEsIDIpOwogICAgICAgICAgICAgICAgICAgICAgICBpIC09IDI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHaXZlbiBhIHJlbGF0aXZlIG1vZHVsZSBuYW1lLCBsaWtlIC4vc29tZXRoaW5nLCBub3JtYWxpemUgaXQgdG8KICAgICAgICAgKiBhIHJlYWwgbmFtZSB0aGF0IGNhbiBiZSBtYXBwZWQgdG8gYSBwYXRoLgogICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSByZWxhdGl2ZSBuYW1lCiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGJhc2VOYW1lIGEgcmVhbCBuYW1lIHRoYXQgdGhlIG5hbWUgYXJnIGlzIHJlbGF0aXZlCiAgICAgICAgICogdG8uCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBhcHBseU1hcCBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgdmFsdWUuIFNob3VsZAogICAgICAgICAqIG9ubHkgYmUgZG9uZSBpZiB0aGlzIG5vcm1hbGl6YXRpb24gaXMgZm9yIGEgZGVwZW5kZW5jeSBJRC4KICAgICAgICAgKiBAcmV0dXJucyB7U3RyaW5nfSBub3JtYWxpemVkIG5hbWUKICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBub3JtYWxpemUobmFtZSwgYmFzZU5hbWUsIGFwcGx5TWFwKSB7CiAgICAgICAgICAgIHZhciBwa2dNYWluLCBtYXBWYWx1ZSwgbmFtZVBhcnRzLCBpLCBqLCBuYW1lU2VnbWVudCwgbGFzdEluZGV4LAogICAgICAgICAgICAgICAgZm91bmRNYXAsIGZvdW5kSSwgZm91bmRTdGFyTWFwLCBzdGFySSwgbm9ybWFsaXplZEJhc2VQYXJ0cywKICAgICAgICAgICAgICAgIGJhc2VQYXJ0cyA9IChiYXNlTmFtZSAmJiBiYXNlTmFtZS5zcGxpdCgnLycpKSwKICAgICAgICAgICAgICAgIG1hcCA9IGNvbmZpZy5tYXAsCiAgICAgICAgICAgICAgICBzdGFyTWFwID0gbWFwICYmIG1hcFsnKiddOwoKICAgICAgICAgICAgLy9BZGp1c3QgYW55IHJlbGF0aXZlIHBhdGhzLgogICAgICAgICAgICBpZiAobmFtZSkgewogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3BsaXQoJy8nKTsKICAgICAgICAgICAgICAgIGxhc3RJbmRleCA9IG5hbWUubGVuZ3RoIC0gMTsKCiAgICAgICAgICAgICAgICAvLyBJZiB3YW50aW5nIG5vZGUgSUQgY29tcGF0aWJpbGl0eSwgc3RyaXAgLmpzIGZyb20gZW5kCiAgICAgICAgICAgICAgICAvLyBvZiBJRHMuIEhhdmUgdG8gZG8gdGhpcyBoZXJlLCBhbmQgbm90IGluIG5hbWVUb1VybAogICAgICAgICAgICAgICAgLy8gYmVjYXVzZSBub2RlIGFsbG93cyBlaXRoZXIgLmpzIG9yIG5vbiAuanMgdG8gbWFwCiAgICAgICAgICAgICAgICAvLyB0byBzYW1lIGZpbGUuCiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm5vZGVJZENvbXBhdCAmJiBqc1N1ZmZpeFJlZ0V4cC50ZXN0KG5hbWVbbGFzdEluZGV4XSkpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lW2xhc3RJbmRleF0gPSBuYW1lW2xhc3RJbmRleF0ucmVwbGFjZShqc1N1ZmZpeFJlZ0V4cCwgJycpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIFN0YXJ0cyB3aXRoIGEgJy4nIHNvIG5lZWQgdGhlIGJhc2VOYW1lCiAgICAgICAgICAgICAgICBpZiAobmFtZVswXS5jaGFyQXQoMCkgPT09ICcuJyAmJiBiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAvL0NvbnZlcnQgYmFzZU5hbWUgdG8gYXJyYXksIGFuZCBsb3Agb2ZmIHRoZSBsYXN0IHBhcnQsCiAgICAgICAgICAgICAgICAgICAgLy9zbyB0aGF0IC4gbWF0Y2hlcyB0aGF0ICdkaXJlY3RvcnknIGFuZCBub3QgbmFtZSBvZiB0aGUgYmFzZU5hbWUncwogICAgICAgICAgICAgICAgICAgIC8vbW9kdWxlLiBGb3IgaW5zdGFuY2UsIGJhc2VOYW1lIG9mICdvbmUvdHdvL3RocmVlJywgbWFwcyB0bwogICAgICAgICAgICAgICAgICAgIC8vJ29uZS90d28vdGhyZWUuanMnLCBidXQgd2Ugd2FudCB0aGUgZGlyZWN0b3J5LCAnb25lL3R3bycgZm9yCiAgICAgICAgICAgICAgICAgICAgLy90aGlzIG5vcm1hbGl6YXRpb24uCiAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZEJhc2VQYXJ0cyA9IGJhc2VQYXJ0cy5zbGljZSgwLCBiYXNlUGFydHMubGVuZ3RoIC0gMSk7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vcm1hbGl6ZWRCYXNlUGFydHMuY29uY2F0KG5hbWUpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHRyaW1Eb3RzKG5hbWUpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuam9pbignLycpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL0FwcGx5IG1hcCBjb25maWcgaWYgYXZhaWxhYmxlLgogICAgICAgICAgICBpZiAoYXBwbHlNYXAgJiYgbWFwICYmIChiYXNlUGFydHMgfHwgc3Rhck1hcCkpIHsKICAgICAgICAgICAgICAgIG5hbWVQYXJ0cyA9IG5hbWUuc3BsaXQoJy8nKTsKCiAgICAgICAgICAgICAgICBvdXRlckxvb3A6IGZvciAoaSA9IG5hbWVQYXJ0cy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lU2VnbWVudCA9IG5hbWVQYXJ0cy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9GaW5kIHRoZSBsb25nZXN0IGJhc2VOYW1lIHNlZ21lbnQgbWF0Y2ggaW4gdGhlIGNvbmZpZy4KICAgICAgICAgICAgICAgICAgICAgICAgLy9TbywgZG8gam9pbnMgb24gdGhlIGJpZ2dlc3QgdG8gc21hbGxlc3QgbGVuZ3RocyBvZiBiYXNlUGFydHMuCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaiA9IGJhc2VQYXJ0cy5sZW5ndGg7IGogPiAwOyBqIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcFZhbHVlID0gZ2V0T3duKG1hcCwgYmFzZVBhcnRzLnNsaWNlKDAsIGopLmpvaW4oJy8nKSk7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iYXNlTmFtZSBzZWdtZW50IGhhcyBjb25maWcsIGZpbmQgaWYgaXQgaGFzIG9uZSBmb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hcFZhbHVlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwVmFsdWUgPSBnZXRPd24obWFwVmFsdWUsIG5hbWVTZWdtZW50KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWFwVmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXRjaCwgdXBkYXRlIG5hbWUgdG8gdGhlIG5ldyB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRNYXAgPSBtYXBWYWx1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRJID0gaTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsgb3V0ZXJMb29wOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9DaGVjayBmb3IgYSBzdGFyIG1hcCBtYXRjaCwgYnV0IGp1c3QgaG9sZCBvbiB0byBpdCwKICAgICAgICAgICAgICAgICAgICAvL2lmIHRoZXJlIGlzIGEgc2hvcnRlciBzZWdtZW50IG1hdGNoIGxhdGVyIGluIGEgbWF0Y2hpbmcKICAgICAgICAgICAgICAgICAgICAvL2NvbmZpZywgdGhlbiBmYXZvciBvdmVyIHRoaXMgc3RhciBtYXAuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFmb3VuZFN0YXJNYXAgJiYgc3Rhck1hcCAmJiBnZXRPd24oc3Rhck1hcCwgbmFtZVNlZ21lbnQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvdW5kU3Rhck1hcCA9IGdldE93bihzdGFyTWFwLCBuYW1lU2VnbWVudCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJJID0gaTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFmb3VuZE1hcCAmJiBmb3VuZFN0YXJNYXApIHsKICAgICAgICAgICAgICAgICAgICBmb3VuZE1hcCA9IGZvdW5kU3Rhck1hcDsKICAgICAgICAgICAgICAgICAgICBmb3VuZEkgPSBzdGFySTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBpZiAoZm91bmRNYXApIHsKICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMuc3BsaWNlKDAsIGZvdW5kSSwgZm91bmRNYXApOwogICAgICAgICAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHMuam9pbignLycpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBJZiB0aGUgbmFtZSBwb2ludHMgdG8gYSBwYWNrYWdlJ3MgbmFtZSwgdXNlCiAgICAgICAgICAgIC8vIHRoZSBwYWNrYWdlIG1haW4gaW5zdGVhZC4KICAgICAgICAgICAgcGtnTWFpbiA9IGdldE93bihjb25maWcucGtncywgbmFtZSk7CgogICAgICAgICAgICByZXR1cm4gcGtnTWFpbiA/IHBrZ01haW4gOiBuYW1lOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gcmVtb3ZlU2NyaXB0KG5hbWUpIHsKICAgICAgICAgICAgaWYgKGlzQnJvd3NlcikgewogICAgICAgICAgICAgICAgZWFjaChzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHROb2RlKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKHNjcmlwdE5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKSA9PT0gbmFtZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NyaXB0Tm9kZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcmVxdWlyZWNvbnRleHQnKSA9PT0gY29udGV4dC5jb250ZXh0TmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzY3JpcHROb2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoc2NyaXB0Tm9kZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBoYXNQYXRoRmFsbGJhY2soaWQpIHsKICAgICAgICAgICAgdmFyIHBhdGhDb25maWcgPSBnZXRPd24oY29uZmlnLnBhdGhzLCBpZCk7CiAgICAgICAgICAgIGlmIChwYXRoQ29uZmlnICYmIGlzQXJyYXkocGF0aENvbmZpZykgJiYgcGF0aENvbmZpZy5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAvL1BvcCBvZmYgdGhlIGZpcnN0IGFycmF5IHZhbHVlLCBzaW5jZSBpdCBmYWlsZWQsIGFuZAogICAgICAgICAgICAgICAgLy9yZXRyeQogICAgICAgICAgICAgICAgcGF0aENvbmZpZy5zaGlmdCgpOwogICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlLnVuZGVmKGlkKTsKCiAgICAgICAgICAgICAgICAvL0N1c3RvbSByZXF1aXJlIHRoYXQgZG9lcyBub3QgZG8gbWFwIHRyYW5zbGF0aW9uLCBzaW5jZQogICAgICAgICAgICAgICAgLy9JRCBpcyAiYWJzb2x1dGUiLCBhbHJlYWR5IG1hcHBlZC9yZXNvbHZlZC4KICAgICAgICAgICAgICAgIGNvbnRleHQubWFrZVJlcXVpcmUobnVsbCwgewogICAgICAgICAgICAgICAgICAgIHNraXBNYXA6IHRydWUKICAgICAgICAgICAgICAgIH0pKFtpZF0pOwoKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvL1R1cm5zIGEgcGx1Z2luIXJlc291cmNlIHRvIFtwbHVnaW4sIHJlc291cmNlXQogICAgICAgIC8vd2l0aCB0aGUgcGx1Z2luIGJlaW5nIHVuZGVmaW5lZCBpZiB0aGUgbmFtZQogICAgICAgIC8vZGlkIG5vdCBoYXZlIGEgcGx1Z2luIHByZWZpeC4KICAgICAgICBmdW5jdGlvbiBzcGxpdFByZWZpeChuYW1lKSB7CiAgICAgICAgICAgIHZhciBwcmVmaXgsCiAgICAgICAgICAgICAgICBpbmRleCA9IG5hbWUgPyBuYW1lLmluZGV4T2YoJyEnKSA6IC0xOwogICAgICAgICAgICBpZiAoaW5kZXggPiAtMSkgewogICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZS5zdWJzdHJpbmcoMCwgaW5kZXgpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyaW5nKGluZGV4ICsgMSwgbmFtZS5sZW5ndGgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBbcHJlZml4LCBuYW1lXTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBtb2R1bGUgbWFwcGluZyB0aGF0IGluY2x1ZGVzIHBsdWdpbiBwcmVmaXgsIG1vZHVsZQogICAgICAgICAqIG5hbWUsIGFuZCBwYXRoLiBJZiBwYXJlbnRNb2R1bGVNYXAgaXMgcHJvdmlkZWQgaXQgd2lsbAogICAgICAgICAqIGFsc28gbm9ybWFsaXplIHRoZSBuYW1lIHZpYSByZXF1aXJlLm5vcm1hbGl6ZSgpCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSB0aGUgbW9kdWxlIG5hbWUKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gW3BhcmVudE1vZHVsZU1hcF0gcGFyZW50IG1vZHVsZSBtYXAKICAgICAgICAgKiBmb3IgdGhlIG1vZHVsZSBuYW1lLCB1c2VkIHRvIHJlc29sdmUgcmVsYXRpdmUgbmFtZXMuCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBpc05vcm1hbGl6ZWQ6IGlzIHRoZSBJRCBhbHJlYWR5IG5vcm1hbGl6ZWQuCiAgICAgICAgICogVGhpcyBpcyB0cnVlIGlmIHRoaXMgY2FsbCBpcyBkb25lIGZvciBhIGRlZmluZSgpIG1vZHVsZSBJRC4KICAgICAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGx5TWFwOiBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgSUQuCiAgICAgICAgICogU2hvdWxkIG9ubHkgYmUgdHJ1ZSBpZiB0aGlzIG1hcCBpcyBmb3IgYSBkZXBlbmRlbmN5LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge09iamVjdH0KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBtYWtlTW9kdWxlTWFwKG5hbWUsIHBhcmVudE1vZHVsZU1hcCwgaXNOb3JtYWxpemVkLCBhcHBseU1hcCkgewogICAgICAgICAgICB2YXIgdXJsLCBwbHVnaW5Nb2R1bGUsIHN1ZmZpeCwgbmFtZVBhcnRzLAogICAgICAgICAgICAgICAgcHJlZml4ID0gbnVsbCwKICAgICAgICAgICAgICAgIHBhcmVudE5hbWUgPSBwYXJlbnRNb2R1bGVNYXAgPyBwYXJlbnRNb2R1bGVNYXAubmFtZSA6IG51bGwsCiAgICAgICAgICAgICAgICBvcmlnaW5hbE5hbWUgPSBuYW1lLAogICAgICAgICAgICAgICAgaXNEZWZpbmUgPSB0cnVlLAogICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUgPSAnJzsKCiAgICAgICAgICAgIC8vSWYgbm8gbmFtZSwgdGhlbiBpdCBtZWFucyBpdCBpcyBhIHJlcXVpcmUgY2FsbCwgZ2VuZXJhdGUgYW4KICAgICAgICAgICAgLy9pbnRlcm5hbCBuYW1lLgogICAgICAgICAgICBpZiAoIW5hbWUpIHsKICAgICAgICAgICAgICAgIGlzRGVmaW5lID0gZmFsc2U7CiAgICAgICAgICAgICAgICBuYW1lID0gJ19AcicgKyAocmVxdWlyZUNvdW50ZXIgKz0gMSk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIG5hbWVQYXJ0cyA9IHNwbGl0UHJlZml4KG5hbWUpOwogICAgICAgICAgICBwcmVmaXggPSBuYW1lUGFydHNbMF07CiAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHNbMV07CgogICAgICAgICAgICBpZiAocHJlZml4KSB7CiAgICAgICAgICAgICAgICBwcmVmaXggPSBub3JtYWxpemUocHJlZml4LCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICBwbHVnaW5Nb2R1bGUgPSBnZXRPd24oZGVmaW5lZCwgcHJlZml4KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9BY2NvdW50IGZvciByZWxhdGl2ZSBwYXRocyBpZiB0aGVyZSBpcyBhIGJhc2UgbmFtZS4KICAgICAgICAgICAgaWYgKG5hbWUpIHsKICAgICAgICAgICAgICAgIGlmIChwcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICBpZiAocGx1Z2luTW9kdWxlICYmIHBsdWdpbk1vZHVsZS5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9QbHVnaW4gaXMgbG9hZGVkLCB1c2UgaXRzIG5vcm1hbGl6ZSBtZXRob2QuCiAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gcGx1Z2luTW9kdWxlLm5vcm1hbGl6ZShuYW1lLCBmdW5jdGlvbiAobmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIG5lc3RlZCBwbHVnaW4gcmVmZXJlbmNlcywgdGhlbiBkbyBub3QgdHJ5IHRvCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSwgYXMgaXQgd2lsbCBub3Qgbm9ybWFsaXplIGNvcnJlY3RseS4gVGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvLyBwbGFjZXMgYSByZXN0cmljdGlvbiBvbiByZXNvdXJjZUlkcywgYW5kIHRoZSBsb25nZXIKICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGVybSBzb2x1dGlvbiBpcyBub3QgdG8gbm9ybWFsaXplIHVudGlsIHBsdWdpbnMgYXJlCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvYWRlZCBhbmQgYWxsIG5vcm1hbGl6YXRpb25zIHRvIGFsbG93IGZvciBhc3luYwogICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2FkaW5nIG9mIGEgbG9hZGVyIHBsdWdpbi4gQnV0IGZvciBub3csIGZpeGVzIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAvLyBjb21tb24gdXNlcy4gRGV0YWlscyBpbiAjMTEzMQogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5hbWUuaW5kZXhPZignIScpID09PSAtMSA/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplKG5hbWUsIHBhcmVudE5hbWUsIGFwcGx5TWFwKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIC8vQSByZWd1bGFyIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CgogICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplZCBuYW1lIG1heSBiZSBhIHBsdWdpbiBJRCBkdWUgdG8gbWFwIGNvbmZpZwogICAgICAgICAgICAgICAgICAgIC8vYXBwbGljYXRpb24gaW4gbm9ybWFsaXplLiBUaGUgbWFwIGNvbmZpZyB2YWx1ZXMgbXVzdAogICAgICAgICAgICAgICAgICAgIC8vYWxyZWFkeSBiZSBub3JtYWxpemVkLCBzbyBkbyBub3QgbmVlZCB0byByZWRvIHRoYXQgcGFydC4KICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMgPSBzcGxpdFByZWZpeChub3JtYWxpemVkTmFtZSk7CiAgICAgICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZVBhcnRzWzBdOwogICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gbmFtZVBhcnRzWzFdOwogICAgICAgICAgICAgICAgICAgIGlzTm9ybWFsaXplZCA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIHVybCA9IGNvbnRleHQubmFtZVRvVXJsKG5vcm1hbGl6ZWROYW1lKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiB0aGUgaWQgaXMgYSBwbHVnaW4gaWQgdGhhdCBjYW5ub3QgYmUgZGV0ZXJtaW5lZCBpZiBpdCBuZWVkcwogICAgICAgICAgICAvL25vcm1hbGl6YXRpb24sIHN0YW1wIGl0IHdpdGggYSB1bmlxdWUgSUQgc28gdHdvIG1hdGNoaW5nIHJlbGF0aXZlCiAgICAgICAgICAgIC8vaWRzIHRoYXQgbWF5IGNvbmZsaWN0IGNhbiBiZSBzZXBhcmF0ZS4KICAgICAgICAgICAgc3VmZml4ID0gcHJlZml4ICYmICFwbHVnaW5Nb2R1bGUgJiYgIWlzTm9ybWFsaXplZCA/CiAgICAgICAgICAgICAgICAgICAgICdfdW5ub3JtYWxpemVkJyArICh1bm5vcm1hbGl6ZWRDb3VudGVyICs9IDEpIDoKICAgICAgICAgICAgICAgICAgICAgJyc7CgogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcHJlZml4OiBwcmVmaXgsCiAgICAgICAgICAgICAgICBuYW1lOiBub3JtYWxpemVkTmFtZSwKICAgICAgICAgICAgICAgIHBhcmVudE1hcDogcGFyZW50TW9kdWxlTWFwLAogICAgICAgICAgICAgICAgdW5ub3JtYWxpemVkOiAhIXN1ZmZpeCwKICAgICAgICAgICAgICAgIHVybDogdXJsLAogICAgICAgICAgICAgICAgb3JpZ2luYWxOYW1lOiBvcmlnaW5hbE5hbWUsCiAgICAgICAgICAgICAgICBpc0RlZmluZTogaXNEZWZpbmUsCiAgICAgICAgICAgICAgICBpZDogKHByZWZpeCA/CiAgICAgICAgICAgICAgICAgICAgICAgIHByZWZpeCArICchJyArIG5vcm1hbGl6ZWROYW1lIDoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUpICsgc3VmZml4CiAgICAgICAgICAgIH07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBnZXRNb2R1bGUoZGVwTWFwKSB7CiAgICAgICAgICAgIHZhciBpZCA9IGRlcE1hcC5pZCwKICAgICAgICAgICAgICAgIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwoKICAgICAgICAgICAgaWYgKCFtb2QpIHsKICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXSA9IG5ldyBjb250ZXh0Lk1vZHVsZShkZXBNYXApOwogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gbW9kOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gb24oZGVwTWFwLCBuYW1lLCBmbikgewogICAgICAgICAgICB2YXIgaWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIGlkKTsKCiAgICAgICAgICAgIGlmIChoYXNQcm9wKGRlZmluZWQsIGlkKSAmJgogICAgICAgICAgICAgICAgICAgICghbW9kIHx8IG1vZC5kZWZpbmVFbWl0Q29tcGxldGUpKSB7CiAgICAgICAgICAgICAgICBpZiAobmFtZSA9PT0gJ2RlZmluZWQnKSB7CiAgICAgICAgICAgICAgICAgICAgZm4oZGVmaW5lZFtpZF0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgbW9kID0gZ2V0TW9kdWxlKGRlcE1hcCk7CiAgICAgICAgICAgICAgICBpZiAobW9kLmVycm9yICYmIG5hbWUgPT09ICdlcnJvcicpIHsKICAgICAgICAgICAgICAgICAgICBmbihtb2QuZXJyb3IpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBtb2Qub24obmFtZSwgZm4pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBvbkVycm9yKGVyciwgZXJyYmFjaykgewogICAgICAgICAgICB2YXIgaWRzID0gZXJyLnJlcXVpcmVNb2R1bGVzLAogICAgICAgICAgICAgICAgbm90aWZpZWQgPSBmYWxzZTsKCiAgICAgICAgICAgIGlmIChlcnJiYWNrKSB7CiAgICAgICAgICAgICAgICBlcnJiYWNrKGVycik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBlYWNoKGlkcywgZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwogICAgICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9TZXQgZXJyb3Igb24gbW9kdWxlLCBzbyBpdCBza2lwcyB0aW1lb3V0IGNoZWNrcy4KICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVycm9yID0gZXJyOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90aWZpZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIGlmICghbm90aWZpZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdG8gdHJhbnNmZXIgZ2xvYmFsUXVldWUgaXRlbXMgdG8gdGhpcyBjb250ZXh0J3MKICAgICAgICAgKiBkZWZRdWV1ZS4KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiB0YWtlR2xvYmFsUXVldWUoKSB7CiAgICAgICAgICAgIC8vUHVzaCBhbGwgdGhlIGdsb2JhbERlZlF1ZXVlIGl0ZW1zIGludG8gdGhlIGNvbnRleHQncyBkZWZRdWV1ZQogICAgICAgICAgICBpZiAoZ2xvYmFsRGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBlYWNoKGdsb2JhbERlZlF1ZXVlLCBmdW5jdGlvbihxdWV1ZUl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQgPSBxdWV1ZUl0ZW1bMF07CiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcFtpZF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBkZWZRdWV1ZS5wdXNoKHF1ZXVlSXRlbSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGdsb2JhbERlZlF1ZXVlID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGhhbmRsZXJzID0gewogICAgICAgICAgICAncmVxdWlyZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QucmVxdWlyZSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBtb2QucmVxdWlyZTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChtb2QucmVxdWlyZSA9IGNvbnRleHQubWFrZVJlcXVpcmUobW9kLm1hcCkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAnZXhwb3J0cyc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIG1vZC51c2luZ0V4cG9ydHMgPSB0cnVlOwogICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChkZWZpbmVkW21vZC5tYXAuaWRdID0gbW9kLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLmV4cG9ydHMgPSBkZWZpbmVkW21vZC5tYXAuaWRdID0ge30pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgJ21vZHVsZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QubW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vZC5tb2R1bGU7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLm1vZHVsZSA9IHsKICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IG1vZC5tYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIHVyaTogbW9kLm1hcC51cmwsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZzogZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdldE93bihjb25maWcuY29uZmlnLCBtb2QubWFwLmlkKSB8fCB7fTsKICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0czogbW9kLmV4cG9ydHMgfHwgKG1vZC5leHBvcnRzID0ge30pCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjbGVhblJlZ2lzdHJ5KGlkKSB7CiAgICAgICAgICAgIC8vQ2xlYW4gdXAgbWFjaGluZXJ5IHVzZWQgZm9yIHdhaXRpbmcgbW9kdWxlcy4KICAgICAgICAgICAgZGVsZXRlIHJlZ2lzdHJ5W2lkXTsKICAgICAgICAgICAgZGVsZXRlIGVuYWJsZWRSZWdpc3RyeVtpZF07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBicmVha0N5Y2xlKG1vZCwgdHJhY2VkLCBwcm9jZXNzZWQpIHsKICAgICAgICAgICAgdmFyIGlkID0gbW9kLm1hcC5pZDsKCiAgICAgICAgICAgIGlmIChtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgIG1vZC5lbWl0KCdlcnJvcicsIG1vZC5lcnJvcik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB0cmFjZWRbaWRdID0gdHJ1ZTsKICAgICAgICAgICAgICAgIGVhY2gobW9kLmRlcE1hcHMsIGZ1bmN0aW9uIChkZXBNYXAsIGkpIHsKICAgICAgICAgICAgICAgICAgICB2YXIgZGVwSWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlcCA9IGdldE93bihyZWdpc3RyeSwgZGVwSWQpOwoKICAgICAgICAgICAgICAgICAgICAvL09ubHkgZm9yY2UgdGhpbmdzIHRoYXQgaGF2ZSBub3QgY29tcGxldGVkCiAgICAgICAgICAgICAgICAgICAgLy9iZWluZyBkZWZpbmVkLCBzbyBzdGlsbCBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAgICAgLy9hbmQgb25seSBpZiBpdCBoYXMgbm90IGJlZW4gbWF0Y2hlZCB1cAogICAgICAgICAgICAgICAgICAgIC8vaW4gdGhlIG1vZHVsZSBhbHJlYWR5LgogICAgICAgICAgICAgICAgICAgIGlmIChkZXAgJiYgIW1vZC5kZXBNYXRjaGVkW2ldICYmICFwcm9jZXNzZWRbZGVwSWRdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChnZXRPd24odHJhY2VkLCBkZXBJZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZC5kZWZpbmVEZXAoaSwgZGVmaW5lZFtkZXBJZF0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmNoZWNrKCk7IC8vcGFzcyBmYWxzZT8KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrQ3ljbGUoZGVwLCB0cmFjZWQsIHByb2Nlc3NlZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHByb2Nlc3NlZFtpZF0gPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBjaGVja0xvYWRlZCgpIHsKICAgICAgICAgICAgdmFyIGVyciwgdXNpbmdQYXRoRmFsbGJhY2ssCiAgICAgICAgICAgICAgICB3YWl0SW50ZXJ2YWwgPSBjb25maWcud2FpdFNlY29uZHMgKiAxMDAwLAogICAgICAgICAgICAgICAgLy9JdCBpcyBwb3NzaWJsZSB0byBkaXNhYmxlIHRoZSB3YWl0IGludGVydmFsIGJ5IHVzaW5nIHdhaXRTZWNvbmRzIG9mIDAuCiAgICAgICAgICAgICAgICBleHBpcmVkID0gd2FpdEludGVydmFsICYmIChjb250ZXh0LnN0YXJ0VGltZSArIHdhaXRJbnRlcnZhbCkgPCBuZXcgRGF0ZSgpLmdldFRpbWUoKSwKICAgICAgICAgICAgICAgIG5vTG9hZHMgPSBbXSwKICAgICAgICAgICAgICAgIHJlcUNhbGxzID0gW10sCiAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSBmYWxzZSwKICAgICAgICAgICAgICAgIG5lZWRDeWNsZUNoZWNrID0gdHJ1ZTsKCiAgICAgICAgICAgIC8vRG8gbm90IGJvdGhlciBpZiB0aGlzIGNhbGwgd2FzIGEgcmVzdWx0IG9mIGEgY3ljbGUgYnJlYWsuCiAgICAgICAgICAgIGlmIChpbkNoZWNrTG9hZGVkKSB7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGluQ2hlY2tMb2FkZWQgPSB0cnVlOwoKICAgICAgICAgICAgLy9GaWd1cmUgb3V0IHRoZSBzdGF0ZSBvZiBhbGwgdGhlIG1vZHVsZXMuCiAgICAgICAgICAgIGVhY2hQcm9wKGVuYWJsZWRSZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgdmFyIG1hcCA9IG1vZC5tYXAsCiAgICAgICAgICAgICAgICAgICAgbW9kSWQgPSBtYXAuaWQ7CgogICAgICAgICAgICAgICAgLy9Ta2lwIHRoaW5ncyB0aGF0IGFyZSBub3QgZW5hYmxlZCBvciBpbiBlcnJvciBzdGF0ZS4KICAgICAgICAgICAgICAgIGlmICghbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICByZXFDYWxscy5wdXNoKG1vZCk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIHRoZSBtb2R1bGUgc2hvdWxkIGJlIGV4ZWN1dGVkLCBhbmQgaXQgaGFzIG5vdAogICAgICAgICAgICAgICAgICAgIC8vYmVlbiBpbml0ZWQgYW5kIHRpbWUgaXMgdXAsIHJlbWVtYmVyIGl0LgogICAgICAgICAgICAgICAgICAgIGlmICghbW9kLmluaXRlZCAmJiBleHBpcmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoYXNQYXRoRmFsbGJhY2sobW9kSWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2luZ1BhdGhGYWxsYmFjayA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9Mb2Fkcy5wdXNoKG1vZElkKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChtb2RJZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFtb2QuaW5pdGVkICYmIG1vZC5mZXRjaGVkICYmIG1hcC5pc0RlZmluZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW1hcC5wcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vTm8gcmVhc29uIHRvIGtlZXAgbG9va2luZyBmb3IgdW5maW5pc2hlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9sb2FkaW5nLiBJZiB0aGUgb25seSBzdGlsbExvYWRpbmcgaXMgYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9wbHVnaW4gcmVzb3VyY2UgdGhvdWdoLCBrZWVwIGdvaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iZWNhdXNlIGl0IG1heSBiZSB0aGF0IGEgcGx1Z2luIHJlc291cmNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL2lzIHdhaXRpbmcgb24gYSBub24tcGx1Z2luIGN5Y2xlLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChuZWVkQ3ljbGVDaGVjayA9IGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CgogICAgICAgICAgICBpZiAoZXhwaXJlZCAmJiBub0xvYWRzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgLy9JZiB3YWl0IHRpbWUgZXhwaXJlZCwgdGhyb3cgZXJyb3Igb2YgdW5sb2FkZWQgbW9kdWxlcy4KICAgICAgICAgICAgICAgIGVyciA9IG1ha2VFcnJvcigndGltZW91dCcsICdMb2FkIHRpbWVvdXQgZm9yIG1vZHVsZXM6ICcgKyBub0xvYWRzLCBudWxsLCBub0xvYWRzKTsKICAgICAgICAgICAgICAgIGVyci5jb250ZXh0TmFtZSA9IGNvbnRleHQuY29udGV4dE5hbWU7CiAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihlcnIpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL05vdCBleHBpcmVkLCBjaGVjayBmb3IgYSBjeWNsZS4KICAgICAgICAgICAgaWYgKG5lZWRDeWNsZUNoZWNrKSB7CiAgICAgICAgICAgICAgICBlYWNoKHJlcUNhbGxzLCBmdW5jdGlvbiAobW9kKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWtDeWNsZShtb2QsIHt9LCB7fSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiBzdGlsbCB3YWl0aW5nIG9uIGxvYWRzLCBhbmQgdGhlIHdhaXRpbmcgbG9hZCBpcyBzb21ldGhpbmcKICAgICAgICAgICAgLy9vdGhlciB0aGFuIGEgcGx1Z2luIHJlc291cmNlLCBvciB0aGVyZSBhcmUgc3RpbGwgb3V0c3RhbmRpbmcKICAgICAgICAgICAgLy9zY3JpcHRzLCB0aGVuIGp1c3QgdHJ5IGJhY2sgbGF0ZXIuCiAgICAgICAgICAgIGlmICgoIWV4cGlyZWQgfHwgdXNpbmdQYXRoRmFsbGJhY2spICYmIHN0aWxsTG9hZGluZykgewogICAgICAgICAgICAgICAgLy9Tb21ldGhpbmcgaXMgc3RpbGwgd2FpdGluZyB0byBsb2FkLiBXYWl0IGZvciBpdCwgYnV0IG9ubHkKICAgICAgICAgICAgICAgIC8vaWYgYSB0aW1lb3V0IGlzIG5vdCBhbHJlYWR5IGluIGVmZmVjdC4KICAgICAgICAgICAgICAgIGlmICgoaXNCcm93c2VyIHx8IGlzV2ViV29ya2VyKSAmJiAhY2hlY2tMb2FkZWRUaW1lb3V0SWQpIHsKICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrTG9hZGVkKCk7CiAgICAgICAgICAgICAgICAgICAgfSwgNTApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBpbkNoZWNrTG9hZGVkID0gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICBNb2R1bGUgPSBmdW5jdGlvbiAobWFwKSB7CiAgICAgICAgICAgIHRoaXMuZXZlbnRzID0gZ2V0T3duKHVuZGVmRXZlbnRzLCBtYXAuaWQpIHx8IHt9OwogICAgICAgICAgICB0aGlzLm1hcCA9IG1hcDsKICAgICAgICAgICAgdGhpcy5zaGltID0gZ2V0T3duKGNvbmZpZy5zaGltLCBtYXAuaWQpOwogICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHMgPSBbXTsKICAgICAgICAgICAgdGhpcy5kZXBNYXBzID0gW107CiAgICAgICAgICAgIHRoaXMuZGVwTWF0Y2hlZCA9IFtdOwogICAgICAgICAgICB0aGlzLnBsdWdpbk1hcHMgPSB7fTsKICAgICAgICAgICAgdGhpcy5kZXBDb3VudCA9IDA7CgogICAgICAgICAgICAvKiB0aGlzLmV4cG9ydHMgdGhpcy5mYWN0b3J5CiAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcyA9IFtdLAogICAgICAgICAgICAgICB0aGlzLmVuYWJsZWQsIHRoaXMuZmV0Y2hlZAogICAgICAgICAgICAqLwogICAgICAgIH07CgogICAgICAgIE1vZHVsZS5wcm90b3R5cGUgPSB7CiAgICAgICAgICAgIGluaXQ6IGZ1bmN0aW9uIChkZXBNYXBzLCBmYWN0b3J5LCBlcnJiYWNrLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIG5vdCBkbyBtb3JlIGluaXRzIGlmIGFscmVhZHkgZG9uZS4gQ2FuIGhhcHBlbiBpZiB0aGVyZQogICAgICAgICAgICAgICAgLy9hcmUgbXVsdGlwbGUgZGVmaW5lIGNhbGxzIGZvciB0aGUgc2FtZSBtb2R1bGUuIFRoYXQgaXMgbm90CiAgICAgICAgICAgICAgICAvL2Egbm9ybWFsLCBjb21tb24gY2FzZSwgYnV0IGl0IGlzIGFsc28gbm90IHVuZXhwZWN0ZWQuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgdGhpcy5mYWN0b3J5ID0gZmFjdG9yeTsKCiAgICAgICAgICAgICAgICBpZiAoZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgIC8vUmVnaXN0ZXIgZm9yIGVycm9ycyBvbiB0aGlzIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLm9uKCdlcnJvcicsIGVycmJhY2spOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgIC8vSWYgbm8gZXJyYmFjayBhbHJlYWR5LCBidXQgdGhlcmUgYXJlIGVycm9yIGxpc3RlbmVycwogICAgICAgICAgICAgICAgICAgIC8vb24gdGhpcyBtb2R1bGUsIHNldCB1cCBhbiBlcnJiYWNrIHRvIHBhc3MgdG8gdGhlIGRlcHMuCiAgICAgICAgICAgICAgICAgICAgZXJyYmFjayA9IGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0RvIGEgY29weSBvZiB0aGUgZGVwZW5kZW5jeSBhcnJheSwgc28gdGhhdAogICAgICAgICAgICAgICAgLy9zb3VyY2UgaW5wdXRzIGFyZSBub3QgbW9kaWZpZWQuIEZvciBleGFtcGxlCiAgICAgICAgICAgICAgICAvLyJzaGltIiBkZXBzIGFyZSBwYXNzZWQgaW4gaGVyZSBkaXJlY3RseSwgYW5kCiAgICAgICAgICAgICAgICAvL2RvaW5nIGEgZGlyZWN0IG1vZGlmaWNhdGlvbiBvZiB0aGUgZGVwTWFwcyBhcnJheQogICAgICAgICAgICAgICAgLy93b3VsZCBhZmZlY3QgdGhhdCBjb25maWcuCiAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMgPSBkZXBNYXBzICYmIGRlcE1hcHMuc2xpY2UoMCk7CgogICAgICAgICAgICAgICAgdGhpcy5lcnJiYWNrID0gZXJyYmFjazsKCiAgICAgICAgICAgICAgICAvL0luZGljYXRlIHRoaXMgbW9kdWxlIGhhcyBiZSBpbml0aWFsaXplZAogICAgICAgICAgICAgICAgdGhpcy5pbml0ZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIHRoaXMuaWdub3JlID0gb3B0aW9ucy5pZ25vcmU7CgogICAgICAgICAgICAgICAgLy9Db3VsZCBoYXZlIG9wdGlvbiB0byBpbml0IHRoaXMgbW9kdWxlIGluIGVuYWJsZWQgbW9kZSwKICAgICAgICAgICAgICAgIC8vb3IgY291bGQgaGF2ZSBiZWVuIHByZXZpb3VzbHkgbWFya2VkIGFzIGVuYWJsZWQuIEhvd2V2ZXIsCiAgICAgICAgICAgICAgICAvL3RoZSBkZXBlbmRlbmNpZXMgYXJlIG5vdCBrbm93biB1bnRpbCBpbml0IGlzIGNhbGxlZC4gU28KICAgICAgICAgICAgICAgIC8vaWYgZW5hYmxlZCBwcmV2aW91c2x5LCBub3cgdHJpZ2dlciBkZXBlbmRlbmNpZXMgYXMgZW5hYmxlZC4KICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVuYWJsZWQgfHwgdGhpcy5lbmFibGVkKSB7CiAgICAgICAgICAgICAgICAgICAgLy9FbmFibGUgdGhpcyBtb2R1bGUgYW5kIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAvL1dpbGwgY2FsbCB0aGlzLmNoZWNrKCkKICAgICAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmNoZWNrKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBkZWZpbmVEZXA6IGZ1bmN0aW9uIChpLCBkZXBFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAvL0JlY2F1c2Ugb2YgY3ljbGVzLCBkZWZpbmVkIGNhbGxiYWNrIGZvciBhIGdpdmVuCiAgICAgICAgICAgICAgICAvL2V4cG9ydCBjYW4gYmUgY2FsbGVkIG1vcmUgdGhhbiBvbmNlLgogICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRlcE1hdGNoZWRbaV0pIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hdGNoZWRbaV0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwQ291bnQgLT0gMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHNbaV0gPSBkZXBFeHBvcnRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLmZldGNoZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0aGlzLmZldGNoZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIGNvbnRleHQuc3RhcnRUaW1lID0gKG5ldyBEYXRlKCkpLmdldFRpbWUoKTsKCiAgICAgICAgICAgICAgICB2YXIgbWFwID0gdGhpcy5tYXA7CgogICAgICAgICAgICAgICAgLy9JZiB0aGUgbWFuYWdlciBpcyBmb3IgYSBwbHVnaW4gbWFuYWdlZCByZXNvdXJjZSwKICAgICAgICAgICAgICAgIC8vYXNrIHRoZSBwbHVnaW4gdG8gbG9hZCBpdCBub3cuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5tYWtlUmVxdWlyZSh0aGlzLm1hcCwgewogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVCdWlsZENhbGxiYWNrOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgfSkodGhpcy5zaGltLmRlcHMgfHwgW10sIGJpbmQodGhpcywgZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgfSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL1JlZ3VsYXIgZGVwZW5kZW5jeS4KICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBsb2FkOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICB2YXIgdXJsID0gdGhpcy5tYXAudXJsOwoKICAgICAgICAgICAgICAgIC8vUmVndWxhciBkZXBlbmRlbmN5LgogICAgICAgICAgICAgICAgaWYgKCF1cmxGZXRjaGVkW3VybF0pIHsKICAgICAgICAgICAgICAgICAgICB1cmxGZXRjaGVkW3VybF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIGNvbnRleHQubG9hZCh0aGlzLm1hcC5pZCwgdXJsKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBDaGVja3MgaWYgdGhlIG1vZHVsZSBpcyByZWFkeSB0byBkZWZpbmUgaXRzZWxmLCBhbmQgaWYgc28sCiAgICAgICAgICAgICAqIGRlZmluZSBpdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNoZWNrOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZW5hYmxlZCB8fCB0aGlzLmVuYWJsaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHZhciBlcnIsIGNqc01vZHVsZSwKICAgICAgICAgICAgICAgICAgICBpZCA9IHRoaXMubWFwLmlkLAogICAgICAgICAgICAgICAgICAgIGRlcEV4cG9ydHMgPSB0aGlzLmRlcEV4cG9ydHMsCiAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0cywKICAgICAgICAgICAgICAgICAgICBmYWN0b3J5ID0gdGhpcy5mYWN0b3J5OwoKICAgICAgICAgICAgICAgIGlmICghdGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGZldGNoIGlmIG5vdCBhbHJlYWR5IGluIHRoZSBkZWZRdWV1ZS4KICAgICAgICAgICAgICAgICAgICBpZiAoIWhhc1Byb3AoY29udGV4dC5kZWZRdWV1ZU1hcCwgaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZmV0Y2goKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgdGhpcy5lcnJvcik7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLmRlZmluaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgLy9UaGUgZmFjdG9yeSBjb3VsZCB0cmlnZ2VyIGFub3RoZXIgcmVxdWlyZSBjYWxsCiAgICAgICAgICAgICAgICAgICAgLy90aGF0IHdvdWxkIHJlc3VsdCBpbiBjaGVja2luZyB0aGlzIG1vZHVsZSB0bwogICAgICAgICAgICAgICAgICAgIC8vZGVmaW5lIGl0c2VsZiBhZ2Fpbi4gSWYgYWxyZWFkeSBpbiB0aGUgcHJvY2VzcwogICAgICAgICAgICAgICAgICAgIC8vb2YgZG9pbmcgdGhhdCwgc2tpcCB0aGlzIHdvcmsuCiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWZpbmluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlcENvdW50IDwgMSAmJiAhdGhpcy5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0Z1bmN0aW9uKGZhY3RvcnkpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjb250ZXh0LmV4ZWNDYihpZCwgZmFjdG9yeSwgZGVwRXhwb3J0cywgZXhwb3J0cyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyID0gZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGYXZvciByZXR1cm4gdmFsdWUgb3ZlciBleHBvcnRzLiBJZiBub2RlL2NqcyBpbiBwbGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlbiB3aWxsIG5vdCBoYXZlIGEgcmV0dXJuIHZhbHVlIGFueXdheS4gRmF2b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1vZHVsZS5leHBvcnRzIGFzc2lnbm1lbnQgb3ZlciBleHBvcnRzIG9iamVjdC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hcC5pc0RlZmluZSAmJiBleHBvcnRzID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjanNNb2R1bGUgPSB0aGlzLm1vZHVsZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2pzTW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjanNNb2R1bGUuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMudXNpbmdFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vZXhwb3J0cyBhbHJlYWR5IHNldCB0aGUgZGVmaW5lZCB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZXJlIGlzIGFuIGVycm9yIGxpc3RlbmVyLCBmYXZvciBwYXNzaW5nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdG8gdGhhdCBpbnN0ZWFkIG9mIHRocm93aW5nIGFuIGVycm9yLiBIb3dldmVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9ubHkgZG8gaXQgZm9yIGRlZmluZSgpJ2QgIG1vZHVsZXMuIHJlcXVpcmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBlcnJiYWNrcyBzaG91bGQgbm90IGJlIGNhbGxlZCBmb3IgZmFpbHVyZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGVpciBjYWxsYmFja3MgKCM2OTkpLiBIb3dldmVyIGlmIGEgZ2xvYmFsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb25FcnJvciBpcyBzZXQsIHVzZSB0aGF0LgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodGhpcy5ldmVudHMuZXJyb3IgJiYgdGhpcy5tYXAuaXNEZWZpbmUpIHx8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5vbkVycm9yICE9PSBkZWZhdWx0T25FcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1hcCA9IHRoaXMubWFwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1vZHVsZXMgPSB0aGlzLm1hcC5pc0RlZmluZSA/IFt0aGlzLm1hcC5pZF0gOiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZVR5cGUgPSB0aGlzLm1hcC5pc0RlZmluZSA/ICdkZWZpbmUnIDogJ3JlcXVpcmUnOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcigodGhpcy5lcnJvciA9IGVycikpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvZyB0aGUgZXJyb3IgZm9yIGRlYnVnZ2luZy4gSWYgcHJvbWlzZXMgY291bGQgYmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXNlZCwgdGhpcyB3b3VsZCBiZSBkaWZmZXJlbnQsIGJ1dCBtYWtpbmcgZG8uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBEbyBub3Qgd2FudCB0byBjb21wbGV0ZWx5IGxvc2UgdGhlIGVycm9yLiBXaGlsZSB0aGlzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpbGwgbWVzcyB1cCBwcm9jZXNzaW5nIGFuZCBsZWFkIHRvIHNpbWlsYXIgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcyBidWcgMTQ0MCwgaXQgYXQgbGVhc3Qgc3VyZmFjZXMgdGhlIGVycm9yLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIGxpdGVyYWwgdmFsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBmYWN0b3J5OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmV4cG9ydHMgPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubWFwLmlzRGVmaW5lICYmICF0aGlzLmlnbm9yZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmaW5lZFtpZF0gPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEub25SZXNvdXJjZUxvYWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzTG9hZE1hcHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNMb2FkTWFwcy5wdXNoKGRlcE1hcC5ub3JtYWxpemVkTWFwIHx8IGRlcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxLm9uUmVzb3VyY2VMb2FkKGNvbnRleHQsIHRoaXMubWFwLCByZXNMb2FkTWFwcyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQ2xlYW4gdXAKICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9GaW5pc2hlZCB0aGUgZGVmaW5lIHN0YWdlLiBBbGxvdyBjYWxsaW5nIGNoZWNrIGFnYWluCiAgICAgICAgICAgICAgICAgICAgLy90byBhbGxvdyBkZWZpbmUgbm90aWZpY2F0aW9ucyBiZWxvdyBpbiB0aGUgY2FzZSBvZiBhCiAgICAgICAgICAgICAgICAgICAgLy9jeWNsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluaW5nID0gZmFsc2U7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlZmluZWQgJiYgIXRoaXMuZGVmaW5lRW1pdHRlZCkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXR0ZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2RlZmluZWQnLCB0aGlzLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXRDb21wbGV0ZSA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGNhbGxQbHVnaW46IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHZhciBtYXAgPSB0aGlzLm1hcCwKICAgICAgICAgICAgICAgICAgICBpZCA9IG1hcC5pZCwKICAgICAgICAgICAgICAgICAgICAvL01hcCBhbHJlYWR5IG5vcm1hbGl6ZWQgdGhlIHByZWZpeC4KICAgICAgICAgICAgICAgICAgICBwbHVnaW5NYXAgPSBtYWtlTW9kdWxlTWFwKG1hcC5wcmVmaXgpOwoKICAgICAgICAgICAgICAgIC8vTWFyayB0aGlzIGFzIGEgZGVwZW5kZW5jeSBmb3IgdGhpcyBwbHVnaW4sIHNvIGl0CiAgICAgICAgICAgICAgICAvL2NhbiBiZSB0cmFjZWQgZm9yIGN5Y2xlcy4KICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcy5wdXNoKHBsdWdpbk1hcCk7CgogICAgICAgICAgICAgICAgb24ocGx1Z2luTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbikgewogICAgICAgICAgICAgICAgICAgIHZhciBsb2FkLCBub3JtYWxpemVkTWFwLCBub3JtYWxpemVkTW9kLAogICAgICAgICAgICAgICAgICAgICAgICBidW5kbGVJZCA9IGdldE93bihidW5kbGVzTWFwLCB0aGlzLm1hcC5pZCksCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSB0aGlzLm1hcC5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnROYW1lID0gdGhpcy5tYXAucGFyZW50TWFwID8gdGhpcy5tYXAucGFyZW50TWFwLm5hbWUgOiBudWxsLAogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKG1hcC5wYXJlbnRNYXAsIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZUJ1aWxkQ2FsbGJhY2s6IHRydWUKICAgICAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgICAgIC8vSWYgY3VycmVudCBtYXAgaXMgbm90IG5vcm1hbGl6ZWQsIHdhaXQgZm9yIHRoYXQKICAgICAgICAgICAgICAgICAgICAvL25vcm1hbGl6ZWQgbmFtZSB0byBsb2FkIGluc3RlYWQgb2YgY29udGludWluZy4KICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5tYXAudW5ub3JtYWxpemVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIHRoZSBJRCBpZiB0aGUgcGx1Z2luIGFsbG93cyBpdC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBsdWdpbi5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBwbHVnaW4ubm9ybWFsaXplKG5hbWUsIGZ1bmN0aW9uIChuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pIHx8ICcnOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL3ByZWZpeCBhbmQgbmFtZSBzaG91bGQgYWxyZWFkeSBiZSBub3JtYWxpemVkLCBubyBuZWVkCiAgICAgICAgICAgICAgICAgICAgICAgIC8vZm9yIGFwcGx5aW5nIG1hcCBjb25maWcgYWdhaW4gZWl0aGVyLgogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTWFwID0gbWFrZU1vZHVsZU1hcChtYXAucHJlZml4ICsgJyEnICsgbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXAucGFyZW50TWFwKTsKICAgICAgICAgICAgICAgICAgICAgICAgb24obm9ybWFsaXplZE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkZWZpbmVkJywgYmluZCh0aGlzLCBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hcC5ub3JtYWxpemVkTWFwID0gbm9ybWFsaXplZE1hcDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZTogdHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE1vZCA9IGdldE93bihyZWdpc3RyeSwgbm9ybWFsaXplZE1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkTW9kKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL01hcmsgdGhpcyBhcyBhIGRlcGVuZGVuY3kgZm9yIHRoaXMgcGx1Z2luLCBzbyBpdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9jYW4gYmUgdHJhY2VkIGZvciBjeWNsZXMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMucHVzaChub3JtYWxpemVkTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5ldmVudHMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLm9uKCdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0lmIGEgcGF0aHMgY29uZmlnLCB0aGVuIGp1c3QgbG9hZCB0aGF0IGZpbGUgaW5zdGVhZCB0bwogICAgICAgICAgICAgICAgICAgIC8vcmVzb2x2ZSB0aGUgcGx1Z2luLCBhcyBpdCBpcyBidWlsdCBpbnRvIHRoYXQgcGF0aHMgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWFwLnVybCA9IGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkKTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGxvYWQgPSBiaW5kKHRoaXMsIGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICBsb2FkLmVycm9yID0gYmluZCh0aGlzLCBmdW5jdGlvbiAoZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdGVkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycjsKICAgICAgICAgICAgICAgICAgICAgICAgZXJyLnJlcXVpcmVNb2R1bGVzID0gW2lkXTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vUmVtb3ZlIHRlbXAgdW5ub3JtYWxpemVkIG1vZHVsZXMgZm9yIHRoaXMgbW9kdWxlLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NpbmNlIHRoZXkgd2lsbCBuZXZlciBiZSByZXNvbHZlZCBvdGhlcndpc2Ugbm93LgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaWQuaW5kZXhPZihpZCArICdfdW5ub3JtYWxpemVkJykgPT09IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhblJlZ2lzdHJ5KG1vZC5tYXAuaWQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9BbGxvdyBwbHVnaW5zIHRvIGxvYWQgb3RoZXIgY29kZSB3aXRob3V0IGhhdmluZyB0byBrbm93IHRoZQogICAgICAgICAgICAgICAgICAgIC8vY29udGV4dCBvciBob3cgdG8gJ2NvbXBsZXRlJyB0aGUgbG9hZC4KICAgICAgICAgICAgICAgICAgICBsb2FkLmZyb21UZXh0ID0gYmluZCh0aGlzLCBmdW5jdGlvbiAodGV4dCwgdGV4dEFsdCkgewogICAgICAgICAgICAgICAgICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtb2R1bGVOYW1lID0gbWFwLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVNYXAgPSBtYWtlTW9kdWxlTWFwKG1vZHVsZU5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzSW50ZXJhY3RpdmUgPSB1c2VJbnRlcmFjdGl2ZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQXMgb2YgMi4xLjAsIHN1cHBvcnQganVzdCBwYXNzaW5nIHRoZSB0ZXh0LCB0byByZWluZm9yY2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9mcm9tVGV4dCBvbmx5IGJlaW5nIGNhbGxlZCBvbmNlIHBlciByZXNvdXJjZS4gU3RpbGwKICAgICAgICAgICAgICAgICAgICAgICAgLy9zdXBwb3J0IG9sZCBzdHlsZSBvZiBwYXNzaW5nIG1vZHVsZU5hbWUgYnV0IGRpc2NhcmQKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGF0IG1vZHVsZU5hbWUgaW4gZmF2b3Igb2YgdGhlIGludGVybmFsIHJlZi4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRleHRBbHQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQgPSB0ZXh0QWx0OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1R1cm4gb2ZmIGludGVyYWN0aXZlIHNjcmlwdCBtYXRjaGluZyBmb3IgSUUgZm9yIGFueSBkZWZpbmUKICAgICAgICAgICAgICAgICAgICAgICAgLy9jYWxscyBpbiB0aGUgdGV4dCwgdGhlbiB0dXJuIGl0IGJhY2sgb24gYXQgdGhlIGVuZC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0ludGVyYWN0aXZlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1ByaW1lIHRoZSBzeXN0ZW0gYnkgY3JlYXRpbmcgYSBtb2R1bGUgaW5zdGFuY2UgZm9yCiAgICAgICAgICAgICAgICAgICAgICAgIC8vaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGdldE1vZHVsZShtb2R1bGVNYXApOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9UcmFuc2ZlciBhbnkgY29uZmlnIHRvIHRoaXMgb3RoZXIgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzUHJvcChjb25maWcuY29uZmlnLCBpZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5jb25maWdbbW9kdWxlTmFtZV0gPSBjb25maWcuY29uZmlnW2lkXTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5leGVjKHRleHQpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ2Zyb210ZXh0ZXZhbCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdmcm9tVGV4dCBldmFsIGZvciAnICsgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcgZmFpbGVkOiAnICsgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2lkXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXJrIHRoaXMgYXMgYSBkZXBlbmRlbmN5IGZvciB0aGUgcGx1Z2luCiAgICAgICAgICAgICAgICAgICAgICAgIC8vcmVzb3VyY2UKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBNYXBzLnB1c2gobW9kdWxlTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3VwcG9ydCBhbm9ueW1vdXMgbW9kdWxlcy4KICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQobW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgdGhlIHZhbHVlIG9mIHRoYXQgbW9kdWxlIHRvIHRoZSB2YWx1ZSBmb3IgdGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvL3Jlc291cmNlIElELgogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUoW21vZHVsZU5hbWVdLCBsb2FkKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9Vc2UgcGFyZW50TmFtZSBoZXJlIHNpbmNlIHRoZSBwbHVnaW4ncyBuYW1lIGlzIG5vdCByZWxpYWJsZSwKICAgICAgICAgICAgICAgICAgICAvL2NvdWxkIGJlIHNvbWUgd2VpcmQgc3RyaW5nIHdpdGggbm8gcGF0aCB0aGF0IGFjdHVhbGx5IHdhbnRzIHRvCiAgICAgICAgICAgICAgICAgICAgLy9yZWZlcmVuY2UgdGhlIHBhcmVudE5hbWUncyBwYXRoLgogICAgICAgICAgICAgICAgICAgIHBsdWdpbi5sb2FkKG1hcC5uYW1lLCBsb2NhbFJlcXVpcmUsIGxvYWQsIGNvbmZpZyk7CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luTWFwc1twbHVnaW5NYXAuaWRdID0gcGx1Z2luTWFwOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZW5hYmxlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBlbmFibGVkUmVnaXN0cnlbdGhpcy5tYXAuaWRdID0gdGhpczsKICAgICAgICAgICAgICAgIHRoaXMuZW5hYmxlZCA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9TZXQgZmxhZyBtZW50aW9uaW5nIHRoYXQgdGhlIG1vZHVsZSBpcyBlbmFibGluZywKICAgICAgICAgICAgICAgIC8vc28gdGhhdCBpbW1lZGlhdGUgY2FsbHMgdG8gdGhlIGRlZmluZWQgY2FsbGJhY2tzCiAgICAgICAgICAgICAgICAvL2ZvciBkZXBlbmRlbmNpZXMgZG8gbm90IHRyaWdnZXIgaW5hZHZlcnRlbnQgbG9hZAogICAgICAgICAgICAgICAgLy93aXRoIHRoZSBkZXBDb3VudCBzdGlsbCBiZWluZyB6ZXJvLgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9FbmFibGUgZWFjaCBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgYmluZCh0aGlzLCBmdW5jdGlvbiAoZGVwTWFwLCBpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIGlkLCBtb2QsIGhhbmRsZXI7CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwTWFwID09PSAnc3RyaW5nJykgewogICAgICAgICAgICAgICAgICAgICAgICAvL0RlcGVuZGVuY3kgbmVlZHMgdG8gYmUgY29udmVydGVkIHRvIGEgZGVwTWFwCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYW5kIHdpcmVkIHVwIHRvIHRoaXMgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBkZXBNYXAgPSBtYWtlTW9kdWxlTWFwKGRlcE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5tYXAuaXNEZWZpbmUgPyB0aGlzLm1hcCA6IHRoaXMubWFwLnBhcmVudE1hcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIXRoaXMuc2tpcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwc1tpXSA9IGRlcE1hcDsKCiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZXIgPSBnZXRPd24oaGFuZGxlcnMsIGRlcE1hcC5pZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBFeHBvcnRzW2ldID0gaGFuZGxlcih0aGlzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBDb3VudCArPSAxOwoKICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKGRlcEV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnVuZGVmZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZURlcChpLCBkZXBFeHBvcnRzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZXJyb3InLCBiaW5kKHRoaXMsIHRoaXMuZXJyYmFjaykpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXZlbnRzLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBObyBkaXJlY3QgZXJyYmFjayBvbiB0aGlzIG1vZHVsZSwgYnV0IHNvbWV0aGluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWxzZSBpcyBsaXN0ZW5pbmcgZm9yIGVycm9ycywgc28gYmUgc3VyZSB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJvcGFnYXRlIHRoZSBlcnJvciBjb3JyZWN0bHkuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbihkZXBNYXAsICdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24oZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIGVycik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlkID0gZGVwTWFwLmlkOwogICAgICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXTsKCiAgICAgICAgICAgICAgICAgICAgLy9Ta2lwIHNwZWNpYWwgbW9kdWxlcyBsaWtlICdyZXF1aXJlJywgJ2V4cG9ydHMnLCAnbW9kdWxlJwogICAgICAgICAgICAgICAgICAgIC8vQWxzbywgZG9uJ3QgY2FsbCBlbmFibGUgaWYgaXQgaXMgYWxyZWFkeSBlbmFibGVkLAogICAgICAgICAgICAgICAgICAgIC8vaW1wb3J0YW50IGluIGNpcmN1bGFyIGRlcGVuZGVuY3kgY2FzZXMuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGhhbmRsZXJzLCBpZCkgJiYgbW9kICYmICFtb2QuZW5hYmxlZCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmVuYWJsZShkZXBNYXAsIHRoaXMpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pKTsKCiAgICAgICAgICAgICAgICAvL0VuYWJsZSBlYWNoIHBsdWdpbiB0aGF0IGlzIHVzZWQgaW4KICAgICAgICAgICAgICAgIC8vYSBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoUHJvcCh0aGlzLnBsdWdpbk1hcHMsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbk1hcCkgewogICAgICAgICAgICAgICAgICAgIHZhciBtb2QgPSBnZXRPd24ocmVnaXN0cnksIHBsdWdpbk1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCAmJiAhbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IGZhbHNlOwoKICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG9uOiBmdW5jdGlvbiAobmFtZSwgY2IpIHsKICAgICAgICAgICAgICAgIHZhciBjYnMgPSB0aGlzLmV2ZW50c1tuYW1lXTsKICAgICAgICAgICAgICAgIGlmICghY2JzKSB7CiAgICAgICAgICAgICAgICAgICAgY2JzID0gdGhpcy5ldmVudHNbbmFtZV0gPSBbXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNicy5wdXNoKGNiKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGVtaXQ6IGZ1bmN0aW9uIChuYW1lLCBldnQpIHsKICAgICAgICAgICAgICAgIGVhY2godGhpcy5ldmVudHNbbmFtZV0sIGZ1bmN0aW9uIChjYikgewogICAgICAgICAgICAgICAgICAgIGNiKGV2dCk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGlmIChuYW1lID09PSAnZXJyb3InKSB7CiAgICAgICAgICAgICAgICAgICAgLy9Ob3cgdGhhdCB0aGUgZXJyb3IgaGFuZGxlciB3YXMgdHJpZ2dlcmVkLCByZW1vdmUKICAgICAgICAgICAgICAgICAgICAvL3RoZSBsaXN0ZW5lcnMsIHNpbmNlIHRoaXMgYnJva2VuIE1vZHVsZSBpbnN0YW5jZQogICAgICAgICAgICAgICAgICAgIC8vY2FuIHN0YXkgYXJvdW5kIGZvciBhIHdoaWxlIGluIHRoZSByZWdpc3RyeS4KICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5ldmVudHNbbmFtZV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjYWxsR2V0TW9kdWxlKGFyZ3MpIHsKICAgICAgICAgICAgLy9Ta2lwIG1vZHVsZXMgYWxyZWFkeSBkZWZpbmVkLgogICAgICAgICAgICBpZiAoIWhhc1Byb3AoZGVmaW5lZCwgYXJnc1swXSkpIHsKICAgICAgICAgICAgICAgIGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKGFyZ3NbMF0sIG51bGwsIHRydWUpKS5pbml0KGFyZ3NbMV0sIGFyZ3NbMl0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihub2RlLCBmdW5jLCBuYW1lLCBpZU5hbWUpIHsKICAgICAgICAgICAgLy9GYXZvciBkZXRhY2hFdmVudCBiZWNhdXNlIG9mIElFOQogICAgICAgICAgICAvL2lzc3VlLCBzZWUgYXR0YWNoRXZlbnQvYWRkRXZlbnRMaXN0ZW5lciBjb21tZW50IGVsc2V3aGVyZQogICAgICAgICAgICAvL2luIHRoaXMgZmlsZS4KICAgICAgICAgICAgaWYgKG5vZGUuZGV0YWNoRXZlbnQgJiYgIWlzT3BlcmEpIHsKICAgICAgICAgICAgICAgIC8vUHJvYmFibHkgSUUuIElmIG5vdCBpdCB3aWxsIHRocm93IGFuIGVycm9yLCB3aGljaCB3aWxsIGJlCiAgICAgICAgICAgICAgICAvL3VzZWZ1bCB0byBrbm93LgogICAgICAgICAgICAgICAgaWYgKGllTmFtZSkgewogICAgICAgICAgICAgICAgICAgIG5vZGUuZGV0YWNoRXZlbnQoaWVOYW1lLCBmdW5jKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUucmVtb3ZlRXZlbnRMaXN0ZW5lcihuYW1lLCBmdW5jLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdpdmVuIGFuIGV2ZW50IGZyb20gYSBzY3JpcHQgbm9kZSwgZ2V0IHRoZSByZXF1aXJlanMgaW5mbyBmcm9tIGl0LAogICAgICAgICAqIGFuZCB0aGVuIHJlbW92ZXMgdGhlIGV2ZW50IGxpc3RlbmVycyBvbiB0aGUgbm9kZS4KICAgICAgICAgKiBAcGFyYW0ge0V2ZW50fSBldnQKICAgICAgICAgKiBAcmV0dXJucyB7T2JqZWN0fQogICAgICAgICAqLwogICAgICAgIGZ1bmN0aW9uIGdldFNjcmlwdERhdGEoZXZ0KSB7CiAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgLy9hbGwgb2xkIGJyb3dzZXJzIHdpbGwgYmUgc3VwcG9ydGVkLCBidXQgdGhpcyBvbmUgd2FzIGVhc3kgZW5vdWdoCiAgICAgICAgICAgIC8vdG8gc3VwcG9ydCBhbmQgc3RpbGwgbWFrZXMgc2Vuc2UuCiAgICAgICAgICAgIHZhciBub2RlID0gZXZ0LmN1cnJlbnRUYXJnZXQgfHwgZXZ0LnNyY0VsZW1lbnQ7CgogICAgICAgICAgICAvL1JlbW92ZSB0aGUgbGlzdGVuZXJzIG9uY2UgaGVyZS4KICAgICAgICAgICAgcmVtb3ZlTGlzdGVuZXIobm9kZSwgY29udGV4dC5vblNjcmlwdExvYWQsICdsb2FkJywgJ29ucmVhZHlzdGF0ZWNoYW5nZScpOwogICAgICAgICAgICByZW1vdmVMaXN0ZW5lcihub2RlLCBjb250ZXh0Lm9uU2NyaXB0RXJyb3IsICdlcnJvcicpOwoKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIG5vZGU6IG5vZGUsCiAgICAgICAgICAgICAgICBpZDogbm9kZSAmJiBub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJykKICAgICAgICAgICAgfTsKICAgICAgICB9CgogICAgICAgIGZ1bmN0aW9uIGludGFrZURlZmluZXMoKSB7CiAgICAgICAgICAgIHZhciBhcmdzOwoKICAgICAgICAgICAgLy9BbnkgZGVmaW5lZCBtb2R1bGVzIGluIHRoZSBnbG9iYWwgcXVldWUsIGludGFrZSB0aGVtIG5vdy4KICAgICAgICAgICAgdGFrZUdsb2JhbFF1ZXVlKCk7CgogICAgICAgICAgICAvL01ha2Ugc3VyZSBhbnkgcmVtYWluaW5nIGRlZlF1ZXVlIGl0ZW1zIGdldCBwcm9wZXJseSBwcm9jZXNzZWQuCiAgICAgICAgICAgIHdoaWxlIChkZWZRdWV1ZS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGFyZ3MgPSBkZWZRdWV1ZS5zaGlmdCgpOwogICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ21pc21hdGNoJywgJ01pc21hdGNoZWQgYW5vbnltb3VzIGRlZmluZSgpIG1vZHVsZTogJyArCiAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3NbYXJncy5sZW5ndGggLSAxXSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL2FyZ3MgYXJlIGlkLCBkZXBzLCBmYWN0b3J5LiBTaG91bGQgYmUgbm9ybWFsaXplZCBieSB0aGUKICAgICAgICAgICAgICAgICAgICAvL2RlZmluZSgpIGZ1bmN0aW9uLgogICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoYXJncyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcCA9IHt9OwogICAgICAgIH0KCiAgICAgICAgY29udGV4dCA9IHsKICAgICAgICAgICAgY29uZmlnOiBjb25maWcsCiAgICAgICAgICAgIGNvbnRleHROYW1lOiBjb250ZXh0TmFtZSwKICAgICAgICAgICAgcmVnaXN0cnk6IHJlZ2lzdHJ5LAogICAgICAgICAgICBkZWZpbmVkOiBkZWZpbmVkLAogICAgICAgICAgICB1cmxGZXRjaGVkOiB1cmxGZXRjaGVkLAogICAgICAgICAgICBkZWZRdWV1ZTogZGVmUXVldWUsCiAgICAgICAgICAgIGRlZlF1ZXVlTWFwOiB7fSwKICAgICAgICAgICAgTW9kdWxlOiBNb2R1bGUsCiAgICAgICAgICAgIG1ha2VNb2R1bGVNYXA6IG1ha2VNb2R1bGVNYXAsCiAgICAgICAgICAgIG5leHRUaWNrOiByZXEubmV4dFRpY2ssCiAgICAgICAgICAgIG9uRXJyb3I6IG9uRXJyb3IsCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogU2V0IGEgY29uZmlndXJhdGlvbiBmb3IgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgY29uZmlnIG9iamVjdCB0byBpbnRlZ3JhdGUuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBjb25maWd1cmU6IGZ1bmN0aW9uIChjZmcpIHsKICAgICAgICAgICAgICAgIC8vTWFrZSBzdXJlIHRoZSBiYXNlVXJsIGVuZHMgaW4gYSBzbGFzaC4KICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybC5jaGFyQXQoY2ZnLmJhc2VVcmwubGVuZ3RoIC0gMSkgIT09ICcvJykgewogICAgICAgICAgICAgICAgICAgICAgICBjZmcuYmFzZVVybCArPSAnLyc7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vU2F2ZSBvZmYgdGhlIHBhdGhzIHNpbmNlIHRoZXkgcmVxdWlyZSBzcGVjaWFsIHByb2Nlc3NpbmcsCiAgICAgICAgICAgICAgICAvL3RoZXkgYXJlIGFkZGl0aXZlLgogICAgICAgICAgICAgICAgdmFyIHNoaW0gPSBjb25maWcuc2hpbSwKICAgICAgICAgICAgICAgICAgICBvYmpzID0gewogICAgICAgICAgICAgICAgICAgICAgICBwYXRoczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnOiB0cnVlLAogICAgICAgICAgICAgICAgICAgICAgICBtYXA6IHRydWUKICAgICAgICAgICAgICAgICAgICB9OwoKICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZywgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG9ianNbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjb25maWdbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHt9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIG1peGluKGNvbmZpZ1twcm9wXSwgdmFsdWUsIHRydWUsIHRydWUpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHZhbHVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIC8vUmV2ZXJzZSBtYXAgdGhlIGJ1bmRsZXMKICAgICAgICAgICAgICAgIGlmIChjZmcuYnVuZGxlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZy5idW5kbGVzLCBmdW5jdGlvbiAodmFsdWUsIHByb3ApIHsKICAgICAgICAgICAgICAgICAgICAgICAgZWFjaCh2YWx1ZSwgZnVuY3Rpb24gKHYpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2ICE9PSBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlc01hcFt2XSA9IHByb3A7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vTWVyZ2Ugc2hpbQogICAgICAgICAgICAgICAgaWYgKGNmZy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgZWFjaFByb3AoY2ZnLnNoaW0sIGZ1bmN0aW9uICh2YWx1ZSwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9Ob3JtYWxpemUgdGhlIHN0cnVjdHVyZQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlcHM6IHZhbHVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodmFsdWUuZXhwb3J0cyB8fCB2YWx1ZS5pbml0KSAmJiAhdmFsdWUuZXhwb3J0c0ZuKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5leHBvcnRzRm4gPSBjb250ZXh0Lm1ha2VTaGltRXhwb3J0cyh2YWx1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgc2hpbVtpZF0gPSB2YWx1ZTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICBjb25maWcuc2hpbSA9IHNoaW07CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgLy9BZGp1c3QgcGFja2FnZXMgaWYgbmVjZXNzYXJ5LgogICAgICAgICAgICAgICAgaWYgKGNmZy5wYWNrYWdlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2goY2ZnLnBhY2thZ2VzLCBmdW5jdGlvbiAocGtnT2JqKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsb2NhdGlvbiwgbmFtZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHBrZ09iaiA9IHR5cGVvZiBwa2dPYmogPT09ICdzdHJpbmcnID8ge25hbWU6IHBrZ09ian0gOiBwa2dPYmo7CgogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gcGtnT2JqLm5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gcGtnT2JqLmxvY2F0aW9uOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9jYXRpb24pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5wYXRoc1tuYW1lXSA9IHBrZ09iai5sb2NhdGlvbjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TYXZlIHBvaW50ZXIgdG8gbWFpbiBtb2R1bGUgSUQgZm9yIHBrZyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAvL1JlbW92ZSBsZWFkaW5nIGRvdCBpbiBtYWluLCBzbyBtYWluIHBhdGhzIGFyZSBub3JtYWxpemVkLAogICAgICAgICAgICAgICAgICAgICAgICAvL2FuZCByZW1vdmUgYW55IHRyYWlsaW5nIC5qcywgc2luY2UgZGlmZmVyZW50IHBhY2thZ2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9lbnZzIGhhdmUgZGlmZmVyZW50IGNvbnZlbnRpb25zOiBzb21lIHVzZSBhIG1vZHVsZSBuYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NvbWUgdXNlIGEgZmlsZSBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICBjb25maWcucGtnc1tuYW1lXSA9IHBrZ09iai5uYW1lICsgJy8nICsgKHBrZ09iai5tYWluIHx8ICdtYWluJykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKGN1cnJEaXJSZWdFeHAsICcnKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0lmIHRoZXJlIGFyZSBhbnkgIndhaXRpbmcgdG8gZXhlY3V0ZSIgbW9kdWxlcyBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAvL3VwZGF0ZSB0aGUgbWFwcyBmb3IgdGhlbSwgc2luY2UgdGhlaXIgaW5mbywgbGlrZSBVUkxzIHRvIGxvYWQsCiAgICAgICAgICAgICAgICAvL21heSBoYXZlIGNoYW5nZWQuCiAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIG1vZHVsZSBhbHJlYWR5IGhhcyBpbml0IGNhbGxlZCwgc2luY2UgaXQgaXMgdG9vCiAgICAgICAgICAgICAgICAgICAgLy9sYXRlIHRvIG1vZGlmeSB0aGVtLCBhbmQgaWdub3JlIHVubm9ybWFsaXplZCBvbmVzCiAgICAgICAgICAgICAgICAgICAgLy9zaW5jZSB0aGV5IGFyZSB0cmFuc2llbnQuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFtb2QuaW5pdGVkICYmICFtb2QubWFwLnVubm9ybWFsaXplZCkgewogICAgICAgICAgICAgICAgICAgICAgICBtb2QubWFwID0gbWFrZU1vZHVsZU1hcChpZCwgbnVsbCwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9JZiBhIGRlcHMgYXJyYXkgb3IgYSBjb25maWcgY2FsbGJhY2sgaXMgc3BlY2lmaWVkLCB0aGVuIGNhbGwKICAgICAgICAgICAgICAgIC8vcmVxdWlyZSB3aXRoIHRob3NlIGFyZ3MuIFRoaXMgaXMgdXNlZnVsIHdoZW4gcmVxdWlyZSBpcyBkZWZpbmVkIGFzIGEKICAgICAgICAgICAgICAgIC8vY29uZmlnIG9iamVjdCBiZWZvcmUgcmVxdWlyZS5qcyBpcyBsb2FkZWQuCiAgICAgICAgICAgICAgICBpZiAoY2ZnLmRlcHMgfHwgY2ZnLmNhbGxiYWNrKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlKGNmZy5kZXBzIHx8IFtdLCBjZmcuY2FsbGJhY2spOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgbWFrZVNoaW1FeHBvcnRzOiBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgIGZ1bmN0aW9uIGZuKCkgewogICAgICAgICAgICAgICAgICAgIHZhciByZXQ7CiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlLmluaXQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0ID0gdmFsdWUuaW5pdC5hcHBseShnbG9iYWwsIGFyZ3VtZW50cyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIHJldHVybiByZXQgfHwgKHZhbHVlLmV4cG9ydHMgJiYgZ2V0R2xvYmFsKHZhbHVlLmV4cG9ydHMpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBmbjsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG1ha2VSZXF1aXJlOiBmdW5jdGlvbiAocmVsTWFwLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICBmdW5jdGlvbiBsb2NhbFJlcXVpcmUoZGVwcywgY2FsbGJhY2ssIGVycmJhY2spIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQsIG1hcCwgcmVxdWlyZU1vZDsKCiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZW5hYmxlQnVpbGRDYWxsYmFjayAmJiBjYWxsYmFjayAmJiBpc0Z1bmN0aW9uKGNhbGxiYWNrKSkgewogICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjay5fX3JlcXVpcmVKc0J1aWxkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwcyA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzRnVuY3Rpb24oY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0ludmFsaWQgY2FsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdyZXF1aXJlYXJncycsICdJbnZhbGlkIHJlcXVpcmUgY2FsbCcpLCBlcnJiYWNrKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiByZXF1aXJlfGV4cG9ydHN8bW9kdWxlIGFyZSByZXF1ZXN0ZWQsIGdldCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy92YWx1ZSBmb3IgdGhlbSBmcm9tIHRoZSBzcGVjaWFsIGhhbmRsZXJzLiBDYXZlYXQ6CiAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBvbmx5IHdvcmtzIHdoaWxlIG1vZHVsZSBpcyBiZWluZyBkZWZpbmVkLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVsTWFwICYmIGhhc1Byb3AoaGFuZGxlcnMsIGRlcHMpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlcnNbZGVwc10ocmVnaXN0cnlbcmVsTWFwLmlkXSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3luY2hyb25vdXMgYWNjZXNzIHRvIG9uZSBtb2R1bGUuIElmIHJlcXVpcmUuZ2V0IGlzCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYXZhaWxhYmxlIChhcyBpbiB0aGUgTm9kZSBhZGFwdGVyKSwgcHJlZmVyIHRoYXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEuZ2V0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVxLmdldChjb250ZXh0LCBkZXBzLCByZWxNYXAsIGxvY2FsUmVxdWlyZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIG1vZHVsZSBuYW1lLCBpZiBpdCBjb250YWlucyAuIG9yIC4uCiAgICAgICAgICAgICAgICAgICAgICAgIG1hcCA9IG1ha2VNb2R1bGVNYXAoZGVwcywgcmVsTWFwLCBmYWxzZSwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFwLmlkOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGRlZmluZWQsIGlkKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub3Rsb2FkZWQnLCAnTW9kdWxlIG5hbWUgIicgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIgaGFzIG5vdCBiZWVuIGxvYWRlZCB5ZXQgZm9yIGNvbnRleHQ6ICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dE5hbWUgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlbE1hcCA/ICcnIDogJy4gVXNlIHJlcXVpcmUoW10pJykpKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0dyYWIgZGVmaW5lcyB3YWl0aW5nIGluIHRoZSBnbG9iYWwgcXVldWUuCiAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAvL01hcmsgYWxsIHRoZSBkZXBlbmRlbmNpZXMgYXMgbmVlZGluZyB0byBiZSBsb2FkZWQuCiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5uZXh0VGljayhmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vU29tZSBkZWZpbmVzIGNvdWxkIGhhdmUgYmVlbiBhZGRlZCBzaW5jZSB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9yZXF1aXJlIGNhbGwsIGNvbGxlY3QgdGhlbS4KICAgICAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZCA9IGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKG51bGwsIHJlbE1hcCkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TdG9yZSBpZiBtYXAgY29uZmlnIHNob3VsZCBiZSBhcHBsaWVkIHRvIHRoaXMgcmVxdWlyZQogICAgICAgICAgICAgICAgICAgICAgICAvL2NhbGwgZm9yIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5za2lwTWFwID0gb3B0aW9ucy5za2lwTWFwOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5pbml0KGRlcHMsIGNhbGxiYWNrLCBlcnJiYWNrLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tMb2FkZWQoKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsUmVxdWlyZTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBtaXhpbihsb2NhbFJlcXVpcmUsIHsKICAgICAgICAgICAgICAgICAgICBpc0Jyb3dzZXI6IGlzQnJvd3NlciwKCiAgICAgICAgICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAgICAgICAgICogQ29udmVydHMgYSBtb2R1bGUgbmFtZSArIC5leHRlbnNpb24gaW50byBhbiBVUkwgcGF0aC4KICAgICAgICAgICAgICAgICAgICAgKiAqUmVxdWlyZXMqIHRoZSB1c2Ugb2YgYSBtb2R1bGUgbmFtZS4gSXQgZG9lcyBub3Qgc3VwcG9ydCB1c2luZwogICAgICAgICAgICAgICAgICAgICAqIHBsYWluIFVSTHMgbGlrZSBuYW1lVG9VcmwuCiAgICAgICAgICAgICAgICAgICAgICovCiAgICAgICAgICAgICAgICAgICAgdG9Vcmw6IGZ1bmN0aW9uIChtb2R1bGVOYW1lUGx1c0V4dCkgewogICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBtb2R1bGVOYW1lUGx1c0V4dC5sYXN0SW5kZXhPZignLicpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudCA9IG1vZHVsZU5hbWVQbHVzRXh0LnNwbGl0KCcvJylbMF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1JlbGF0aXZlID0gc2VnbWVudCA9PT0gJy4nIHx8IHNlZ21lbnQgPT09ICcuLic7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0hhdmUgYSBmaWxlIGV4dGVuc2lvbiBhbGlhcywgYW5kIGl0IGlzIG5vdCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9kb3RzIGZyb20gYSByZWxhdGl2ZSBwYXRoLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5kZXggIT09IC0xICYmICghaXNSZWxhdGl2ZSB8fCBpbmRleCA+IDEpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHQgPSBtb2R1bGVOYW1lUGx1c0V4dC5zdWJzdHJpbmcoaW5kZXgsIG1vZHVsZU5hbWVQbHVzRXh0Lmxlbmd0aCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lUGx1c0V4dCA9IG1vZHVsZU5hbWVQbHVzRXh0LnN1YnN0cmluZygwLCBpbmRleCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb250ZXh0Lm5hbWVUb1VybChub3JtYWxpemUobW9kdWxlTmFtZVBsdXNFeHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbE1hcCAmJiByZWxNYXAuaWQsIHRydWUpLCBleHQsICB0cnVlKTsKICAgICAgICAgICAgICAgICAgICB9LAoKICAgICAgICAgICAgICAgICAgICBkZWZpbmVkOiBmdW5jdGlvbiAoaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGhhc1Byb3AoZGVmaW5lZCwgbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQpOwogICAgICAgICAgICAgICAgICAgIH0sCgogICAgICAgICAgICAgICAgICAgIHNwZWNpZmllZDogZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQ7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBoYXNQcm9wKGRlZmluZWQsIGlkKSB8fCBoYXNQcm9wKHJlZ2lzdHJ5LCBpZCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9Pbmx5IGFsbG93IHVuZGVmIG9uIHRvcCBsZXZlbCByZXF1aXJlIGNhbGxzCiAgICAgICAgICAgICAgICBpZiAoIXJlbE1hcCkgewogICAgICAgICAgICAgICAgICAgIGxvY2FsUmVxdWlyZS51bmRlZiA9IGZ1bmN0aW9uIChpZCkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgYW55IHdhaXRpbmcgZGVmaW5lKCkgY2FsbHMgdG8gdGhpcyBjb250ZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAvL2ZpeCBmb3IgIzQwOAogICAgICAgICAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtYXAgPSBtYWtlTW9kdWxlTWFwKGlkLCByZWxNYXAsIHRydWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kID0gZ2V0T3duKHJlZ2lzdHJ5LCBpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBtb2QudW5kZWZlZCA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB1cmxGZXRjaGVkW21hcC51cmxdOwogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgdW5kZWZFdmVudHNbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9DbGVhbiBxdWV1ZWQgZGVmaW5lcyB0b28uIEdvIGJhY2t3YXJkcwogICAgICAgICAgICAgICAgICAgICAgICAvL2luIGFycmF5IHNvIHRoYXQgdGhlIHNwbGljZXMgZG8gbm90CiAgICAgICAgICAgICAgICAgICAgICAgIC8vbWVzcyB1cCB0aGUgaXRlcmF0aW9uLgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUmV2ZXJzZShkZWZRdWV1ZSwgZnVuY3Rpb24oYXJncywgaSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmUXVldWUuc3BsaWNlKGksIDEpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIGNvbnRleHQuZGVmUXVldWVNYXBbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9Ib2xkIG9uIHRvIGxpc3RlbmVycyBpbiBjYXNlIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9tb2R1bGUgd2lsbCBiZSBhdHRlbXB0ZWQgdG8gYmUgcmVsb2FkZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdXNpbmcgYSBkaWZmZXJlbnQgY29uZmlnLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5ldmVudHMuZGVmaW5lZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVmRXZlbnRzW2lkXSA9IG1vZC5ldmVudHM7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbFJlcXVpcmU7CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGVkIHRvIGVuYWJsZSBhIG1vZHVsZSBpZiBpdCBpcyBzdGlsbCBpbiB0aGUgcmVnaXN0cnkKICAgICAgICAgICAgICogYXdhaXRpbmcgZW5hYmxlbWVudC4gQSBzZWNvbmQgYXJnLCBwYXJlbnQsIHRoZSBwYXJlbnQgbW9kdWxlLAogICAgICAgICAgICAgKiBpcyBwYXNzZWQgaW4gZm9yIGNvbnRleHQsIHdoZW4gdGhpcyBtZXRob2QgaXMgb3ZlcnJpZGRlbiBieQogICAgICAgICAgICAgKiB0aGUgb3B0aW1pemVyLiBOb3Qgc2hvd24gaGVyZSB0byBrZWVwIGNvZGUgY29tcGFjdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGVuYWJsZTogZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgZGVwTWFwLmlkKTsKICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICBnZXRNb2R1bGUoZGVwTWFwKS5lbmFibGUoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdXNlZCBieSBlbnZpcm9ubWVudCBhZGFwdGVycyB0byBjb21wbGV0ZSBhIGxvYWQgZXZlbnQuCiAgICAgICAgICAgICAqIEEgbG9hZCBldmVudCBjb3VsZCBiZSBhIHNjcmlwdCBsb2FkIG9yIGp1c3QgYSBsb2FkIHBhc3MgZnJvbSBhIHN5bmNocm9ub3VzCiAgICAgICAgICAgICAqIGxvYWQgY2FsbC4KICAgICAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSB0byBwb3RlbnRpYWxseSBjb21wbGV0ZS4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNvbXBsZXRlTG9hZDogZnVuY3Rpb24gKG1vZHVsZU5hbWUpIHsKICAgICAgICAgICAgICAgIHZhciBmb3VuZCwgYXJncywgbW9kLAogICAgICAgICAgICAgICAgICAgIHNoaW0gPSBnZXRPd24oY29uZmlnLnNoaW0sIG1vZHVsZU5hbWUpIHx8IHt9LAogICAgICAgICAgICAgICAgICAgIHNoRXhwb3J0cyA9IHNoaW0uZXhwb3J0czsKCiAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICB3aGlsZSAoZGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgYXJncyA9IGRlZlF1ZXVlLnNoaWZ0KCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgYXJnc1swXSA9IG1vZHVsZU5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vSWYgYWxyZWFkeSBmb3VuZCBhbiBhbm9ueW1vdXMgbW9kdWxlIGFuZCBib3VuZCBpdAogICAgICAgICAgICAgICAgICAgICAgICAvL3RvIHRoaXMgbmFtZSwgdGhlbiB0aGlzIGlzIHNvbWUgb3RoZXIgYW5vbiBtb2R1bGUKICAgICAgICAgICAgICAgICAgICAgICAgLy93YWl0aW5nIGZvciBpdHMgY29tcGxldGVMb2FkIHRvIGZpcmUuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmb3VuZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJnc1swXSA9PT0gbW9kdWxlTmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0ZvdW5kIG1hdGNoaW5nIGRlZmluZSBjYWxsIGZvciB0aGlzIHNjcmlwdCEKICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgY2FsbEdldE1vZHVsZShhcmdzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQuZGVmUXVldWVNYXAgPSB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIHRoaXMgYWZ0ZXIgdGhlIGN5Y2xlIG9mIGNhbGxHZXRNb2R1bGUgaW4gY2FzZSB0aGUgcmVzdWx0CiAgICAgICAgICAgICAgICAvL29mIHRob3NlIGNhbGxzL2luaXQgY2FsbHMgY2hhbmdlcyB0aGUgcmVnaXN0cnkuCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmICghZm91bmQgJiYgIWhhc1Byb3AoZGVmaW5lZCwgbW9kdWxlTmFtZSkgJiYgbW9kICYmICFtb2QuaW5pdGVkKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbmZpZy5lbmZvcmNlRGVmaW5lICYmICghc2hFeHBvcnRzIHx8ICFnZXRHbG9iYWwoc2hFeHBvcnRzKSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc1BhdGhGYWxsYmFjayhtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub2RlZmluZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdObyBkZWZpbmUgY2FsbCBmb3IgJyArIG1vZHVsZU5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFttb2R1bGVOYW1lXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9BIHNjcmlwdCB0aGF0IGRvZXMgbm90IGNhbGwgZGVmaW5lKCksIHNvIGp1c3Qgc2ltdWxhdGUKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGUgY2FsbCBmb3IgaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoW21vZHVsZU5hbWUsIChzaGltLmRlcHMgfHwgW10pLCBzaGltLmV4cG9ydHNGbl0pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBjaGVja0xvYWRlZCgpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIENvbnZlcnRzIGEgbW9kdWxlIG5hbWUgdG8gYSBmaWxlIHBhdGguIFN1cHBvcnRzIGNhc2VzIHdoZXJlCiAgICAgICAgICAgICAqIG1vZHVsZU5hbWUgbWF5IGFjdHVhbGx5IGJlIGp1c3QgYW4gVVJMLgogICAgICAgICAgICAgKiBOb3RlIHRoYXQgaXQgKipkb2VzIG5vdCoqIGNhbGwgbm9ybWFsaXplIG9uIHRoZSBtb2R1bGVOYW1lLAogICAgICAgICAgICAgKiBpdCBpcyBhc3N1bWVkIHRvIGhhdmUgYWxyZWFkeSBiZWVuIG5vcm1hbGl6ZWQuIFRoaXMgaXMgYW4KICAgICAgICAgICAgICogaW50ZXJuYWwgQVBJLCBub3QgYSBwdWJsaWMgb25lLiBVc2UgdG9VcmwgZm9yIHRoZSBwdWJsaWMgQVBJLgogICAgICAgICAgICAgKi8KICAgICAgICAgICAgbmFtZVRvVXJsOiBmdW5jdGlvbiAobW9kdWxlTmFtZSwgZXh0LCBza2lwRXh0KSB7CiAgICAgICAgICAgICAgICB2YXIgcGF0aHMsIHN5bXMsIGksIHBhcmVudE1vZHVsZSwgdXJsLAogICAgICAgICAgICAgICAgICAgIHBhcmVudFBhdGgsIGJ1bmRsZUlkLAogICAgICAgICAgICAgICAgICAgIHBrZ01haW4gPSBnZXRPd24oY29uZmlnLnBrZ3MsIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmIChwa2dNYWluKSB7CiAgICAgICAgICAgICAgICAgICAgbW9kdWxlTmFtZSA9IHBrZ01haW47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgYnVuZGxlSWQgPSBnZXRPd24oYnVuZGxlc01hcCwgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkLCBleHQsIHNraXBFeHQpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vSWYgYSBjb2xvbiBpcyBpbiB0aGUgVVJMLCBpdCBpbmRpY2F0ZXMgYSBwcm90b2NvbCBpcyB1c2VkIGFuZCBpdCBpcyBqdXN0CiAgICAgICAgICAgICAgICAvL2FuIFVSTCB0byBhIGZpbGUsIG9yIGlmIGl0IHN0YXJ0cyB3aXRoIGEgc2xhc2gsIGNvbnRhaW5zIGEgcXVlcnkgYXJnIChpLmUuID8pCiAgICAgICAgICAgICAgICAvL29yIGVuZHMgd2l0aCAuanMsIHRoZW4gYXNzdW1lIHRoZSB1c2VyIG1lYW50IHRvIHVzZSBhbiB1cmwgYW5kIG5vdCBhIG1vZHVsZSBpZC4KICAgICAgICAgICAgICAgIC8vVGhlIHNsYXNoIGlzIGltcG9ydGFudCBmb3IgcHJvdG9jb2wtbGVzcyBVUkxzIGFzIHdlbGwgYXMgZnVsbCBwYXRocy4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIHBsYWluIHBhdGgsIG5vdCBtb2R1bGUgbmFtZSBsb29rdXAsIHNvIGp1c3QgcmV0dXJuIGl0LgogICAgICAgICAgICAgICAgICAgIC8vQWRkIGV4dGVuc2lvbiBpZiBpdCBpcyBpbmNsdWRlZC4gVGhpcyBpcyBhIGJpdCB3b25reSwgb25seSBub24tLmpzIHRoaW5ncyBwYXNzCiAgICAgICAgICAgICAgICAgICAgLy9hbiBleHRlbnNpb24sIHRoaXMgbWV0aG9kIHByb2JhYmx5IG5lZWRzIHRvIGJlIHJld29ya2VkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IG1vZHVsZU5hbWUgKyAoZXh0IHx8ICcnKTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgLy9BIG1vZHVsZSB0aGF0IG5lZWRzIHRvIGJlIGNvbnZlcnRlZCB0byBhIHBhdGguCiAgICAgICAgICAgICAgICAgICAgcGF0aHMgPSBjb25maWcucGF0aHM7CgogICAgICAgICAgICAgICAgICAgIHN5bXMgPSBtb2R1bGVOYW1lLnNwbGl0KCcvJyk7CiAgICAgICAgICAgICAgICAgICAgLy9Gb3IgZWFjaCBtb2R1bGUgbmFtZSBzZWdtZW50LCBzZWUgaWYgdGhlcmUgaXMgYSBwYXRoCiAgICAgICAgICAgICAgICAgICAgLy9yZWdpc3RlcmVkIGZvciBpdC4gU3RhcnQgd2l0aCBtb3N0IHNwZWNpZmljIG5hbWUKICAgICAgICAgICAgICAgICAgICAvL2FuZCB3b3JrIHVwIGZyb20gaXQuCiAgICAgICAgICAgICAgICAgICAgZm9yIChpID0gc3ltcy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50TW9kdWxlID0gc3ltcy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gZ2V0T3duKHBhdGhzLCBwYXJlbnRNb2R1bGUpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAocGFyZW50UGF0aCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiBhbiBhcnJheSwgaXQgbWVhbnMgdGhlcmUgYXJlIGEgZmV3IGNob2ljZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0Nob29zZSB0aGUgb25lIHRoYXQgaXMgZGVzaXJlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzQXJyYXkocGFyZW50UGF0aCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gcGFyZW50UGF0aFswXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXMuc3BsaWNlKDAsIGksIHBhcmVudFBhdGgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIC8vSm9pbiB0aGUgcGF0aCBwYXJ0cyB0b2dldGhlciwgdGhlbiBmaWd1cmUgb3V0IGlmIGJhc2VVcmwgaXMgbmVlZGVkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IHN5bXMuam9pbignLycpOwogICAgICAgICAgICAgICAgICAgIHVybCArPSAoZXh0IHx8ICgvXmRhdGFcOnxcPy8udGVzdCh1cmwpIHx8IHNraXBFeHQgPyAnJyA6ICcuanMnKSk7CiAgICAgICAgICAgICAgICAgICAgdXJsID0gKHVybC5jaGFyQXQoMCkgPT09ICcvJyB8fCB1cmwubWF0Y2goL15bXHdcK1wuXC1dKzovKSA/ICcnIDogY29uZmlnLmJhc2VVcmwpICsgdXJsOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBjb25maWcudXJsQXJncyA/IHVybCArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKHVybC5pbmRleE9mKCc/JykgPT09IC0xID8gJz8nIDogJyYnKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLnVybEFyZ3MpIDogdXJsOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLy9EZWxlZ2F0ZXMgdG8gcmVxLmxvYWQuIEJyb2tlbiBvdXQgYXMgYSBzZXBhcmF0ZSBmdW5jdGlvbiB0bwogICAgICAgICAgICAvL2FsbG93IG92ZXJyaWRpbmcgaW4gdGhlIG9wdGltaXplci4KICAgICAgICAgICAgbG9hZDogZnVuY3Rpb24gKGlkLCB1cmwpIHsKICAgICAgICAgICAgICAgIHJlcS5sb2FkKGNvbnRleHQsIGlkLCB1cmwpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIEV4ZWN1dGVzIGEgbW9kdWxlIGNhbGxiYWNrIGZ1bmN0aW9uLiBCcm9rZW4gb3V0IGFzIGEgc2VwYXJhdGUgZnVuY3Rpb24KICAgICAgICAgICAgICogc29sZWx5IHRvIGFsbG93IHRoZSBidWlsZCBzeXN0ZW0gdG8gc2VxdWVuY2UgdGhlIGZpbGVzIGluIHRoZSBidWlsdAogICAgICAgICAgICAgKiBsYXllciBpbiB0aGUgcmlnaHQgc2VxdWVuY2UuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBleGVjQ2I6IGZ1bmN0aW9uIChuYW1lLCBjYWxsYmFjaywgYXJncywgZXhwb3J0cykgewogICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrLmFwcGx5KGV4cG9ydHMsIGFyZ3MpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIGNhbGxiYWNrIGZvciBzY3JpcHQgbG9hZHMsIHVzZWQgdG8gY2hlY2sgc3RhdHVzIG9mIGxvYWRpbmcuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2dCB0aGUgZXZlbnQgZnJvbSB0aGUgYnJvd3NlciBmb3IgdGhlIHNjcmlwdAogICAgICAgICAgICAgKiB0aGF0IHdhcyBsb2FkZWQuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdExvYWQ6IGZ1bmN0aW9uIChldnQpIHsKICAgICAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgICAgIC8vYWxsIG9sZCBicm93c2VycyB3aWxsIGJlIHN1cHBvcnRlZCwgYnV0IHRoaXMgb25lIHdhcyBlYXN5IGVub3VnaAogICAgICAgICAgICAgICAgLy90byBzdXBwb3J0IGFuZCBzdGlsbCBtYWtlcyBzZW5zZS4KICAgICAgICAgICAgICAgIGlmIChldnQudHlwZSA9PT0gJ2xvYWQnIHx8CiAgICAgICAgICAgICAgICAgICAgICAgIChyZWFkeVJlZ0V4cC50ZXN0KChldnQuY3VycmVudFRhcmdldCB8fCBldnQuc3JjRWxlbWVudCkucmVhZHlTdGF0ZSkpKSB7CiAgICAgICAgICAgICAgICAgICAgLy9SZXNldCBpbnRlcmFjdGl2ZSBzY3JpcHQgc28gYSBzY3JpcHQgbm9kZSBpcyBub3QgaGVsZCBvbnRvIGZvcgogICAgICAgICAgICAgICAgICAgIC8vdG8gbG9uZy4KICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCA9IG51bGw7CgogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvdXQgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSBhbmQgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBnZXRTY3JpcHREYXRhKGV2dCk7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQoZGF0YS5pZCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGJhY2sgZm9yIHNjcmlwdCBlcnJvcnMuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdEVycm9yOiBmdW5jdGlvbiAoZXZ0KSB7CiAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IGdldFNjcmlwdERhdGEoZXZ0KTsKICAgICAgICAgICAgICAgIGlmICghaGFzUGF0aEZhbGxiYWNrKGRhdGEuaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmVudHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24odmFsdWUsIGtleSkgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoa2V5LmluZGV4T2YoJ19AcicpICE9PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHZhbHVlLmRlcE1hcHMsIGZ1bmN0aW9uKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZXBNYXAuaWQgPT09IGRhdGEuaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50cy5wdXNoKGtleSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ3NjcmlwdGVycm9yJywgJ1NjcmlwdCBlcnJvciBmb3IgIicgKyBkYXRhLmlkICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhcmVudHMubGVuZ3RoID8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIsIG5lZWRlZCBieTogJyArIHBhcmVudHMuam9pbignLCAnKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICciJyksIGV2dCwgW2RhdGEuaWRdKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBjb250ZXh0LnJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKCk7CiAgICAgICAgcmV0dXJuIGNvbnRleHQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBNYWluIGVudHJ5IHBvaW50LgogICAgICoKICAgICAqIElmIHRoZSBvbmx5IGFyZ3VtZW50IHRvIHJlcXVpcmUgaXMgYSBzdHJpbmcsIHRoZW4gdGhlIG1vZHVsZSB0aGF0CiAgICAgKiBpcyByZXByZXNlbnRlZCBieSB0aGF0IHN0cmluZyBpcyBmZXRjaGVkIGZvciB0aGUgYXBwcm9wcmlhdGUgY29udGV4dC4KICAgICAqCiAgICAgKiBJZiB0aGUgZmlyc3QgYXJndW1lbnQgaXMgYW4gYXJyYXksIHRoZW4gaXQgd2lsbCBiZSB0cmVhdGVkIGFzIGFuIGFycmF5CiAgICAgKiBvZiBkZXBlbmRlbmN5IHN0cmluZyBuYW1lcyB0byBmZXRjaC4gQW4gb3B0aW9uYWwgZnVuY3Rpb24gY2FsbGJhY2sgY2FuCiAgICAgKiBiZSBzcGVjaWZpZWQgdG8gZXhlY3V0ZSB3aGVuIGFsbCBvZiB0aG9zZSBkZXBlbmRlbmNpZXMgYXJlIGF2YWlsYWJsZS4KICAgICAqCiAgICAgKiBNYWtlIGEgbG9jYWwgcmVxIHZhcmlhYmxlIHRvIGhlbHAgQ2FqYSBjb21wbGlhbmNlIChpdCBhc3N1bWVzIHRoaW5ncwogICAgICogb24gYSByZXF1aXJlIHRoYXQgYXJlIG5vdCBzdGFuZGFyZGl6ZWQpLCBhbmQgdG8gZ2l2ZSBhIHNob3J0CiAgICAgKiBuYW1lIGZvciBtaW5pZmljYXRpb24vbG9jYWwgc2NvcGUgdXNlLgogICAgICovCiAgICByZXEgPSByZXF1aXJlanMgPSBmdW5jdGlvbiAoZGVwcywgY2FsbGJhY2ssIGVycmJhY2ssIG9wdGlvbmFsKSB7CgogICAgICAgIC8vRmluZCB0aGUgcmlnaHQgY29udGV4dCwgdXNlIGRlZmF1bHQKICAgICAgICB2YXIgY29udGV4dCwgY29uZmlnLAogICAgICAgICAgICBjb250ZXh0TmFtZSA9IGRlZkNvbnRleHROYW1lOwoKICAgICAgICAvLyBEZXRlcm1pbmUgaWYgaGF2ZSBjb25maWcgb2JqZWN0IGluIHRoZSBjYWxsLgogICAgICAgIGlmICghaXNBcnJheShkZXBzKSAmJiB0eXBlb2YgZGVwcyAhPT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgLy8gZGVwcyBpcyBhIGNvbmZpZyBvYmplY3QKICAgICAgICAgICAgY29uZmlnID0gZGVwczsKICAgICAgICAgICAgaWYgKGlzQXJyYXkoY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAvLyBBZGp1c3QgYXJncyBpZiB0aGVyZSBhcmUgZGVwZW5kZW5jaWVzCiAgICAgICAgICAgICAgICBkZXBzID0gY2FsbGJhY2s7CiAgICAgICAgICAgICAgICBjYWxsYmFjayA9IGVycmJhY2s7CiAgICAgICAgICAgICAgICBlcnJiYWNrID0gb3B0aW9uYWw7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBkZXBzID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmIChjb25maWcgJiYgY29uZmlnLmNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dE5hbWUgPSBjb25maWcuY29udGV4dDsKICAgICAgICB9CgogICAgICAgIGNvbnRleHQgPSBnZXRPd24oY29udGV4dHMsIGNvbnRleHROYW1lKTsKICAgICAgICBpZiAoIWNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dCA9IGNvbnRleHRzW2NvbnRleHROYW1lXSA9IHJlcS5zLm5ld0NvbnRleHQoY29udGV4dE5hbWUpOwogICAgICAgIH0KCiAgICAgICAgaWYgKGNvbmZpZykgewogICAgICAgICAgICBjb250ZXh0LmNvbmZpZ3VyZShjb25maWcpOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIGNvbnRleHQucmVxdWlyZShkZXBzLCBjYWxsYmFjaywgZXJyYmFjayk7CiAgICB9OwoKICAgIC8qKgogICAgICogU3VwcG9ydCByZXF1aXJlLmNvbmZpZygpIHRvIG1ha2UgaXQgZWFzaWVyIHRvIGNvb3BlcmF0ZSB3aXRoIG90aGVyCiAgICAgKiBBTUQgbG9hZGVycyBvbiBnbG9iYWxseSBhZ3JlZWQgbmFtZXMuCiAgICAgKi8KICAgIHJlcS5jb25maWcgPSBmdW5jdGlvbiAoY29uZmlnKSB7CiAgICAgICAgcmV0dXJuIHJlcShjb25maWcpOwogICAgfTsKCiAgICAvKioKICAgICAqIEV4ZWN1dGUgc29tZXRoaW5nIGFmdGVyIHRoZSBjdXJyZW50IHRpY2sKICAgICAqIG9mIHRoZSBldmVudCBsb29wLiBPdmVycmlkZSBmb3Igb3RoZXIgZW52cwogICAgICogdGhhdCBoYXZlIGEgYmV0dGVyIHNvbHV0aW9uIHRoYW4gc2V0VGltZW91dC4KICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBmbiBmdW5jdGlvbiB0byBleGVjdXRlIGxhdGVyLgogICAgICovCiAgICByZXEubmV4dFRpY2sgPSB0eXBlb2Ygc2V0VGltZW91dCAhPT0gJ3VuZGVmaW5lZCcgPyBmdW5jdGlvbiAoZm4pIHsKICAgICAgICBzZXRUaW1lb3V0KGZuLCA0KTsKICAgIH0gOiBmdW5jdGlvbiAoZm4pIHsgZm4oKTsgfTsKCiAgICAvKioKICAgICAqIEV4cG9ydCByZXF1aXJlIGFzIGEgZ2xvYmFsLCBidXQgb25seSBpZiBpdCBkb2VzIG5vdCBhbHJlYWR5IGV4aXN0LgogICAgICovCiAgICBpZiAoIXJlcXVpcmUpIHsKICAgICAgICByZXF1aXJlID0gcmVxOwogICAgfQoKICAgIHJlcS52ZXJzaW9uID0gdmVyc2lvbjsKCiAgICAvL1VzZWQgdG8gZmlsdGVyIG91dCBkZXBlbmRlbmNpZXMgdGhhdCBhcmUgYWxyZWFkeSBwYXRocy4KICAgIHJlcS5qc0V4dFJlZ0V4cCA9IC9eXC98OnxcP3xcLmpzJC87CiAgICByZXEuaXNCcm93c2VyID0gaXNCcm93c2VyOwogICAgcyA9IHJlcS5zID0gewogICAgICAgIGNvbnRleHRzOiBjb250ZXh0cywKICAgICAgICBuZXdDb250ZXh0OiBuZXdDb250ZXh0CiAgICB9OwoKICAgIC8vQ3JlYXRlIGRlZmF1bHQgY29udGV4dC4KICAgIHJlcSh7fSk7CgogICAgLy9FeHBvcnRzIHNvbWUgY29udGV4dC1zZW5zaXRpdmUgbWV0aG9kcyBvbiBnbG9iYWwgcmVxdWlyZS4KICAgIGVhY2goWwogICAgICAgICd0b1VybCcsCiAgICAgICAgJ3VuZGVmJywKICAgICAgICAnZGVmaW5lZCcsCiAgICAgICAgJ3NwZWNpZmllZCcKICAgIF0sIGZ1bmN0aW9uIChwcm9wKSB7CiAgICAgICAgLy9SZWZlcmVuY2UgZnJvbSBjb250ZXh0cyBpbnN0ZWFkIG9mIGVhcmx5IGJpbmRpbmcgdG8gZGVmYXVsdCBjb250ZXh0LAogICAgICAgIC8vc28gdGhhdCBkdXJpbmcgYnVpbGRzLCB0aGUgbGF0ZXN0IGluc3RhbmNlIG9mIHRoZSBkZWZhdWx0IGNvbnRleHQKICAgICAgICAvL3dpdGggaXRzIGNvbmZpZyBnZXRzIHVzZWQuCiAgICAgICAgcmVxW3Byb3BdID0gZnVuY3Rpb24gKCkgewogICAgICAgICAgICB2YXIgY3R4ID0gY29udGV4dHNbZGVmQ29udGV4dE5hbWVdOwogICAgICAgICAgICByZXR1cm4gY3R4LnJlcXVpcmVbcHJvcF0uYXBwbHkoY3R4LCBhcmd1bWVudHMpOwogICAgICAgIH07CiAgICB9KTsKCiAgICBpZiAoaXNCcm93c2VyKSB7CiAgICAgICAgaGVhZCA9IHMuaGVhZCA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdoZWFkJylbMF07CiAgICAgICAgLy9JZiBCQVNFIHRhZyBpcyBpbiBwbGF5LCB1c2luZyBhcHBlbmRDaGlsZCBpcyBhIHByb2JsZW0gZm9yIElFNi4KICAgICAgICAvL1doZW4gdGhhdCBicm93c2VyIGRpZXMsIHRoaXMgY2FuIGJlIHJlbW92ZWQuIERldGFpbHMgaW4gdGhpcyBqUXVlcnkgYnVnOgogICAgICAgIC8vaHR0cDovL2Rldi5qcXVlcnkuY29tL3RpY2tldC8yNzA5CiAgICAgICAgYmFzZUVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnYmFzZScpWzBdOwogICAgICAgIGlmIChiYXNlRWxlbWVudCkgewogICAgICAgICAgICBoZWFkID0gcy5oZWFkID0gYmFzZUVsZW1lbnQucGFyZW50Tm9kZTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBBbnkgZXJyb3JzIHRoYXQgcmVxdWlyZSBleHBsaWNpdGx5IGdlbmVyYXRlcyB3aWxsIGJlIHBhc3NlZCB0byB0aGlzCiAgICAgKiBmdW5jdGlvbi4gSW50ZXJjZXB0L292ZXJyaWRlIGl0IGlmIHlvdSB3YW50IGN1c3RvbSBlcnJvciBoYW5kbGluZy4KICAgICAqIEBwYXJhbSB7RXJyb3J9IGVyciB0aGUgZXJyb3Igb2JqZWN0LgogICAgICovCiAgICByZXEub25FcnJvciA9IGRlZmF1bHRPbkVycm9yOwoKICAgIC8qKgogICAgICogQ3JlYXRlcyB0aGUgbm9kZSBmb3IgdGhlIGxvYWQgY29tbWFuZC4gT25seSB1c2VkIGluIGJyb3dzZXIgZW52cy4KICAgICAqLwogICAgcmVxLmNyZWF0ZU5vZGUgPSBmdW5jdGlvbiAoY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgbm9kZSA9IGNvbmZpZy54aHRtbCA/CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCAnaHRtbDpzY3JpcHQnKSA6CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsKICAgICAgICBub2RlLnR5cGUgPSBjb25maWcuc2NyaXB0VHlwZSB8fCAndGV4dC9qYXZhc2NyaXB0JzsKICAgICAgICBub2RlLmNoYXJzZXQgPSAndXRmLTgnOwogICAgICAgIG5vZGUuYXN5bmMgPSB0cnVlOwogICAgICAgIHJldHVybiBub2RlOwogICAgfTsKCiAgICAvKioKICAgICAqIERvZXMgdGhlIHJlcXVlc3QgdG8gbG9hZCBhIG1vZHVsZSBmb3IgdGhlIGJyb3dzZXIgY2FzZS4KICAgICAqIE1ha2UgdGhpcyBhIHNlcGFyYXRlIGZ1bmN0aW9uIHRvIGFsbG93IG90aGVyIGVudmlyb25tZW50cwogICAgICogdG8gb3ZlcnJpZGUgaXQuCiAgICAgKgogICAgICogQHBhcmFtIHtPYmplY3R9IGNvbnRleHQgdGhlIHJlcXVpcmUgY29udGV4dCB0byBmaW5kIHN0YXRlLgogICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZS4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSB1cmwgdGhlIFVSTCB0byB0aGUgbW9kdWxlLgogICAgICovCiAgICByZXEubG9hZCA9IGZ1bmN0aW9uIChjb250ZXh0LCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgY29uZmlnID0gKGNvbnRleHQgJiYgY29udGV4dC5jb25maWcpIHx8IHt9LAogICAgICAgICAgICBub2RlOwogICAgICAgIGlmIChpc0Jyb3dzZXIpIHsKICAgICAgICAgICAgLy9JbiB0aGUgYnJvd3NlciBzbyB1c2UgYSBzY3JpcHQgdGFnCiAgICAgICAgICAgIG5vZGUgPSByZXEuY3JlYXRlTm9kZShjb25maWcsIG1vZHVsZU5hbWUsIHVybCk7CiAgICAgICAgICAgIGlmIChjb25maWcub25Ob2RlQ3JlYXRlZCkgewogICAgICAgICAgICAgICAgY29uZmlnLm9uTm9kZUNyZWF0ZWQobm9kZSwgY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcsIGNvbnRleHQuY29udGV4dE5hbWUpOwogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJywgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAvL1NldCB1cCBsb2FkIGxpc3RlbmVyLiBUZXN0IGF0dGFjaEV2ZW50IGZpcnN0IGJlY2F1c2UgSUU5IGhhcwogICAgICAgICAgICAvL2Egc3VidGxlIGlzc3VlIGluIGl0cyBhZGRFdmVudExpc3RlbmVyIGFuZCBzY3JpcHQgb25sb2FkIGZpcmluZ3MKICAgICAgICAgICAgLy90aGF0IGRvIG5vdCBtYXRjaCB0aGUgYmVoYXZpb3Igb2YgYWxsIG90aGVyIGJyb3dzZXJzIHdpdGgKICAgICAgICAgICAgLy9hZGRFdmVudExpc3RlbmVyIHN1cHBvcnQsIHdoaWNoIGZpcmUgdGhlIG9ubG9hZCBldmVudCBmb3IgYQogICAgICAgICAgICAvL3NjcmlwdCByaWdodCBhZnRlciB0aGUgc2NyaXB0IGV4ZWN1dGlvbi4gU2VlOgogICAgICAgICAgICAvL2h0dHBzOi8vY29ubmVjdC5taWNyb3NvZnQuY29tL0lFL2ZlZWRiYWNrL2RldGFpbHMvNjQ4MDU3L3NjcmlwdC1vbmxvYWQtZXZlbnQtaXMtbm90LWZpcmVkLWltbWVkaWF0ZWx5LWFmdGVyLXNjcmlwdC1leGVjdXRpb24KICAgICAgICAgICAgLy9VTkZPUlRVTkFURUxZIE9wZXJhIGltcGxlbWVudHMgYXR0YWNoRXZlbnQgYnV0IGRvZXMgbm90IGZvbGxvdyB0aGUgc2NyaXB0CiAgICAgICAgICAgIC8vc2NyaXB0IGV4ZWN1dGlvbiBtb2RlLgogICAgICAgICAgICBpZiAobm9kZS5hdHRhY2hFdmVudCAmJgogICAgICAgICAgICAgICAgICAgIC8vQ2hlY2sgaWYgbm9kZS5hdHRhY2hFdmVudCBpcyBhcnRpZmljaWFsbHkgYWRkZWQgYnkgY3VzdG9tIHNjcmlwdCBvcgogICAgICAgICAgICAgICAgICAgIC8vbmF0aXZlbHkgc3VwcG9ydGVkIGJ5IGJyb3dzZXIKICAgICAgICAgICAgICAgICAgICAvL3JlYWQgaHR0cHM6Ly9naXRodWIuY29tL2pyYnVya2UvcmVxdWlyZWpzL2lzc3Vlcy8xODcKICAgICAgICAgICAgICAgICAgICAvL2lmIHdlIGNhbiBOT1QgZmluZCBbbmF0aXZlIGNvZGVdIHRoZW4gaXQgbXVzdCBOT1QgbmF0aXZlbHkgc3VwcG9ydGVkLgogICAgICAgICAgICAgICAgICAgIC8vaW4gSUU4LCBub2RlLmF0dGFjaEV2ZW50IGRvZXMgbm90IGhhdmUgdG9TdHJpbmcoKQogICAgICAgICAgICAgICAgICAgIC8vTm90ZSB0aGUgdGVzdCBmb3IgIltuYXRpdmUgY29kZSIgd2l0aCBubyBjbG9zaW5nIGJyYWNlLCBzZWU6CiAgICAgICAgICAgICAgICAgICAgLy9odHRwczovL2dpdGh1Yi5jb20vanJidXJrZS9yZXF1aXJlanMvaXNzdWVzLzI3MwogICAgICAgICAgICAgICAgICAgICEobm9kZS5hdHRhY2hFdmVudC50b1N0cmluZyAmJiBub2RlLmF0dGFjaEV2ZW50LnRvU3RyaW5nKCkuaW5kZXhPZignW25hdGl2ZSBjb2RlJykgPCAwKSAmJgogICAgICAgICAgICAgICAgICAgICFpc09wZXJhKSB7CiAgICAgICAgICAgICAgICAvL1Byb2JhYmx5IElFLiBJRSAoYXQgbGVhc3QgNi04KSBkbyBub3QgZmlyZQogICAgICAgICAgICAgICAgLy9zY3JpcHQgb25sb2FkIHJpZ2h0IGFmdGVyIGV4ZWN1dGluZyB0aGUgc2NyaXB0LCBzbwogICAgICAgICAgICAgICAgLy93ZSBjYW5ub3QgdGllIHRoZSBhbm9ueW1vdXMgZGVmaW5lIGNhbGwgdG8gYSBuYW1lLgogICAgICAgICAgICAgICAgLy9Ib3dldmVyLCBJRSByZXBvcnRzIHRoZSBzY3JpcHQgYXMgYmVpbmcgaW4gJ2ludGVyYWN0aXZlJwogICAgICAgICAgICAgICAgLy9yZWFkeVN0YXRlIGF0IHRoZSB0aW1lIG9mIHRoZSBkZWZpbmUgY2FsbC4KICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKCiAgICAgICAgICAgICAgICBub2RlLmF0dGFjaEV2ZW50KCdvbnJlYWR5c3RhdGVjaGFuZ2UnLCBjb250ZXh0Lm9uU2NyaXB0TG9hZCk7CiAgICAgICAgICAgICAgICAvL0l0IHdvdWxkIGJlIGdyZWF0IHRvIGFkZCBhbiBlcnJvciBoYW5kbGVyIGhlcmUgdG8gY2F0Y2gKICAgICAgICAgICAgICAgIC8vNDA0cyBpbiBJRTkrLiBIb3dldmVyLCBvbnJlYWR5c3RhdGVjaGFuZ2Ugd2lsbCBmaXJlIGJlZm9yZQogICAgICAgICAgICAgICAgLy90aGUgZXJyb3IgaGFuZGxlciwgc28gdGhhdCBkb2VzIG5vdCBoZWxwLiBJZiBhZGRFdmVudExpc3RlbmVyCiAgICAgICAgICAgICAgICAvL2lzIHVzZWQsIHRoZW4gSUUgd2lsbCBmaXJlIGVycm9yIGJlZm9yZSBsb2FkLCBidXQgd2UgY2Fubm90CiAgICAgICAgICAgICAgICAvL3VzZSB0aGF0IHBhdGh3YXkgZ2l2ZW4gdGhlIGNvbm5lY3QubWljcm9zb2Z0LmNvbSBpc3N1ZQogICAgICAgICAgICAgICAgLy9tZW50aW9uZWQgYWJvdmUgYWJvdXQgbm90IGRvaW5nIHRoZSAnc2NyaXB0IGV4ZWN1dGUsCiAgICAgICAgICAgICAgICAvL3RoZW4gZmlyZSB0aGUgc2NyaXB0IGxvYWQgZXZlbnQgbGlzdGVuZXIgYmVmb3JlIGV4ZWN1dGUKICAgICAgICAgICAgICAgIC8vbmV4dCBzY3JpcHQnIHRoYXQgb3RoZXIgYnJvd3NlcnMgZG8uCiAgICAgICAgICAgICAgICAvL0Jlc3QgaG9wZTogSUUxMCBmaXhlcyB0aGUgaXNzdWVzLAogICAgICAgICAgICAgICAgLy9hbmQgdGhlbiBkZXN0cm95cyBhbGwgaW5zdGFsbHMgb2YgSUUgNi05LgogICAgICAgICAgICAgICAgLy9ub2RlLmF0dGFjaEV2ZW50KCdvbmVycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIGNvbnRleHQub25TY3JpcHRMb2FkLCBmYWxzZSk7CiAgICAgICAgICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbm9kZS5zcmMgPSB1cmw7CgogICAgICAgICAgICAvL0ZvciBzb21lIGNhY2hlIGNhc2VzIGluIElFIDYtOCwgdGhlIHNjcmlwdCBleGVjdXRlcyBiZWZvcmUgdGhlIGVuZAogICAgICAgICAgICAvL29mIHRoZSBhcHBlbmRDaGlsZCBleGVjdXRpb24sIHNvIHRvIHRpZSBhbiBhbm9ueW1vdXMgZGVmaW5lCiAgICAgICAgICAgIC8vY2FsbCB0byB0aGUgbW9kdWxlIG5hbWUgKHdoaWNoIGlzIHN0b3JlZCBvbiB0aGUgbm9kZSksIGhvbGQgb24KICAgICAgICAgICAgLy90byBhIHJlZmVyZW5jZSB0byB0aGlzIG5vZGUsIGJ1dCBjbGVhciBhZnRlciB0aGUgRE9NIGluc2VydGlvbi4KICAgICAgICAgICAgY3VycmVudGx5QWRkaW5nU2NyaXB0ID0gbm9kZTsKICAgICAgICAgICAgaWYgKGJhc2VFbGVtZW50KSB7CiAgICAgICAgICAgICAgICBoZWFkLmluc2VydEJlZm9yZShub2RlLCBiYXNlRWxlbWVudCk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBoZWFkLmFwcGVuZENoaWxkKG5vZGUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGN1cnJlbnRseUFkZGluZ1NjcmlwdCA9IG51bGw7CgogICAgICAgICAgICByZXR1cm4gbm9kZTsKICAgICAgICB9IGVsc2UgaWYgKGlzV2ViV29ya2VyKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAvL0luIGEgd2ViIHdvcmtlciwgdXNlIGltcG9ydFNjcmlwdHMuIFRoaXMgaXMgbm90IGEgdmVyeQogICAgICAgICAgICAgICAgLy9lZmZpY2llbnQgdXNlIG9mIGltcG9ydFNjcmlwdHMsIGltcG9ydFNjcmlwdHMgd2lsbCBibG9jayB1bnRpbAogICAgICAgICAgICAgICAgLy9pdHMgc2NyaXB0IGlzIGRvd25sb2FkZWQgYW5kIGV2YWx1YXRlZC4gSG93ZXZlciwgaWYgd2ViIHdvcmtlcnMKICAgICAgICAgICAgICAgIC8vYXJlIGluIHBsYXksIHRoZSBleHBlY3RhdGlvbiBpcyB0aGF0IGEgYnVpbGQgaGFzIGJlZW4gZG9uZSBzbwogICAgICAgICAgICAgICAgLy90aGF0IG9ubHkgb25lIHNjcmlwdCBuZWVkcyB0byBiZSBsb2FkZWQgYW55d2F5LiBUaGlzIG1heSBuZWVkCiAgICAgICAgICAgICAgICAvL3RvIGJlIHJlZXZhbHVhdGVkIGlmIG90aGVyIHVzZSBjYXNlcyBiZWNvbWUgY29tbW9uLgogICAgICAgICAgICAgICAgaW1wb3J0U2NyaXB0cyh1cmwpOwoKICAgICAgICAgICAgICAgIC8vQWNjb3VudCBmb3IgYW5vbnltb3VzIG1vZHVsZXMKICAgICAgICAgICAgICAgIGNvbnRleHQuY29tcGxldGVMb2FkKG1vZHVsZU5hbWUpOwogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICBjb250ZXh0Lm9uRXJyb3IobWFrZUVycm9yKCdpbXBvcnRzY3JpcHRzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaW1wb3J0U2NyaXB0cyBmYWlsZWQgZm9yICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lICsgJyBhdCAnICsgdXJsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW21vZHVsZU5hbWVdKSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9OwoKICAgIGZ1bmN0aW9uIGdldEludGVyYWN0aXZlU2NyaXB0KCkgewogICAgICAgIGlmIChpbnRlcmFjdGl2ZVNjcmlwdCAmJiBpbnRlcmFjdGl2ZVNjcmlwdC5yZWFkeVN0YXRlID09PSAnaW50ZXJhY3RpdmUnKSB7CiAgICAgICAgICAgIHJldHVybiBpbnRlcmFjdGl2ZVNjcmlwdDsKICAgICAgICB9CgogICAgICAgIGVhY2hSZXZlcnNlKHNjcmlwdHMoKSwgZnVuY3Rpb24gKHNjcmlwdCkgewogICAgICAgICAgICBpZiAoc2NyaXB0LnJlYWR5U3RhdGUgPT09ICdpbnRlcmFjdGl2ZScpIHsKICAgICAgICAgICAgICAgIHJldHVybiAoaW50ZXJhY3RpdmVTY3JpcHQgPSBzY3JpcHQpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgcmV0dXJuIGludGVyYWN0aXZlU2NyaXB0OwogICAgfQoKICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gc2NyaXB0IGF0dHJpYnV0ZSwgd2hpY2ggY291bGQgYWxzbyBhZGp1c3QgdGhlIGJhc2VVcmwuCiAgICBpZiAoaXNCcm93c2VyICYmICFjZmcuc2tpcERhdGFNYWluKSB7CiAgICAgICAgLy9GaWd1cmUgb3V0IGJhc2VVcmwuIEdldCBpdCBmcm9tIHRoZSBzY3JpcHQgdGFnIHdpdGggcmVxdWlyZS5qcyBpbiBpdC4KICAgICAgICBlYWNoUmV2ZXJzZShzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHQpIHsKICAgICAgICAgICAgLy9TZXQgdGhlICdoZWFkJyB3aGVyZSB3ZSBjYW4gYXBwZW5kIGNoaWxkcmVuIGJ5CiAgICAgICAgICAgIC8vdXNpbmcgdGhlIHNjcmlwdCdzIHBhcmVudC4KICAgICAgICAgICAgaWYgKCFoZWFkKSB7CiAgICAgICAgICAgICAgICBoZWFkID0gc2NyaXB0LnBhcmVudE5vZGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gYXR0cmlidXRlIHRvIHNldCBtYWluIHNjcmlwdCBmb3IgdGhlIHBhZ2UKICAgICAgICAgICAgLy90byBsb2FkLiBJZiBpdCBpcyB0aGVyZSwgdGhlIHBhdGggdG8gZGF0YSBtYWluIGJlY29tZXMgdGhlCiAgICAgICAgICAgIC8vYmFzZVVybCwgaWYgaXQgaXMgbm90IGFscmVhZHkgc2V0LgogICAgICAgICAgICBkYXRhTWFpbiA9IHNjcmlwdC5nZXRBdHRyaWJ1dGUoJ2RhdGEtbWFpbicpOwogICAgICAgICAgICBpZiAoZGF0YU1haW4pIHsKICAgICAgICAgICAgICAgIC8vUHJlc2VydmUgZGF0YU1haW4gaW4gY2FzZSBpdCBpcyBhIHBhdGggKGkuZS4gY29udGFpbnMgJz8nKQogICAgICAgICAgICAgICAgbWFpblNjcmlwdCA9IGRhdGFNYWluOwoKICAgICAgICAgICAgICAgIC8vU2V0IGZpbmFsIGJhc2VVcmwgaWYgdGhlcmUgaXMgbm90IGFscmVhZHkgYW4gZXhwbGljaXQgb25lLgogICAgICAgICAgICAgICAgaWYgKCFjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvZmYgdGhlIGRpcmVjdG9yeSBvZiBkYXRhLW1haW4gZm9yIHVzZSBhcyB0aGUKICAgICAgICAgICAgICAgICAgICAvL2Jhc2VVcmwuCiAgICAgICAgICAgICAgICAgICAgc3JjID0gbWFpblNjcmlwdC5zcGxpdCgnLycpOwogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBzcmMucG9wKCk7CiAgICAgICAgICAgICAgICAgICAgc3ViUGF0aCA9IHNyYy5sZW5ndGggPyBzcmMuam9pbignLycpICArICcvJyA6ICcuLyc7CgogICAgICAgICAgICAgICAgICAgIGNmZy5iYXNlVXJsID0gc3ViUGF0aDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1N0cmlwIG9mZiBhbnkgdHJhaWxpbmcgLmpzIHNpbmNlIG1haW5TY3JpcHQgaXMgbm93CiAgICAgICAgICAgICAgICAvL2xpa2UgYSBtb2R1bGUgbmFtZS4KICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBtYWluU2NyaXB0LnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKCiAgICAgICAgICAgICAgICAvL0lmIG1haW5TY3JpcHQgaXMgc3RpbGwgYSBwYXRoLCBmYWxsIGJhY2sgdG8gZGF0YU1haW4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtYWluU2NyaXB0KSkgewogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBkYXRhTWFpbjsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1B1dCB0aGUgZGF0YS1tYWluIHNjcmlwdCBpbiB0aGUgZmlsZXMgdG8gbG9hZC4KICAgICAgICAgICAgICAgIGNmZy5kZXBzID0gY2ZnLmRlcHMgPyBjZmcuZGVwcy5jb25jYXQobWFpblNjcmlwdCkgOiBbbWFpblNjcmlwdF07CgogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKICAgIH0KCiAgICAvKioKICAgICAqIFRoZSBmdW5jdGlvbiB0aGF0IGhhbmRsZXMgZGVmaW5pdGlvbnMgb2YgbW9kdWxlcy4gRGlmZmVycyBmcm9tCiAgICAgKiByZXF1aXJlKCkgaW4gdGhhdCBhIHN0cmluZyBmb3IgdGhlIG1vZHVsZSBzaG91bGQgYmUgdGhlIGZpcnN0IGFyZ3VtZW50LAogICAgICogYW5kIHRoZSBmdW5jdGlvbiB0byBleGVjdXRlIGFmdGVyIGRlcGVuZGVuY2llcyBhcmUgbG9hZGVkIHNob3VsZAogICAgICogcmV0dXJuIGEgdmFsdWUgdG8gZGVmaW5lIHRoZSBtb2R1bGUgY29ycmVzcG9uZGluZyB0byB0aGUgZmlyc3QgYXJndW1lbnQncwogICAgICogbmFtZS4KICAgICAqLwogICAgZGVmaW5lID0gZnVuY3Rpb24gKG5hbWUsIGRlcHMsIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIG5vZGUsIGNvbnRleHQ7CgogICAgICAgIC8vQWxsb3cgZm9yIGFub255bW91cyBtb2R1bGVzCiAgICAgICAgaWYgKHR5cGVvZiBuYW1lICE9PSAnc3RyaW5nJykgewogICAgICAgICAgICAvL0FkanVzdCBhcmdzIGFwcHJvcHJpYXRlbHkKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbmFtZTsKICAgICAgICAgICAgbmFtZSA9IG51bGw7CiAgICAgICAgfQoKICAgICAgICAvL1RoaXMgbW9kdWxlIG1heSBub3QgaGF2ZSBkZXBlbmRlbmNpZXMKICAgICAgICBpZiAoIWlzQXJyYXkoZGVwcykpIHsKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbnVsbDsKICAgICAgICB9CgogICAgICAgIC8vSWYgbm8gbmFtZSwgYW5kIGNhbGxiYWNrIGlzIGEgZnVuY3Rpb24sIHRoZW4gZmlndXJlIG91dCBpZiBpdCBhCiAgICAgICAgLy9Db21tb25KUyB0aGluZyB3aXRoIGRlcGVuZGVuY2llcy4KICAgICAgICBpZiAoIWRlcHMgJiYgaXNGdW5jdGlvbihjYWxsYmFjaykpIHsKICAgICAgICAgICAgZGVwcyA9IFtdOwogICAgICAgICAgICAvL1JlbW92ZSBjb21tZW50cyBmcm9tIHRoZSBjYWxsYmFjayBzdHJpbmcsCiAgICAgICAgICAgIC8vbG9vayBmb3IgcmVxdWlyZSBjYWxscywgYW5kIHB1bGwgdGhlbSBpbnRvIHRoZSBkZXBlbmRlbmNpZXMsCiAgICAgICAgICAgIC8vYnV0IG9ubHkgaWYgdGhlcmUgYXJlIGZ1bmN0aW9uIGFyZ3MuCiAgICAgICAgICAgIGlmIChjYWxsYmFjay5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGNhbGxiYWNrCiAgICAgICAgICAgICAgICAgICAgLnRvU3RyaW5nKCkKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjb21tZW50UmVnRXhwLCAnJykKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjanNSZXF1aXJlUmVnRXhwLCBmdW5jdGlvbiAobWF0Y2gsIGRlcCkgewogICAgICAgICAgICAgICAgICAgICAgICBkZXBzLnB1c2goZGVwKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAvL01heSBiZSBhIENvbW1vbkpTIHRoaW5nIGV2ZW4gd2l0aG91dCByZXF1aXJlIGNhbGxzLCBidXQgc3RpbGwKICAgICAgICAgICAgICAgIC8vY291bGQgdXNlIGV4cG9ydHMsIGFuZCBtb2R1bGUuIEF2b2lkIGRvaW5nIGV4cG9ydHMgYW5kIG1vZHVsZQogICAgICAgICAgICAgICAgLy93b3JrIHRob3VnaCBpZiBpdCBqdXN0IG5lZWRzIHJlcXVpcmUuCiAgICAgICAgICAgICAgICAvL1JFUVVJUkVTIHRoZSBmdW5jdGlvbiB0byBleHBlY3QgdGhlIENvbW1vbkpTIHZhcmlhYmxlcyBpbiB0aGUKICAgICAgICAgICAgICAgIC8vb3JkZXIgbGlzdGVkIGJlbG93LgogICAgICAgICAgICAgICAgZGVwcyA9IChjYWxsYmFjay5sZW5ndGggPT09IDEgPyBbJ3JlcXVpcmUnXSA6IFsncmVxdWlyZScsICdleHBvcnRzJywgJ21vZHVsZSddKS5jb25jYXQoZGVwcyk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8vSWYgaW4gSUUgNi04IGFuZCBoaXQgYW4gYW5vbnltb3VzIGRlZmluZSgpIGNhbGwsIGRvIHRoZSBpbnRlcmFjdGl2ZQogICAgICAgIC8vd29yay4KICAgICAgICBpZiAodXNlSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgbm9kZSA9IGN1cnJlbnRseUFkZGluZ1NjcmlwdCB8fCBnZXRJbnRlcmFjdGl2ZVNjcmlwdCgpOwogICAgICAgICAgICBpZiAobm9kZSkgewogICAgICAgICAgICAgICAgaWYgKCFuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQgPSBjb250ZXh0c1tub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy9BbHdheXMgc2F2ZSBvZmYgZXZhbHVhdGluZyB0aGUgZGVmIGNhbGwgdW50aWwgdGhlIHNjcmlwdCBvbmxvYWQgaGFuZGxlci4KICAgICAgICAvL1RoaXMgYWxsb3dzIG11bHRpcGxlIG1vZHVsZXMgdG8gYmUgaW4gYSBmaWxlIHdpdGhvdXQgcHJlbWF0dXJlbHkKICAgICAgICAvL3RyYWNpbmcgZGVwZW5kZW5jaWVzLCBhbmQgYWxsb3dzIGZvciBhbm9ueW1vdXMgbW9kdWxlIHN1cHBvcnQsCiAgICAgICAgLy93aGVyZSB0aGUgbW9kdWxlIG5hbWUgaXMgbm90IGtub3duIHVudGlsIHRoZSBzY3JpcHQgb25sb2FkIGV2ZW50CiAgICAgICAgLy9vY2N1cnMuIElmIG5vIGNvbnRleHQsIHVzZSB0aGUgZ2xvYmFsIHF1ZXVlLCBhbmQgZ2V0IGl0IHByb2Nlc3NlZAogICAgICAgIC8vaW4gdGhlIG9uc2NyaXB0IGxvYWQgY2FsbGJhY2suCiAgICAgICAgaWYgKGNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgICAgICBjb250ZXh0LmRlZlF1ZXVlTWFwW25hbWVdID0gdHJ1ZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBnbG9iYWxEZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgIH0KICAgIH07CgogICAgZGVmaW5lLmFtZCA9IHsKICAgICAgICBqUXVlcnk6IHRydWUKICAgIH07CgogICAgLyoqCiAgICAgKiBFeGVjdXRlcyB0aGUgdGV4dC4gTm9ybWFsbHkganVzdCB1c2VzIGV2YWwsIGJ1dCBjYW4gYmUgbW9kaWZpZWQKICAgICAqIHRvIHVzZSBhIGJldHRlciwgZW52aXJvbm1lbnQtc3BlY2lmaWMgY2FsbC4gT25seSB1c2VkIGZvciB0cmFuc3BpbGluZwogICAgICogbG9hZGVyIHBsdWdpbnMsIG5vdCBmb3IgcGxhaW4gSlMgbW9kdWxlcy4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IHRoZSB0ZXh0IHRvIGV4ZWN1dGUvZXZhbHVhdGUuCiAgICAgKi8KICAgIHJlcS5leGVjID0gZnVuY3Rpb24gKHRleHQpIHsKICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgcmV0dXJuIGV2YWwodGV4dCk7CiAgICB9OwoKICAgIC8vU2V0IHVwIHdpdGggY29uZmlnIGluZm8uCiAgICByZXEoY2ZnKTsKfSh0aGlzKSk7Cg==",
"ok": true,
"headers": [
[
"content-type",
"application/javascript"
]
],
"status": 200,
"status_text": ""
}
},
"base_uri": "https://localhost:8080/",
"height": 617
}
},
"source": [
"configure_plotly_browser_state()\n",
"perf_post_LASSO = backtestmodel.cumulative_return\n",
"mychart([perf_post_LASSO],[\"Post-LASSO\"], title=\"Post-LASSO\")\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/html": [
"\n",
" <script src=\"/static/components/requirejs/require.js\"></script>\n",
" <script>\n",
" requirejs.config({\n",
" paths: {\n",
" base: '/static/base',\n",
" plotly: 'https://cdn.plot.ly/plotly-latest.min.js?noext',\n",
" },\n",
" });\n",
" </script>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
},
{
"output_type": "display_data",
"data": {
"text/html": [
"<div id=\"806e1b18-ffaa-43b6-a366-99ce2a32d710\" style=\"height: 600px; width: 900px;\" class=\"plotly-graph-div\"></div><script type=\"text/javascript\">require([\"plotly\"], function(Plotly) { window.PLOTLYENV=window.PLOTLYENV || {};window.PLOTLYENV.BASE_URL=\"https://plot.ly\";Plotly.newPlot(\"806e1b18-ffaa-43b6-a366-99ce2a32d710\", [{\"type\": \"scatter\", \"x\": [1970.0, 1970.081850533808, 1970.1637010676156, 1970.2455516014236, 1970.3274021352313, 1970.4092526690392, 1970.491103202847, 1970.5729537366549, 1970.6548042704626, 1970.7366548042705, 1970.8185053380782, 1970.9003558718862, 1970.982206405694, 1971.0640569395018, 1971.1459074733095, 1971.2277580071175, 1971.3096085409252, 1971.3914590747331, 1971.4733096085408, 1971.5551601423488, 1971.6370106761565, 1971.7188612099644, 1971.8007117437724, 1971.88256227758, 1971.964412811388, 1972.0462633451957, 1972.1281138790036, 1972.2099644128114, 1972.2918149466193, 1972.373665480427, 1972.455516014235, 1972.5373665480427, 1972.6192170818506, 1972.7010676156583, 1972.7829181494662, 1972.864768683274, 1972.946619217082, 1973.0284697508896, 1973.1103202846975, 1973.1921708185052, 1973.2740213523132, 1973.355871886121, 1973.4377224199288, 1973.5195729537365, 1973.6014234875445, 1973.6832740213524, 1973.7651245551601, 1973.846975088968, 1973.9288256227758, 1974.0106761565837, 1974.0925266903914, 1974.1743772241994, 1974.256227758007, 1974.338078291815, 1974.4199288256227, 1974.5017793594307, 1974.5836298932384, 1974.6654804270463, 1974.747330960854, 1974.829181494662, 1974.9110320284697, 1974.9928825622776, 1975.0747330960853, 1975.1565836298932, 1975.238434163701, 1975.320284697509, 1975.4021352313168, 1975.4839857651245, 1975.5658362989325, 1975.6476868327402, 1975.7295373665481, 1975.8113879003558, 1975.8932384341638, 1975.9750889679715, 1976.0569395017794, 1976.1387900355871, 1976.220640569395, 1976.3024911032028, 1976.3843416370107, 1976.4661921708184, 1976.5480427046264, 1976.629893238434, 1976.711743772242, 1976.7935943060497, 1976.8754448398577, 1976.9572953736654, 1977.0391459074733, 1977.1209964412812, 1977.202846975089, 1977.284697508897, 1977.3665480427046, 1977.4483985765125, 1977.5302491103203, 1977.6120996441282, 1977.693950177936, 1977.7758007117438, 1977.8576512455516, 1977.9395017793595, 1978.0213523131672, 1978.1032028469751, 1978.1850533807828, 1978.2669039145908, 1978.3487544483985, 1978.4306049822064, 1978.5124555160141, 1978.594306049822, 1978.6761565836298, 1978.7580071174377, 1978.8398576512454, 1978.9217081850534, 1979.0035587188613, 1979.085409252669, 1979.167259786477, 1979.2491103202847, 1979.3309608540926, 1979.4128113879003, 1979.4946619217083, 1979.576512455516, 1979.658362989324, 1979.7402135231316, 1979.8220640569396, 1979.9039145907473, 1979.9857651245552, 1980.067615658363, 1980.1494661921708, 1980.2313167259786, 1980.3131672597865, 1980.3950177935942, 1980.4768683274021, 1980.5587188612099, 1980.6405693950178, 1980.7224199288257, 1980.8042704626334, 1980.8861209964414, 1980.967971530249, 1981.049822064057, 1981.1316725978647, 1981.2135231316727, 1981.2953736654804, 1981.3772241992883, 1981.459074733096, 1981.540925266904, 1981.6227758007117, 1981.7046263345196, 1981.7864768683273, 1981.8683274021353, 1981.950177935943, 1982.032028469751, 1982.1138790035586, 1982.1957295373666, 1982.2775800711743, 1982.3594306049822, 1982.4412811387901, 1982.5231316725979, 1982.6049822064058, 1982.6868327402135, 1982.7686832740214, 1982.8505338078292, 1982.932384341637, 1983.0142348754448, 1983.0960854092527, 1983.1779359430604, 1983.2597864768684, 1983.341637010676, 1983.423487544484, 1983.5053380782917, 1983.5871886120997, 1983.6690391459074, 1983.7508896797153, 1983.832740213523, 1983.914590747331, 1983.9964412811387, 1984.0782918149466, 1984.1601423487546, 1984.2419928825623, 1984.3238434163702, 1984.405693950178, 1984.4875444839859, 1984.5693950177936, 1984.6512455516015, 1984.7330960854092, 1984.8149466192172, 1984.8967971530249, 1984.9786476868328, 1985.0604982206405, 1985.1423487544484, 1985.2241992882562, 1985.306049822064, 1985.3879003558718, 1985.4697508896797, 1985.5516014234875, 1985.6334519572954, 1985.715302491103, 1985.797153024911, 1985.8790035587188, 1985.9608540925267, 1986.0427046263346, 1986.1245551601423, 1986.2064056939503, 1986.288256227758, 1986.370106761566, 1986.4519572953736, 1986.5338078291816, 1986.6156583629893, 1986.6975088967972, 1986.779359430605, 1986.8612099644129, 1986.9430604982206, 1987.0249110320285, 1987.1067615658362, 1987.1886120996442, 1987.2704626334519, 1987.3523131672598, 1987.4341637010675, 1987.5160142348755, 1987.5978647686832, 1987.679715302491, 1987.761565836299, 1987.8434163701068, 1987.9252669039147, 1988.0071174377224, 1988.0889679715303, 1988.170818505338, 1988.252669039146, 1988.3345195729537, 1988.4163701067616, 1988.4982206405693, 1988.5800711743773, 1988.661921708185, 1988.743772241993, 1988.8256227758006, 1988.9074733096086, 1988.9893238434163, 1989.0711743772242, 1989.153024911032, 1989.2348754448399, 1989.3167259786476, 1989.3985765124555, 1989.4804270462632, 1989.5622775800712, 1989.644128113879, 1989.7259786476868, 1989.8078291814948, 1989.8896797153025, 1989.9715302491104, 1990.053380782918, 1990.135231316726, 1990.2170818505338, 1990.2989323843417, 1990.3807829181494, 1990.4626334519573, 1990.544483985765, 1990.626334519573, 1990.7081850533807, 1990.7900355871886, 1990.8718861209964, 1990.9537366548043, 1991.035587188612, 1991.11743772242, 1991.1992882562276, 1991.2811387900356, 1991.3629893238435, 1991.4448398576512, 1991.5266903914592, 1991.6085409252669, 1991.6903914590748, 1991.7722419928825, 1991.8540925266905, 1991.9359430604982, 1992.017793594306, 1992.0996441281138, 1992.1814946619218, 1992.2633451957295, 1992.3451957295374, 1992.4270462633451, 1992.508896797153, 1992.5907473309608, 1992.6725978647687, 1992.7544483985764, 1992.8362989323844, 1992.918149466192, 1993.0, 1993.081850533808, 1993.1637010676156, 1993.2455516014236, 1993.3274021352313, 1993.4092526690392, 1993.491103202847, 1993.5729537366549, 1993.6548042704626, 1993.7366548042705, 1993.8185053380782, 1993.9003558718862, 1993.982206405694, 1994.0640569395018, 1994.1459074733095, 1994.2277580071175, 1994.3096085409252, 1994.3914590747331, 1994.4733096085408, 1994.5551601423488, 1994.6370106761565, 1994.7188612099644, 1994.8007117437724, 1994.88256227758, 1994.964412811388, 1995.0462633451957, 1995.1281138790036, 1995.2099644128114, 1995.2918149466193, 1995.373665480427, 1995.455516014235, 1995.5373665480427, 1995.6192170818506, 1995.7010676156583, 1995.7829181494662, 1995.864768683274, 1995.946619217082, 1996.0284697508896, 1996.1103202846975, 1996.1921708185052, 1996.2740213523132, 1996.355871886121, 1996.4377224199288, 1996.5195729537368, 1996.6014234875445, 1996.6832740213524, 1996.7651245551601, 1996.846975088968, 1996.9288256227758, 1997.0106761565837, 1997.0925266903914, 1997.1743772241994, 1997.256227758007, 1997.338078291815, 1997.4199288256227, 1997.5017793594307, 1997.5836298932384, 1997.6654804270463, 1997.747330960854, 1997.829181494662, 1997.9110320284697, 1997.9928825622776, 1998.0747330960853, 1998.1565836298932, 1998.238434163701, 1998.320284697509, 1998.4021352313168, 1998.4839857651245, 1998.5658362989325, 1998.6476868327402, 1998.7295373665481, 1998.8113879003558, 1998.8932384341638, 1998.9750889679715, 1999.0569395017794, 1999.1387900355871, 1999.220640569395, 1999.3024911032028, 1999.3843416370107, 1999.4661921708184, 1999.5480427046264, 1999.629893238434, 1999.711743772242, 1999.7935943060497, 1999.8754448398577, 1999.9572953736654, 2000.0391459074733, 2000.1209964412812, 2000.202846975089, 2000.284697508897, 2000.3665480427046, 2000.4483985765125, 2000.5302491103203, 2000.6120996441282, 2000.693950177936, 2000.7758007117438, 2000.8576512455516, 2000.9395017793595, 2001.0213523131672, 2001.1032028469751, 2001.1850533807828, 2001.2669039145908, 2001.3487544483985, 2001.4306049822064, 2001.5124555160141, 2001.594306049822, 2001.6761565836298, 2001.7580071174377, 2001.8398576512454, 2001.9217081850534, 2002.0035587188613, 2002.085409252669, 2002.167259786477, 2002.2491103202847, 2002.3309608540926, 2002.4128113879003, 2002.4946619217083, 2002.576512455516, 2002.658362989324, 2002.7402135231316, 2002.8220640569396, 2002.9039145907473, 2002.9857651245552, 2003.067615658363, 2003.1494661921708, 2003.2313167259786, 2003.3131672597865, 2003.3950177935942, 2003.4768683274021, 2003.5587188612099, 2003.6405693950178, 2003.7224199288257, 2003.8042704626334, 2003.8861209964414, 2003.967971530249, 2004.049822064057, 2004.1316725978647, 2004.2135231316727, 2004.2953736654804, 2004.3772241992883, 2004.459074733096, 2004.540925266904, 2004.6227758007117, 2004.7046263345196, 2004.7864768683273, 2004.8683274021353, 2004.950177935943, 2005.032028469751, 2005.1138790035586, 2005.1957295373666, 2005.2775800711743, 2005.3594306049822, 2005.4412811387901, 2005.5231316725979, 2005.6049822064058, 2005.6868327402135, 2005.7686832740214, 2005.8505338078292, 2005.932384341637, 2006.0142348754448, 2006.0960854092527, 2006.1779359430604, 2006.2597864768684, 2006.341637010676, 2006.423487544484, 2006.5053380782917, 2006.5871886120997, 2006.6690391459074, 2006.7508896797153, 2006.832740213523, 2006.914590747331, 2006.9964412811387, 2007.0782918149466, 2007.1601423487546, 2007.2419928825623, 2007.3238434163702, 2007.405693950178, 2007.4875444839859, 2007.5693950177936, 2007.6512455516015, 2007.7330960854092, 2007.8149466192172, 2007.8967971530249, 2007.9786476868328, 2008.0604982206405, 2008.1423487544484, 2008.2241992882562, 2008.306049822064, 2008.3879003558718, 2008.4697508896797, 2008.5516014234875, 2008.6334519572954, 2008.715302491103, 2008.797153024911, 2008.879003558719, 2008.9608540925267, 2009.0427046263346, 2009.1245551601423, 2009.2064056939503, 2009.288256227758, 2009.370106761566, 2009.4519572953736, 2009.5338078291816, 2009.6156583629893, 2009.6975088967972, 2009.779359430605, 2009.8612099644129, 2009.9430604982206, 2010.0249110320285, 2010.1067615658362, 2010.1886120996442, 2010.2704626334519, 2010.3523131672598, 2010.4341637010675, 2010.5160142348755, 2010.5978647686832, 2010.679715302491, 2010.761565836299, 2010.8434163701068, 2010.9252669039147, 2011.0071174377224, 2011.0889679715303, 2011.170818505338, 2011.252669039146, 2011.3345195729537, 2011.4163701067616, 2011.4982206405693, 2011.5800711743773, 2011.661921708185, 2011.743772241993, 2011.8256227758006, 2011.9074733096086, 2011.9893238434163, 2012.0711743772242, 2012.153024911032, 2012.2348754448399, 2012.3167259786476, 2012.3985765124555, 2012.4804270462632, 2012.5622775800712, 2012.644128113879, 2012.7259786476868, 2012.8078291814948, 2012.8896797153025, 2012.9715302491104, 2013.053380782918, 2013.135231316726, 2013.2170818505338, 2013.2989323843417, 2013.3807829181494, 2013.4626334519573, 2013.544483985765, 2013.626334519573, 2013.7081850533807, 2013.7900355871886, 2013.8718861209964, 2013.9537366548043, 2014.035587188612, 2014.11743772242, 2014.1992882562276, 2014.2811387900356, 2014.3629893238435, 2014.4448398576512, 2014.5266903914592, 2014.6085409252669, 2014.6903914590748, 2014.7722419928825, 2014.8540925266905, 2014.9359430604982, 2015.017793594306, 2015.0996441281138, 2015.1814946619218, 2015.2633451957295, 2015.3451957295374, 2015.4270462633451, 2015.508896797153, 2015.5907473309608, 2015.6725978647687, 2015.7544483985764, 2015.8362989323844, 2015.918149466192, 2016.0], \"y\": [100.0, 100.66, 99.779225, 104.53204208416666, 108.512970686872, 111.42292685079163, 110.51482999695767, 112.00217541733339, 114.36075456133008, 113.1409065126759, 113.24650469208773, 111.9743689560466, 114.68788116374813, 116.01826058524762, 118.00507329777, 116.34120176427143, 117.11777928604793, 118.92822495751143, 120.08777515084716, 117.4578528750436, 118.25362982827201, 118.34034915681274, 118.99122107717521, 117.07447082432371, 119.30669073470747, 119.07503691019758, 119.18121215144252, 120.56868009623891, 121.21774149075699, 121.53088732294147, 121.36074408068936, 124.07922474809678, 122.91288003546468, 124.59371366994966, 125.9071390682204, 124.47074845668378, 122.98021124391501, 127.80001068958278, 129.33787081821407, 132.2479729116239, 134.6240281582694, 139.1788077776242, 135.57987577317445, 135.7256241396306, 137.7173976738797, 139.923171326623, 147.11055822710054, 153.10653939617345, 149.0989757274786, 150.09296889899514, 147.56390237304706, 149.25965755115067, 149.3977227343855, 149.00430873118492, 152.59282916646094, 155.13095655826308, 157.9491689357382, 168.15663397821027, 169.91106819271624, 174.4052159464136, 160.6911524658273, 165.10480278688868, 166.57285965833543, 169.5600662748749, 175.13435345366145, 174.483437439992, 174.75097871073334, 175.05096789085343, 176.34780381131148, 172.25506519785728, 175.15756304644117, 172.8629989705328, 171.22656258027843, 173.11290854470448, 172.41180126509843, 168.5799489819816, 172.75230271928567, 174.34306350682573, 175.1392301635069, 176.0295212501714, 176.56787820266152, 176.45458048081483, 179.6969333971498, 179.05152191136503, 179.11866623208178, 179.65303691967415, 179.98988636389856, 179.53991164798884, 179.910960798728, 181.36524106518436, 184.11745859834855, 186.1688339495651, 185.51724303074164, 185.97949016129323, 184.10574679791821, 185.7534932317596, 184.9593970481938, 185.24454278530976, 184.75673215597513, 186.10237702184446, 187.9509939669281, 189.5376136076656, 187.77175484088752, 191.3832315923273, 189.13926320190726, 193.1568963844211, 191.97542003486973, 192.94009652054496, 194.5189896437381, 195.04743289893693, 196.50216166930818, 195.71451550461705, 194.27275190706638, 197.657954609047, 200.94401810442238, 203.27831778140205, 202.79722576265274, 201.4621440263819, 205.00787776124625, 204.05629952863782, 213.70816249634234, 216.4204752586918, 211.27868546733737, 217.73500996407674, 213.8901725797944, 213.08273717830568, 218.67615902923623, 220.65882287110134, 223.97054403769175, 225.47487952514493, 234.52581698075014, 233.3219177869156, 232.5675102527379, 236.4494496113732, 240.38239212324237, 241.00938952936383, 242.2325121812253, 240.85582407032865, 247.4572807817229, 248.9234651703546, 248.6994340517013, 249.22584785377745, 246.23721456159754, 248.1845405334222, 250.22999478831852, 253.08261672890535, 256.3262922666475, 259.72902379648724, 260.92377730595103, 260.93682349481634, 264.98569320604423, 263.91470936266984, 268.7575442794748, 275.4115331465942, 282.8453494454427, 274.5014116368021, 277.9624169351895, 271.6526700707607, 271.0278689295979, 272.744378766152, 275.45136672540605, 274.19117672263735, 270.0029064981991, 277.4549867175494, 274.63419435258766, 276.02338565235453, 273.41956504770064, 273.14386698627754, 281.96186149215123, 286.2923257482349, 284.58650064065165, 283.54538835914127, 285.7026961889071, 285.6455556496693, 285.82646450158074, 282.09404725263096, 279.9195723050586, 282.6557861243405, 283.72281171695994, 283.14354430970445, 283.07511795316293, 281.6314348516018, 290.50751890667476, 292.6742208185204, 291.1815822923459, 294.8213520710002, 289.63249627455065, 290.97204656982046, 289.5002129675881, 287.1383737301275, 292.3116500968319, 297.5610801464875, 298.5306333326315, 307.7353278603876, 310.7972943725984, 313.29403263739164, 313.57338648316, 317.6158700572388, 320.9455430950055, 323.772538420434, 328.75863551210875, 322.2108593548259, 322.7398221822668, 320.97013215730067, 319.1245538973962, 330.69015960489435, 323.1476682145727, 327.00389705526663, 328.23833676665026, 326.2853186628887, 316.96715377074105, 313.4673081145225, 316.8501428145917, 319.23708055712837, 322.32037869350927, 318.33435001033286, 315.78502242400015, 311.3403482333824, 313.1668782763515, 316.4081554665118, 318.68365745124174, 315.4410512366754, 313.24347857972657, 316.5351454671352, 315.7569965678618, 314.4045040992295, 316.56865510244586, 311.90981972818815, 312.2815122633642, 311.5996976282559, 311.7996407675674, 314.4499377140917, 318.37532110322263, 324.1007706277289, 322.839478462036, 318.4111969491317, 314.52923377299356, 315.2552720876196, 318.6127407353527, 318.2888177822718, 325.91183496815717, 327.3621426337655, 328.94984902553927, 332.80130350788, 328.9962752711065, 334.8551506065595, 338.0613886736173, 343.850689954653, 359.13485312313736, 362.0857444996325, 367.05838872409413, 370.5117963980066, 374.6924045006975, 379.66644617044415, 380.60928451176744, 374.0025416814507, 369.10310838542364, 364.67694694403514, 362.0847016461746, 368.5267919629628, 369.34369301848074, 365.2347444336502, 360.68148461971066, 365.45750861188327, 379.93267143215223, 382.5827018153915, 384.6072019458313, 385.0751407081988, 387.4016363499775, 394.1230547406496, 391.955377939576, 394.9864995289754, 395.0523306122302, 394.1865075876384, 405.5784976569211, 403.050391688193, 407.11784189097966, 409.4960886173594, 409.40395199742056, 405.4259102638456, 411.67960492966546, 412.2147884160741, 412.9876911443543, 412.0756766597439, 413.6759038707726, 414.7859342128258, 415.4012000152415, 411.8737514917787, 409.4231026704026, 408.5633141547948, 406.99375008958344, 409.4730203505458, 405.96861375137905, 405.70811722422195, 407.1247147335299, 405.8287010582949, 403.9517433159003, 397.2192142606353, 403.6409248911822, 398.57523128379785, 404.47414470679803, 405.78531505922257, 400.94294363284916, 401.24030964937685, 404.3900460801244, 404.1137128819696, 399.3990528983466, 393.544528447945, 390.8061144374948, 402.35117840150235, 404.93963764921864, 395.40668367955993, 400.59969145855155, 403.81784231326856, 410.7332228628833, 411.499924878894, 417.816448725785, 415.0553783604554, 416.5253661588154, 408.3996504740005, 415.8121041301036, 413.123185856729, 419.6746310457736, 413.1766688417482, 412.40540572657693, 418.2787460464662, 415.29502432466813, 419.0257579598514, 425.72318632457626, 428.462005489931, 429.72953892283874, 436.71264393033493, 435.107724963891, 442.9106568315768, 456.19797653652404, 464.20044937493554, 472.14601373340315, 474.88052606294247, 471.2437327008438, 476.3802893872829, 473.6768312450101, 484.20824612635744, 489.93804370551936, 502.2354886025279, 516.9258766441518, 526.3425430303528, 535.6631922298486, 559.1297039094512, 585.3855029221993, 573.8485303021076, 595.6643385957593, 591.8868339151646, 587.102415341017, 586.3293971608181, 588.288714562997, 605.2265271364568, 609.8312922970866, 634.7733921520374, 647.8074058042259, 647.4889004963723, 696.174670072862, 740.4919892785836, 723.4174781591349, 743.2391170606952, 793.531630648469, 787.540466837073, 784.0490374340955, 810.4845574795818, 826.9981803382283, 853.0830812763965, 882.2443046046945, 906.498670945452, 913.4258316225935, 911.6979344244407, 934.3840180260356, 955.1740624271151, 944.0622041675463, 965.7126973831218, 1004.4136337307505, 1044.0042711269707, 1072.1401862338428, 1049.1338447375747, 1029.0953883030872, 1042.4822041459297, 1036.3228717897675, 1081.8951700767225, 1069.4082966554204, 1047.5032500455952, 1053.5962272833603, 1086.5737891973297, 1094.7230926163097, 1104.5391096801027, 1109.7580569733411, 1131.1671394891184, 1139.41523321456, 1133.737147302374, 1121.5967120166777, 1132.401427009105, 1113.5563799279619, 1102.1145881242019, 1077.9139886266414, 1086.4834048362231, 1067.053459946402, 1072.3353745731365, 1065.8030649163618, 1068.7162599604665, 1071.842255020851, 1061.3024728464793, 1076.036888844498, 1078.2427644666293, 1077.7575552226192, 1074.8296471975978, 1074.596767440705, 1087.9128123839075, 1101.8380963824216, 1105.0885187667498, 1093.0706811251612, 1082.5407668969888, 1085.075716526139, 1074.1616632774137, 1071.8343130069793, 1111.6440257825802, 1115.0252763610022, 1131.1188078498126, 1132.4195944788398, 1139.950184782124, 1144.2059988053109, 1155.190376393842, 1189.143346873351, 1176.6077940917278, 1180.8239720205563, 1180.9518946175253, 1194.4147462161652, 1190.990757277012, 1163.240672632458, 1194.0471631126743, 1194.8033929826454, 1204.0929893630857, 1249.7582159846806, 1266.6820251594731, 1289.3345220427416, 1279.3421794969104, 1287.8178214360776, 1288.7192939110828, 1302.4548937186853, 1308.7175309993158, 1310.4406757484649, 1306.804202873263, 1310.5285948514518, 1325.9163847693326, 1344.1477350599107, 1358.2612862780397, 1335.5670039531442, 1317.2363468238873, 1292.1759253255627, 1323.0804662062658, 1286.8060100911107, 1291.8352769138835, 1286.2373240472568, 1247.9610450124837, 1256.197587909566, 1316.2124276719455, 1283.603264776373, 1319.0093214964547, 1372.3742402953321, 1375.473518787999, 1416.8179603069013, 1426.4523224369882, 1421.7688039783202, 1490.8312236315671, 1459.9461701153332, 1650.7368021132384, 1657.766189662237, 1638.6189901716382, 1625.728520782288, 1640.5091025837337, 1647.330886268644, 1648.2781015282485, 1671.010603678492, 1717.2836723120224, 1725.14024511285, 1724.162665640619, 1707.3808156950502, 1755.4720420037943, 1741.9987940814149, 1798.9766713044946, 1771.602242956145, 1756.0859599782539, 1735.3641456505106, 1740.3822403050167, 1782.165917257673, 1800.6855914145087, 1836.5942632499668, 1826.4011650889295, 1819.597820748973, 1802.4784379187597, 1848.7871131196225, 1849.3263426942822, 1885.6193721696575, 1939.972350572448, 2063.5647557401676, 1966.0269282855159, 1952.7070958463814, 1995.6015617184737, 1992.8409795580965, 2001.2773397048925, 2031.863528380049, 2020.8237365425173, 1999.857690275889, 1975.9093944348351, 1983.2367251058645, 1981.4518120532694, 1986.075199614727, 2008.666805010344, 1980.7798142007837, 1958.6611062755417, 1955.3477045707589, 1980.2620932398313, 1994.420967206496, 2044.6138948811931, 1999.2916202113267, 1946.560303728253, 1940.4124174356448, 1952.2974434924379, 1928.886143315891, 1924.1442982135727, 1917.3135859549145, 1905.3942864955616, 1923.8130979316854, 1920.318170803776, 1898.65058077654, 1903.349740963962, 1894.0391884810801, 1891.1034277389344, 1898.8727109878955, 1891.957649532048, 1937.1439047283716, 1957.031915483583, 1982.0003810052945, 1976.8471800146806, 2017.6690742819837, 2007.7993097269546, 1984.2411311594915, 1978.2553370804937, 1987.9487882321878, 2038.9231084104413, 2136.502570173784, 2109.1731414636447, 2064.2653299933145, 2110.418862329748, 2101.1857798070555, 2098.7343963972803, 2162.1336646217815, 2112.494679238173, 2132.492962201628, 2204.7133905215233, 2203.3538172640347, 2167.5860402971152, 2085.5970983228767, 2093.226907707575, 2082.69099893878, 2095.1524334157634, 2066.0298145912843], \"mode\": \"line\", \"name\": \"Post-LASSO\"}], {\"title\": \"Post-LASSO\", \"autosize\": false, \"width\": 900, \"height\": 600, \"yaxis\": {\"type\": \"log\", \"autorange\": true}}, {\"showLink\": true, \"linkText\": \"Export to plot.ly\"})});</script>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "code",
"metadata": {
"scrolled": false,
"id": "mmuwIkGzfkZd",
"outputId": "359dcd1e-08d3-4802-fd33-0f0837769523",
"colab": {
"resources": {
"http://localhost:8080/static/components/requirejs/require.js": {
"data": "LyoqIHZpbTogZXQ6dHM9NDpzdz00OnN0cz00CiAqIEBsaWNlbnNlIFJlcXVpcmVKUyAyLjEuMjIgQ29weXJpZ2h0IChjKSAyMDEwLTIwMTUsIFRoZSBEb2pvIEZvdW5kYXRpb24gQWxsIFJpZ2h0cyBSZXNlcnZlZC4KICogQXZhaWxhYmxlIHZpYSB0aGUgTUlUIG9yIG5ldyBCU0QgbGljZW5zZS4KICogc2VlOiBodHRwOi8vZ2l0aHViLmNvbS9qcmJ1cmtlL3JlcXVpcmVqcyBmb3IgZGV0YWlscwogKi8KLy9Ob3QgdXNpbmcgc3RyaWN0OiB1bmV2ZW4gc3RyaWN0IHN1cHBvcnQgaW4gYnJvd3NlcnMsICMzOTIsIGFuZCBjYXVzZXMKLy9wcm9ibGVtcyB3aXRoIHJlcXVpcmVqcy5leGVjKCkvdHJhbnNwaWxlciBwbHVnaW5zIHRoYXQgbWF5IG5vdCBiZSBzdHJpY3QuCi8qanNsaW50IHJlZ2V4cDogdHJ1ZSwgbm9tZW46IHRydWUsIHNsb3BweTogdHJ1ZSAqLwovKmdsb2JhbCB3aW5kb3csIG5hdmlnYXRvciwgZG9jdW1lbnQsIGltcG9ydFNjcmlwdHMsIHNldFRpbWVvdXQsIG9wZXJhICovCgp2YXIgcmVxdWlyZWpzLCByZXF1aXJlLCBkZWZpbmU7CihmdW5jdGlvbiAoZ2xvYmFsKSB7CiAgICB2YXIgcmVxLCBzLCBoZWFkLCBiYXNlRWxlbWVudCwgZGF0YU1haW4sIHNyYywKICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCwgY3VycmVudGx5QWRkaW5nU2NyaXB0LCBtYWluU2NyaXB0LCBzdWJQYXRoLAogICAgICAgIHZlcnNpb24gPSAnMi4xLjIyJywKICAgICAgICBjb21tZW50UmVnRXhwID0gLyhcL1wqKFtcc1xTXSo/KVwqXC98KFteOl18XilcL1wvKC4qKSQpL21nLAogICAgICAgIGNqc1JlcXVpcmVSZWdFeHAgPSAvW14uXVxzKnJlcXVpcmVccypcKFxzKlsiJ10oW14nIlxzXSspWyInXVxzKlwpL2csCiAgICAgICAganNTdWZmaXhSZWdFeHAgPSAvXC5qcyQvLAogICAgICAgIGN1cnJEaXJSZWdFeHAgPSAvXlwuXC8vLAogICAgICAgIG9wID0gT2JqZWN0LnByb3RvdHlwZSwKICAgICAgICBvc3RyaW5nID0gb3AudG9TdHJpbmcsCiAgICAgICAgaGFzT3duID0gb3AuaGFzT3duUHJvcGVydHksCiAgICAgICAgYXAgPSBBcnJheS5wcm90b3R5cGUsCiAgICAgICAgaXNCcm93c2VyID0gISEodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmRvY3VtZW50KSwKICAgICAgICBpc1dlYldvcmtlciA9ICFpc0Jyb3dzZXIgJiYgdHlwZW9mIGltcG9ydFNjcmlwdHMgIT09ICd1bmRlZmluZWQnLAogICAgICAgIC8vUFMzIGluZGljYXRlcyBsb2FkZWQgYW5kIGNvbXBsZXRlLCBidXQgbmVlZCB0byB3YWl0IGZvciBjb21wbGV0ZQogICAgICAgIC8vc3BlY2lmaWNhbGx5LiBTZXF1ZW5jZSBpcyAnbG9hZGluZycsICdsb2FkZWQnLCBleGVjdXRpb24sCiAgICAgICAgLy8gdGhlbiAnY29tcGxldGUnLiBUaGUgVUEgY2hlY2sgaXMgdW5mb3J0dW5hdGUsIGJ1dCBub3Qgc3VyZSBob3cKICAgICAgICAvL3RvIGZlYXR1cmUgdGVzdCB3L28gY2F1c2luZyBwZXJmIGlzc3Vlcy4KICAgICAgICByZWFkeVJlZ0V4cCA9IGlzQnJvd3NlciAmJiBuYXZpZ2F0b3IucGxhdGZvcm0gPT09ICdQTEFZU1RBVElPTiAzJyA/CiAgICAgICAgICAgICAgICAgICAgICAvXmNvbXBsZXRlJC8gOiAvXihjb21wbGV0ZXxsb2FkZWQpJC8sCiAgICAgICAgZGVmQ29udGV4dE5hbWUgPSAnXycsCiAgICAgICAgLy9PaCB0aGUgdHJhZ2VkeSwgZGV0ZWN0aW5nIG9wZXJhLiBTZWUgdGhlIHVzYWdlIG9mIGlzT3BlcmEgZm9yIHJlYXNvbi4KICAgICAgICBpc09wZXJhID0gdHlwZW9mIG9wZXJhICE9PSAndW5kZWZpbmVkJyAmJiBvcGVyYS50b1N0cmluZygpID09PSAnW29iamVjdCBPcGVyYV0nLAogICAgICAgIGNvbnRleHRzID0ge30sCiAgICAgICAgY2ZnID0ge30sCiAgICAgICAgZ2xvYmFsRGVmUXVldWUgPSBbXSwKICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwoKICAgIGZ1bmN0aW9uIGlzRnVuY3Rpb24oaXQpIHsKICAgICAgICByZXR1cm4gb3N0cmluZy5jYWxsKGl0KSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJzsKICAgIH0KCiAgICBmdW5jdGlvbiBpc0FycmF5KGl0KSB7CiAgICAgICAgcmV0dXJuIG9zdHJpbmcuY2FsbChpdCkgPT09ICdbb2JqZWN0IEFycmF5XSc7CiAgICB9CgogICAgLyoqCiAgICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIGl0ZXJhdGluZyBvdmVyIGFuIGFycmF5LiBJZiB0aGUgZnVuYyByZXR1cm5zCiAgICAgKiBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoKGFyeSwgZnVuYykgewogICAgICAgIGlmIChhcnkpIHsKICAgICAgICAgICAgdmFyIGk7CiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBhcnkubGVuZ3RoOyBpICs9IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhlbHBlciBmdW5jdGlvbiBmb3IgaXRlcmF0aW5nIG92ZXIgYW4gYXJyYXkgYmFja3dhcmRzLiBJZiB0aGUgZnVuYwogICAgICogcmV0dXJucyBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoUmV2ZXJzZShhcnksIGZ1bmMpIHsKICAgICAgICBpZiAoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpOwogICAgICAgICAgICBmb3IgKGkgPSBhcnkubGVuZ3RoIC0gMTsgaSA+IC0xOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBoYXNQcm9wKG9iaiwgcHJvcCkgewogICAgICAgIHJldHVybiBoYXNPd24uY2FsbChvYmosIHByb3ApOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldE93bihvYmosIHByb3ApIHsKICAgICAgICByZXR1cm4gaGFzUHJvcChvYmosIHByb3ApICYmIG9ialtwcm9wXTsKICAgIH0KCiAgICAvKioKICAgICAqIEN5Y2xlcyBvdmVyIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGFuZCBjYWxscyBhIGZ1bmN0aW9uIGZvciBlYWNoCiAgICAgKiBwcm9wZXJ0eSB2YWx1ZS4gSWYgdGhlIGZ1bmN0aW9uIHJldHVybnMgYSB0cnV0aHkgdmFsdWUsIHRoZW4gdGhlCiAgICAgKiBpdGVyYXRpb24gaXMgc3RvcHBlZC4KICAgICAqLwogICAgZnVuY3Rpb24gZWFjaFByb3Aob2JqLCBmdW5jKSB7CiAgICAgICAgdmFyIHByb3A7CiAgICAgICAgZm9yIChwcm9wIGluIG9iaikgewogICAgICAgICAgICBpZiAoaGFzUHJvcChvYmosIHByb3ApKSB7CiAgICAgICAgICAgICAgICBpZiAoZnVuYyhvYmpbcHJvcF0sIHByb3ApKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBTaW1wbGUgZnVuY3Rpb24gdG8gbWl4IGluIHByb3BlcnRpZXMgZnJvbSBzb3VyY2UgaW50byB0YXJnZXQsCiAgICAgKiBidXQgb25seSBpZiB0YXJnZXQgZG9lcyBub3QgYWxyZWFkeSBoYXZlIGEgcHJvcGVydHkgb2YgdGhlIHNhbWUgbmFtZS4KICAgICAqLwogICAgZnVuY3Rpb24gbWl4aW4odGFyZ2V0LCBzb3VyY2UsIGZvcmNlLCBkZWVwU3RyaW5nTWl4aW4pIHsKICAgICAgICBpZiAoc291cmNlKSB7CiAgICAgICAgICAgIGVhY2hQcm9wKHNvdXJjZSwgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICBpZiAoZm9yY2UgfHwgIWhhc1Byb3AodGFyZ2V0LCBwcm9wKSkgewogICAgICAgICAgICAgICAgICAgIGlmIChkZWVwU3RyaW5nTWl4aW4gJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAhaXNBcnJheSh2YWx1ZSkgJiYgIWlzRnVuY3Rpb24odmFsdWUpICYmCiAgICAgICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApKSB7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRhcmdldFtwcm9wXSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0ge307CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgbWl4aW4odGFyZ2V0W3Byb3BdLCB2YWx1ZSwgZm9yY2UsIGRlZXBTdHJpbmdNaXhpbik7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0gdmFsdWU7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRhcmdldDsKICAgIH0KCiAgICAvL1NpbWlsYXIgdG8gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQsIGJ1dCB0aGUgJ3RoaXMnIG9iamVjdCBpcyBzcGVjaWZpZWQKICAgIC8vZmlyc3QsIHNpbmNlIGl0IGlzIGVhc2llciB0byByZWFkL2ZpZ3VyZSBvdXQgd2hhdCAndGhpcycgd2lsbCBiZS4KICAgIGZ1bmN0aW9uIGJpbmQob2JqLCBmbikgewogICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHJldHVybiBmbi5hcHBseShvYmosIGFyZ3VtZW50cyk7CiAgICAgICAgfTsKICAgIH0KCiAgICBmdW5jdGlvbiBzY3JpcHRzKCkgewogICAgICAgIHJldHVybiBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7CiAgICB9CgogICAgZnVuY3Rpb24gZGVmYXVsdE9uRXJyb3IoZXJyKSB7CiAgICAgICAgdGhyb3cgZXJyOwogICAgfQoKICAgIC8vQWxsb3cgZ2V0dGluZyBhIGdsb2JhbCB0aGF0IGlzIGV4cHJlc3NlZCBpbgogICAgLy9kb3Qgbm90YXRpb24sIGxpa2UgJ2EuYi5jJy4KICAgIGZ1bmN0aW9uIGdldEdsb2JhbCh2YWx1ZSkgewogICAgICAgIGlmICghdmFsdWUpIHsKICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgIH0KICAgICAgICB2YXIgZyA9IGdsb2JhbDsKICAgICAgICBlYWNoKHZhbHVlLnNwbGl0KCcuJyksIGZ1bmN0aW9uIChwYXJ0KSB7CiAgICAgICAgICAgIGcgPSBnW3BhcnRdOwogICAgICAgIH0pOwogICAgICAgIHJldHVybiBnOwogICAgfQoKICAgIC8qKgogICAgICogQ29uc3RydWN0cyBhbiBlcnJvciB3aXRoIGEgcG9pbnRlciB0byBhbiBVUkwgd2l0aCBtb3JlIGluZm9ybWF0aW9uLgogICAgICogQHBhcmFtIHtTdHJpbmd9IGlkIHRoZSBlcnJvciBJRCB0aGF0IG1hcHMgdG8gYW4gSUQgb24gYSB3ZWIgcGFnZS4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGh1bWFuIHJlYWRhYmxlIGVycm9yLgogICAgICogQHBhcmFtIHtFcnJvcn0gW2Vycl0gdGhlIG9yaWdpbmFsIGVycm9yLCBpZiB0aGVyZSBpcyBvbmUuCiAgICAgKgogICAgICogQHJldHVybnMge0Vycm9yfQogICAgICovCiAgICBmdW5jdGlvbiBtYWtlRXJyb3IoaWQsIG1zZywgZXJyLCByZXF1aXJlTW9kdWxlcykgewogICAgICAgIHZhciBlID0gbmV3IEVycm9yKG1zZyArICdcbmh0dHA6Ly9yZXF1aXJlanMub3JnL2RvY3MvZXJyb3JzLmh0bWwjJyArIGlkKTsKICAgICAgICBlLnJlcXVpcmVUeXBlID0gaWQ7CiAgICAgICAgZS5yZXF1aXJlTW9kdWxlcyA9IHJlcXVpcmVNb2R1bGVzOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgZS5vcmlnaW5hbEVycm9yID0gZXJyOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZTsKICAgIH0KCiAgICBpZiAodHlwZW9mIGRlZmluZSAhPT0gJ3VuZGVmaW5lZCcpIHsKICAgICAgICAvL0lmIGEgZGVmaW5lIGlzIGFscmVhZHkgaW4gcGxheSB2aWEgYW5vdGhlciBBTUQgbG9hZGVyLAogICAgICAgIC8vZG8gbm90IG92ZXJ3cml0ZS4KICAgICAgICByZXR1cm47CiAgICB9CgogICAgaWYgKHR5cGVvZiByZXF1aXJlanMgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgaWYgKGlzRnVuY3Rpb24ocmVxdWlyZWpzKSkgewogICAgICAgICAgICAvL0RvIG5vdCBvdmVyd3JpdGUgYW4gZXhpc3RpbmcgcmVxdWlyZWpzIGluc3RhbmNlLgogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNmZyA9IHJlcXVpcmVqczsKICAgICAgICByZXF1aXJlanMgPSB1bmRlZmluZWQ7CiAgICB9CgogICAgLy9BbGxvdyBmb3IgYSByZXF1aXJlIGNvbmZpZyBvYmplY3QKICAgIGlmICh0eXBlb2YgcmVxdWlyZSAhPT0gJ3VuZGVmaW5lZCcgJiYgIWlzRnVuY3Rpb24ocmVxdWlyZSkpIHsKICAgICAgICAvL2Fzc3VtZSBpdCBpcyBhIGNvbmZpZyBvYmplY3QuCiAgICAgICAgY2ZnID0gcmVxdWlyZTsKICAgICAgICByZXF1aXJlID0gdW5kZWZpbmVkOwogICAgfQoKICAgIGZ1bmN0aW9uIG5ld0NvbnRleHQoY29udGV4dE5hbWUpIHsKICAgICAgICB2YXIgaW5DaGVja0xvYWRlZCwgTW9kdWxlLCBjb250ZXh0LCBoYW5kbGVycywKICAgICAgICAgICAgY2hlY2tMb2FkZWRUaW1lb3V0SWQsCiAgICAgICAgICAgIGNvbmZpZyA9IHsKICAgICAgICAgICAgICAgIC8vRGVmYXVsdHMuIERvIG5vdCBzZXQgYSBkZWZhdWx0IGZvciBtYXAKICAgICAgICAgICAgICAgIC8vY29uZmlnIHRvIHNwZWVkIHVwIG5vcm1hbGl6ZSgpLCB3aGljaAogICAgICAgICAgICAgICAgLy93aWxsIHJ1biBmYXN0ZXIgaWYgdGhlcmUgaXMgbm8gZGVmYXVsdC4KICAgICAgICAgICAgICAgIHdhaXRTZWNvbmRzOiA3LAogICAgICAgICAgICAgICAgYmFzZVVybDogJy4vJywKICAgICAgICAgICAgICAgIHBhdGhzOiB7fSwKICAgICAgICAgICAgICAgIGJ1bmRsZXM6IHt9LAogICAgICAgICAgICAgICAgcGtnczoge30sCiAgICAgICAgICAgICAgICBzaGltOiB7fSwKICAgICAgICAgICAgICAgIGNvbmZpZzoge30KICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgLy9yZWdpc3RyeSBvZiBqdXN0IGVuYWJsZWQgbW9kdWxlcywgdG8gc3BlZWQKICAgICAgICAgICAgLy9jeWNsZSBicmVha2luZyBjb2RlIHdoZW4gbG90cyBvZiBtb2R1bGVzCiAgICAgICAgICAgIC8vYXJlIHJlZ2lzdGVyZWQsIGJ1dCBub3QgYWN0aXZhdGVkLgogICAgICAgICAgICBlbmFibGVkUmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgdW5kZWZFdmVudHMgPSB7fSwKICAgICAgICAgICAgZGVmUXVldWUgPSBbXSwKICAgICAgICAgICAgZGVmaW5lZCA9IHt9LAogICAgICAgICAgICB1cmxGZXRjaGVkID0ge30sCiAgICAgICAgICAgIGJ1bmRsZXNNYXAgPSB7fSwKICAgICAgICAgICAgcmVxdWlyZUNvdW50ZXIgPSAxLAogICAgICAgICAgICB1bm5vcm1hbGl6ZWRDb3VudGVyID0gMTsKCiAgICAgICAgLyoqCiAgICAgICAgICogVHJpbXMgdGhlIC4gYW5kIC4uIGZyb20gYW4gYXJyYXkgb2YgcGF0aCBzZWdtZW50cy4KICAgICAgICAgKiBJdCB3aWxsIGtlZXAgYSBsZWFkaW5nIHBhdGggc2VnbWVudCBpZiBhIC4uIHdpbGwgYmVjb21lCiAgICAgICAgICogdGhlIGZpcnN0IHBhdGggc2VnbWVudCwgdG8gaGVscCB3aXRoIG1vZHVsZSBuYW1lIGxvb2t1cHMsCiAgICAgICAgICogd2hpY2ggYWN0IGxpa2UgcGF0aHMsIGJ1dCBjYW4gYmUgcmVtYXBwZWQuIEJ1dCB0aGUgZW5kIHJlc3VsdCwKICAgICAgICAgKiBhbGwgcGF0aHMgdGhhdCB1c2UgdGhpcyBmdW5jdGlvbiBzaG91bGQgbG9vayBub3JtYWxpemVkLgogICAgICAgICAqIE5PVEU6IHRoaXMgbWV0aG9kIE1PRElGSUVTIHRoZSBpbnB1dCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnkgdGhlIGFycmF5IG9mIHBhdGggc2VnbWVudHMuCiAgICAgICAgICovCiAgICAgICAgZnVuY3Rpb24gdHJpbURvdHMoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpLCBwYXJ0OwogICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYXJ5Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBwYXJ0ID0gYXJ5W2ldOwogICAgICAgICAgICAgICAgaWYgKHBhcnQgPT09ICcuJykgewogICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSwgMSk7CiAgICAgICAgICAgICAgICAgICAgaSAtPSAxOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0ID09PSAnLi4nKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gSWYgYXQgdGhlIHN0YXJ0LCBvciBwcmV2aW91cyB2YWx1ZSBpcyBzdGlsbCAuLiwKICAgICAgICAgICAgICAgICAgICAvLyBrZWVwIHRoZW0gc28gdGhhdCB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGggaXQgbWF5CiAgICAgICAgICAgICAgICAgICAgLy8gc3RpbGwgd29yayB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGgsIGV2ZW4gdGhvdWdoCiAgICAgICAgICAgICAgICAgICAgLy8gYXMgYW4gSUQgaXQgaXMgbGVzcyB0aGFuIGlkZWFsLiBJbiBsYXJnZXIgcG9pbnQKICAgICAgICAgICAgICAgICAgICAvLyByZWxlYXNlcywgbWF5IGJlIGJldHRlciB0byBqdXN0IGtpY2sgb3V0IGFuIGVycm9yLgogICAgICAgICAgICAgICAgICAgIGlmIChpID09PSAwIHx8IChpID09PSAxICYmIGFyeVsyXSA9PT0gJy4uJykgfHwgYXJ5W2kgLSAxXSA9PT0gJy4uJykgewogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSAtIDEsIDIpOwogICAgICAgICAgICAgICAgICAgICAgICBpIC09IDI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHaXZlbiBhIHJlbGF0aXZlIG1vZHVsZSBuYW1lLCBsaWtlIC4vc29tZXRoaW5nLCBub3JtYWxpemUgaXQgdG8KICAgICAgICAgKiBhIHJlYWwgbmFtZSB0aGF0IGNhbiBiZSBtYXBwZWQgdG8gYSBwYXRoLgogICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSByZWxhdGl2ZSBuYW1lCiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGJhc2VOYW1lIGEgcmVhbCBuYW1lIHRoYXQgdGhlIG5hbWUgYXJnIGlzIHJlbGF0aXZlCiAgICAgICAgICogdG8uCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBhcHBseU1hcCBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgdmFsdWUuIFNob3VsZAogICAgICAgICAqIG9ubHkgYmUgZG9uZSBpZiB0aGlzIG5vcm1hbGl6YXRpb24gaXMgZm9yIGEgZGVwZW5kZW5jeSBJRC4KICAgICAgICAgKiBAcmV0dXJucyB7U3RyaW5nfSBub3JtYWxpemVkIG5hbWUKICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBub3JtYWxpemUobmFtZSwgYmFzZU5hbWUsIGFwcGx5TWFwKSB7CiAgICAgICAgICAgIHZhciBwa2dNYWluLCBtYXBWYWx1ZSwgbmFtZVBhcnRzLCBpLCBqLCBuYW1lU2VnbWVudCwgbGFzdEluZGV4LAogICAgICAgICAgICAgICAgZm91bmRNYXAsIGZvdW5kSSwgZm91bmRTdGFyTWFwLCBzdGFySSwgbm9ybWFsaXplZEJhc2VQYXJ0cywKICAgICAgICAgICAgICAgIGJhc2VQYXJ0cyA9IChiYXNlTmFtZSAmJiBiYXNlTmFtZS5zcGxpdCgnLycpKSwKICAgICAgICAgICAgICAgIG1hcCA9IGNvbmZpZy5tYXAsCiAgICAgICAgICAgICAgICBzdGFyTWFwID0gbWFwICYmIG1hcFsnKiddOwoKICAgICAgICAgICAgLy9BZGp1c3QgYW55IHJlbGF0aXZlIHBhdGhzLgogICAgICAgICAgICBpZiAobmFtZSkgewogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3BsaXQoJy8nKTsKICAgICAgICAgICAgICAgIGxhc3RJbmRleCA9IG5hbWUubGVuZ3RoIC0gMTsKCiAgICAgICAgICAgICAgICAvLyBJZiB3YW50aW5nIG5vZGUgSUQgY29tcGF0aWJpbGl0eSwgc3RyaXAgLmpzIGZyb20gZW5kCiAgICAgICAgICAgICAgICAvLyBvZiBJRHMuIEhhdmUgdG8gZG8gdGhpcyBoZXJlLCBhbmQgbm90IGluIG5hbWVUb1VybAogICAgICAgICAgICAgICAgLy8gYmVjYXVzZSBub2RlIGFsbG93cyBlaXRoZXIgLmpzIG9yIG5vbiAuanMgdG8gbWFwCiAgICAgICAgICAgICAgICAvLyB0byBzYW1lIGZpbGUuCiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm5vZGVJZENvbXBhdCAmJiBqc1N1ZmZpeFJlZ0V4cC50ZXN0KG5hbWVbbGFzdEluZGV4XSkpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lW2xhc3RJbmRleF0gPSBuYW1lW2xhc3RJbmRleF0ucmVwbGFjZShqc1N1ZmZpeFJlZ0V4cCwgJycpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIFN0YXJ0cyB3aXRoIGEgJy4nIHNvIG5lZWQgdGhlIGJhc2VOYW1lCiAgICAgICAgICAgICAgICBpZiAobmFtZVswXS5jaGFyQXQoMCkgPT09ICcuJyAmJiBiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAvL0NvbnZlcnQgYmFzZU5hbWUgdG8gYXJyYXksIGFuZCBsb3Agb2ZmIHRoZSBsYXN0IHBhcnQsCiAgICAgICAgICAgICAgICAgICAgLy9zbyB0aGF0IC4gbWF0Y2hlcyB0aGF0ICdkaXJlY3RvcnknIGFuZCBub3QgbmFtZSBvZiB0aGUgYmFzZU5hbWUncwogICAgICAgICAgICAgICAgICAgIC8vbW9kdWxlLiBGb3IgaW5zdGFuY2UsIGJhc2VOYW1lIG9mICdvbmUvdHdvL3RocmVlJywgbWFwcyB0bwogICAgICAgICAgICAgICAgICAgIC8vJ29uZS90d28vdGhyZWUuanMnLCBidXQgd2Ugd2FudCB0aGUgZGlyZWN0b3J5LCAnb25lL3R3bycgZm9yCiAgICAgICAgICAgICAgICAgICAgLy90aGlzIG5vcm1hbGl6YXRpb24uCiAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZEJhc2VQYXJ0cyA9IGJhc2VQYXJ0cy5zbGljZSgwLCBiYXNlUGFydHMubGVuZ3RoIC0gMSk7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vcm1hbGl6ZWRCYXNlUGFydHMuY29uY2F0KG5hbWUpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHRyaW1Eb3RzKG5hbWUpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuam9pbignLycpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL0FwcGx5IG1hcCBjb25maWcgaWYgYXZhaWxhYmxlLgogICAgICAgICAgICBpZiAoYXBwbHlNYXAgJiYgbWFwICYmIChiYXNlUGFydHMgfHwgc3Rhck1hcCkpIHsKICAgICAgICAgICAgICAgIG5hbWVQYXJ0cyA9IG5hbWUuc3BsaXQoJy8nKTsKCiAgICAgICAgICAgICAgICBvdXRlckxvb3A6IGZvciAoaSA9IG5hbWVQYXJ0cy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lU2VnbWVudCA9IG5hbWVQYXJ0cy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9GaW5kIHRoZSBsb25nZXN0IGJhc2VOYW1lIHNlZ21lbnQgbWF0Y2ggaW4gdGhlIGNvbmZpZy4KICAgICAgICAgICAgICAgICAgICAgICAgLy9TbywgZG8gam9pbnMgb24gdGhlIGJpZ2dlc3QgdG8gc21hbGxlc3QgbGVuZ3RocyBvZiBiYXNlUGFydHMuCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaiA9IGJhc2VQYXJ0cy5sZW5ndGg7IGogPiAwOyBqIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcFZhbHVlID0gZ2V0T3duKG1hcCwgYmFzZVBhcnRzLnNsaWNlKDAsIGopLmpvaW4oJy8nKSk7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iYXNlTmFtZSBzZWdtZW50IGhhcyBjb25maWcsIGZpbmQgaWYgaXQgaGFzIG9uZSBmb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hcFZhbHVlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwVmFsdWUgPSBnZXRPd24obWFwVmFsdWUsIG5hbWVTZWdtZW50KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWFwVmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXRjaCwgdXBkYXRlIG5hbWUgdG8gdGhlIG5ldyB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRNYXAgPSBtYXBWYWx1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRJID0gaTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsgb3V0ZXJMb29wOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9DaGVjayBmb3IgYSBzdGFyIG1hcCBtYXRjaCwgYnV0IGp1c3QgaG9sZCBvbiB0byBpdCwKICAgICAgICAgICAgICAgICAgICAvL2lmIHRoZXJlIGlzIGEgc2hvcnRlciBzZWdtZW50IG1hdGNoIGxhdGVyIGluIGEgbWF0Y2hpbmcKICAgICAgICAgICAgICAgICAgICAvL2NvbmZpZywgdGhlbiBmYXZvciBvdmVyIHRoaXMgc3RhciBtYXAuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFmb3VuZFN0YXJNYXAgJiYgc3Rhck1hcCAmJiBnZXRPd24oc3Rhck1hcCwgbmFtZVNlZ21lbnQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvdW5kU3Rhck1hcCA9IGdldE93bihzdGFyTWFwLCBuYW1lU2VnbWVudCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJJID0gaTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFmb3VuZE1hcCAmJiBmb3VuZFN0YXJNYXApIHsKICAgICAgICAgICAgICAgICAgICBmb3VuZE1hcCA9IGZvdW5kU3Rhck1hcDsKICAgICAgICAgICAgICAgICAgICBmb3VuZEkgPSBzdGFySTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBpZiAoZm91bmRNYXApIHsKICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMuc3BsaWNlKDAsIGZvdW5kSSwgZm91bmRNYXApOwogICAgICAgICAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHMuam9pbignLycpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBJZiB0aGUgbmFtZSBwb2ludHMgdG8gYSBwYWNrYWdlJ3MgbmFtZSwgdXNlCiAgICAgICAgICAgIC8vIHRoZSBwYWNrYWdlIG1haW4gaW5zdGVhZC4KICAgICAgICAgICAgcGtnTWFpbiA9IGdldE93bihjb25maWcucGtncywgbmFtZSk7CgogICAgICAgICAgICByZXR1cm4gcGtnTWFpbiA/IHBrZ01haW4gOiBuYW1lOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gcmVtb3ZlU2NyaXB0KG5hbWUpIHsKICAgICAgICAgICAgaWYgKGlzQnJvd3NlcikgewogICAgICAgICAgICAgICAgZWFjaChzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHROb2RlKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKHNjcmlwdE5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKSA9PT0gbmFtZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NyaXB0Tm9kZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcmVxdWlyZWNvbnRleHQnKSA9PT0gY29udGV4dC5jb250ZXh0TmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzY3JpcHROb2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoc2NyaXB0Tm9kZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBoYXNQYXRoRmFsbGJhY2soaWQpIHsKICAgICAgICAgICAgdmFyIHBhdGhDb25maWcgPSBnZXRPd24oY29uZmlnLnBhdGhzLCBpZCk7CiAgICAgICAgICAgIGlmIChwYXRoQ29uZmlnICYmIGlzQXJyYXkocGF0aENvbmZpZykgJiYgcGF0aENvbmZpZy5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAvL1BvcCBvZmYgdGhlIGZpcnN0IGFycmF5IHZhbHVlLCBzaW5jZSBpdCBmYWlsZWQsIGFuZAogICAgICAgICAgICAgICAgLy9yZXRyeQogICAgICAgICAgICAgICAgcGF0aENvbmZpZy5zaGlmdCgpOwogICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlLnVuZGVmKGlkKTsKCiAgICAgICAgICAgICAgICAvL0N1c3RvbSByZXF1aXJlIHRoYXQgZG9lcyBub3QgZG8gbWFwIHRyYW5zbGF0aW9uLCBzaW5jZQogICAgICAgICAgICAgICAgLy9JRCBpcyAiYWJzb2x1dGUiLCBhbHJlYWR5IG1hcHBlZC9yZXNvbHZlZC4KICAgICAgICAgICAgICAgIGNvbnRleHQubWFrZVJlcXVpcmUobnVsbCwgewogICAgICAgICAgICAgICAgICAgIHNraXBNYXA6IHRydWUKICAgICAgICAgICAgICAgIH0pKFtpZF0pOwoKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvL1R1cm5zIGEgcGx1Z2luIXJlc291cmNlIHRvIFtwbHVnaW4sIHJlc291cmNlXQogICAgICAgIC8vd2l0aCB0aGUgcGx1Z2luIGJlaW5nIHVuZGVmaW5lZCBpZiB0aGUgbmFtZQogICAgICAgIC8vZGlkIG5vdCBoYXZlIGEgcGx1Z2luIHByZWZpeC4KICAgICAgICBmdW5jdGlvbiBzcGxpdFByZWZpeChuYW1lKSB7CiAgICAgICAgICAgIHZhciBwcmVmaXgsCiAgICAgICAgICAgICAgICBpbmRleCA9IG5hbWUgPyBuYW1lLmluZGV4T2YoJyEnKSA6IC0xOwogICAgICAgICAgICBpZiAoaW5kZXggPiAtMSkgewogICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZS5zdWJzdHJpbmcoMCwgaW5kZXgpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyaW5nKGluZGV4ICsgMSwgbmFtZS5sZW5ndGgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBbcHJlZml4LCBuYW1lXTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBtb2R1bGUgbWFwcGluZyB0aGF0IGluY2x1ZGVzIHBsdWdpbiBwcmVmaXgsIG1vZHVsZQogICAgICAgICAqIG5hbWUsIGFuZCBwYXRoLiBJZiBwYXJlbnRNb2R1bGVNYXAgaXMgcHJvdmlkZWQgaXQgd2lsbAogICAgICAgICAqIGFsc28gbm9ybWFsaXplIHRoZSBuYW1lIHZpYSByZXF1aXJlLm5vcm1hbGl6ZSgpCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSB0aGUgbW9kdWxlIG5hbWUKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gW3BhcmVudE1vZHVsZU1hcF0gcGFyZW50IG1vZHVsZSBtYXAKICAgICAgICAgKiBmb3IgdGhlIG1vZHVsZSBuYW1lLCB1c2VkIHRvIHJlc29sdmUgcmVsYXRpdmUgbmFtZXMuCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBpc05vcm1hbGl6ZWQ6IGlzIHRoZSBJRCBhbHJlYWR5IG5vcm1hbGl6ZWQuCiAgICAgICAgICogVGhpcyBpcyB0cnVlIGlmIHRoaXMgY2FsbCBpcyBkb25lIGZvciBhIGRlZmluZSgpIG1vZHVsZSBJRC4KICAgICAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGx5TWFwOiBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgSUQuCiAgICAgICAgICogU2hvdWxkIG9ubHkgYmUgdHJ1ZSBpZiB0aGlzIG1hcCBpcyBmb3IgYSBkZXBlbmRlbmN5LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge09iamVjdH0KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBtYWtlTW9kdWxlTWFwKG5hbWUsIHBhcmVudE1vZHVsZU1hcCwgaXNOb3JtYWxpemVkLCBhcHBseU1hcCkgewogICAgICAgICAgICB2YXIgdXJsLCBwbHVnaW5Nb2R1bGUsIHN1ZmZpeCwgbmFtZVBhcnRzLAogICAgICAgICAgICAgICAgcHJlZml4ID0gbnVsbCwKICAgICAgICAgICAgICAgIHBhcmVudE5hbWUgPSBwYXJlbnRNb2R1bGVNYXAgPyBwYXJlbnRNb2R1bGVNYXAubmFtZSA6IG51bGwsCiAgICAgICAgICAgICAgICBvcmlnaW5hbE5hbWUgPSBuYW1lLAogICAgICAgICAgICAgICAgaXNEZWZpbmUgPSB0cnVlLAogICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUgPSAnJzsKCiAgICAgICAgICAgIC8vSWYgbm8gbmFtZSwgdGhlbiBpdCBtZWFucyBpdCBpcyBhIHJlcXVpcmUgY2FsbCwgZ2VuZXJhdGUgYW4KICAgICAgICAgICAgLy9pbnRlcm5hbCBuYW1lLgogICAgICAgICAgICBpZiAoIW5hbWUpIHsKICAgICAgICAgICAgICAgIGlzRGVmaW5lID0gZmFsc2U7CiAgICAgICAgICAgICAgICBuYW1lID0gJ19AcicgKyAocmVxdWlyZUNvdW50ZXIgKz0gMSk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIG5hbWVQYXJ0cyA9IHNwbGl0UHJlZml4KG5hbWUpOwogICAgICAgICAgICBwcmVmaXggPSBuYW1lUGFydHNbMF07CiAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHNbMV07CgogICAgICAgICAgICBpZiAocHJlZml4KSB7CiAgICAgICAgICAgICAgICBwcmVmaXggPSBub3JtYWxpemUocHJlZml4LCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICBwbHVnaW5Nb2R1bGUgPSBnZXRPd24oZGVmaW5lZCwgcHJlZml4KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9BY2NvdW50IGZvciByZWxhdGl2ZSBwYXRocyBpZiB0aGVyZSBpcyBhIGJhc2UgbmFtZS4KICAgICAgICAgICAgaWYgKG5hbWUpIHsKICAgICAgICAgICAgICAgIGlmIChwcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICBpZiAocGx1Z2luTW9kdWxlICYmIHBsdWdpbk1vZHVsZS5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9QbHVnaW4gaXMgbG9hZGVkLCB1c2UgaXRzIG5vcm1hbGl6ZSBtZXRob2QuCiAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gcGx1Z2luTW9kdWxlLm5vcm1hbGl6ZShuYW1lLCBmdW5jdGlvbiAobmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIG5lc3RlZCBwbHVnaW4gcmVmZXJlbmNlcywgdGhlbiBkbyBub3QgdHJ5IHRvCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSwgYXMgaXQgd2lsbCBub3Qgbm9ybWFsaXplIGNvcnJlY3RseS4gVGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvLyBwbGFjZXMgYSByZXN0cmljdGlvbiBvbiByZXNvdXJjZUlkcywgYW5kIHRoZSBsb25nZXIKICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGVybSBzb2x1dGlvbiBpcyBub3QgdG8gbm9ybWFsaXplIHVudGlsIHBsdWdpbnMgYXJlCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvYWRlZCBhbmQgYWxsIG5vcm1hbGl6YXRpb25zIHRvIGFsbG93IGZvciBhc3luYwogICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2FkaW5nIG9mIGEgbG9hZGVyIHBsdWdpbi4gQnV0IGZvciBub3csIGZpeGVzIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAvLyBjb21tb24gdXNlcy4gRGV0YWlscyBpbiAjMTEzMQogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5hbWUuaW5kZXhPZignIScpID09PSAtMSA/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplKG5hbWUsIHBhcmVudE5hbWUsIGFwcGx5TWFwKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIC8vQSByZWd1bGFyIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CgogICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplZCBuYW1lIG1heSBiZSBhIHBsdWdpbiBJRCBkdWUgdG8gbWFwIGNvbmZpZwogICAgICAgICAgICAgICAgICAgIC8vYXBwbGljYXRpb24gaW4gbm9ybWFsaXplLiBUaGUgbWFwIGNvbmZpZyB2YWx1ZXMgbXVzdAogICAgICAgICAgICAgICAgICAgIC8vYWxyZWFkeSBiZSBub3JtYWxpemVkLCBzbyBkbyBub3QgbmVlZCB0byByZWRvIHRoYXQgcGFydC4KICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMgPSBzcGxpdFByZWZpeChub3JtYWxpemVkTmFtZSk7CiAgICAgICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZVBhcnRzWzBdOwogICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gbmFtZVBhcnRzWzFdOwogICAgICAgICAgICAgICAgICAgIGlzTm9ybWFsaXplZCA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIHVybCA9IGNvbnRleHQubmFtZVRvVXJsKG5vcm1hbGl6ZWROYW1lKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiB0aGUgaWQgaXMgYSBwbHVnaW4gaWQgdGhhdCBjYW5ub3QgYmUgZGV0ZXJtaW5lZCBpZiBpdCBuZWVkcwogICAgICAgICAgICAvL25vcm1hbGl6YXRpb24sIHN0YW1wIGl0IHdpdGggYSB1bmlxdWUgSUQgc28gdHdvIG1hdGNoaW5nIHJlbGF0aXZlCiAgICAgICAgICAgIC8vaWRzIHRoYXQgbWF5IGNvbmZsaWN0IGNhbiBiZSBzZXBhcmF0ZS4KICAgICAgICAgICAgc3VmZml4ID0gcHJlZml4ICYmICFwbHVnaW5Nb2R1bGUgJiYgIWlzTm9ybWFsaXplZCA/CiAgICAgICAgICAgICAgICAgICAgICdfdW5ub3JtYWxpemVkJyArICh1bm5vcm1hbGl6ZWRDb3VudGVyICs9IDEpIDoKICAgICAgICAgICAgICAgICAgICAgJyc7CgogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcHJlZml4OiBwcmVmaXgsCiAgICAgICAgICAgICAgICBuYW1lOiBub3JtYWxpemVkTmFtZSwKICAgICAgICAgICAgICAgIHBhcmVudE1hcDogcGFyZW50TW9kdWxlTWFwLAogICAgICAgICAgICAgICAgdW5ub3JtYWxpemVkOiAhIXN1ZmZpeCwKICAgICAgICAgICAgICAgIHVybDogdXJsLAogICAgICAgICAgICAgICAgb3JpZ2luYWxOYW1lOiBvcmlnaW5hbE5hbWUsCiAgICAgICAgICAgICAgICBpc0RlZmluZTogaXNEZWZpbmUsCiAgICAgICAgICAgICAgICBpZDogKHByZWZpeCA/CiAgICAgICAgICAgICAgICAgICAgICAgIHByZWZpeCArICchJyArIG5vcm1hbGl6ZWROYW1lIDoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUpICsgc3VmZml4CiAgICAgICAgICAgIH07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBnZXRNb2R1bGUoZGVwTWFwKSB7CiAgICAgICAgICAgIHZhciBpZCA9IGRlcE1hcC5pZCwKICAgICAgICAgICAgICAgIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwoKICAgICAgICAgICAgaWYgKCFtb2QpIHsKICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXSA9IG5ldyBjb250ZXh0Lk1vZHVsZShkZXBNYXApOwogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gbW9kOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gb24oZGVwTWFwLCBuYW1lLCBmbikgewogICAgICAgICAgICB2YXIgaWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIGlkKTsKCiAgICAgICAgICAgIGlmIChoYXNQcm9wKGRlZmluZWQsIGlkKSAmJgogICAgICAgICAgICAgICAgICAgICghbW9kIHx8IG1vZC5kZWZpbmVFbWl0Q29tcGxldGUpKSB7CiAgICAgICAgICAgICAgICBpZiAobmFtZSA9PT0gJ2RlZmluZWQnKSB7CiAgICAgICAgICAgICAgICAgICAgZm4oZGVmaW5lZFtpZF0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgbW9kID0gZ2V0TW9kdWxlKGRlcE1hcCk7CiAgICAgICAgICAgICAgICBpZiAobW9kLmVycm9yICYmIG5hbWUgPT09ICdlcnJvcicpIHsKICAgICAgICAgICAgICAgICAgICBmbihtb2QuZXJyb3IpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBtb2Qub24obmFtZSwgZm4pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBvbkVycm9yKGVyciwgZXJyYmFjaykgewogICAgICAgICAgICB2YXIgaWRzID0gZXJyLnJlcXVpcmVNb2R1bGVzLAogICAgICAgICAgICAgICAgbm90aWZpZWQgPSBmYWxzZTsKCiAgICAgICAgICAgIGlmIChlcnJiYWNrKSB7CiAgICAgICAgICAgICAgICBlcnJiYWNrKGVycik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBlYWNoKGlkcywgZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwogICAgICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9TZXQgZXJyb3Igb24gbW9kdWxlLCBzbyBpdCBza2lwcyB0aW1lb3V0IGNoZWNrcy4KICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVycm9yID0gZXJyOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90aWZpZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIGlmICghbm90aWZpZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdG8gdHJhbnNmZXIgZ2xvYmFsUXVldWUgaXRlbXMgdG8gdGhpcyBjb250ZXh0J3MKICAgICAgICAgKiBkZWZRdWV1ZS4KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiB0YWtlR2xvYmFsUXVldWUoKSB7CiAgICAgICAgICAgIC8vUHVzaCBhbGwgdGhlIGdsb2JhbERlZlF1ZXVlIGl0ZW1zIGludG8gdGhlIGNvbnRleHQncyBkZWZRdWV1ZQogICAgICAgICAgICBpZiAoZ2xvYmFsRGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBlYWNoKGdsb2JhbERlZlF1ZXVlLCBmdW5jdGlvbihxdWV1ZUl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQgPSBxdWV1ZUl0ZW1bMF07CiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcFtpZF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBkZWZRdWV1ZS5wdXNoKHF1ZXVlSXRlbSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGdsb2JhbERlZlF1ZXVlID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGhhbmRsZXJzID0gewogICAgICAgICAgICAncmVxdWlyZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QucmVxdWlyZSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBtb2QucmVxdWlyZTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChtb2QucmVxdWlyZSA9IGNvbnRleHQubWFrZVJlcXVpcmUobW9kLm1hcCkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAnZXhwb3J0cyc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIG1vZC51c2luZ0V4cG9ydHMgPSB0cnVlOwogICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChkZWZpbmVkW21vZC5tYXAuaWRdID0gbW9kLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLmV4cG9ydHMgPSBkZWZpbmVkW21vZC5tYXAuaWRdID0ge30pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgJ21vZHVsZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QubW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vZC5tb2R1bGU7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLm1vZHVsZSA9IHsKICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IG1vZC5tYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIHVyaTogbW9kLm1hcC51cmwsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZzogZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdldE93bihjb25maWcuY29uZmlnLCBtb2QubWFwLmlkKSB8fCB7fTsKICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0czogbW9kLmV4cG9ydHMgfHwgKG1vZC5leHBvcnRzID0ge30pCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjbGVhblJlZ2lzdHJ5KGlkKSB7CiAgICAgICAgICAgIC8vQ2xlYW4gdXAgbWFjaGluZXJ5IHVzZWQgZm9yIHdhaXRpbmcgbW9kdWxlcy4KICAgICAgICAgICAgZGVsZXRlIHJlZ2lzdHJ5W2lkXTsKICAgICAgICAgICAgZGVsZXRlIGVuYWJsZWRSZWdpc3RyeVtpZF07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBicmVha0N5Y2xlKG1vZCwgdHJhY2VkLCBwcm9jZXNzZWQpIHsKICAgICAgICAgICAgdmFyIGlkID0gbW9kLm1hcC5pZDsKCiAgICAgICAgICAgIGlmIChtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgIG1vZC5lbWl0KCdlcnJvcicsIG1vZC5lcnJvcik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB0cmFjZWRbaWRdID0gdHJ1ZTsKICAgICAgICAgICAgICAgIGVhY2gobW9kLmRlcE1hcHMsIGZ1bmN0aW9uIChkZXBNYXAsIGkpIHsKICAgICAgICAgICAgICAgICAgICB2YXIgZGVwSWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlcCA9IGdldE93bihyZWdpc3RyeSwgZGVwSWQpOwoKICAgICAgICAgICAgICAgICAgICAvL09ubHkgZm9yY2UgdGhpbmdzIHRoYXQgaGF2ZSBub3QgY29tcGxldGVkCiAgICAgICAgICAgICAgICAgICAgLy9iZWluZyBkZWZpbmVkLCBzbyBzdGlsbCBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAgICAgLy9hbmQgb25seSBpZiBpdCBoYXMgbm90IGJlZW4gbWF0Y2hlZCB1cAogICAgICAgICAgICAgICAgICAgIC8vaW4gdGhlIG1vZHVsZSBhbHJlYWR5LgogICAgICAgICAgICAgICAgICAgIGlmIChkZXAgJiYgIW1vZC5kZXBNYXRjaGVkW2ldICYmICFwcm9jZXNzZWRbZGVwSWRdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChnZXRPd24odHJhY2VkLCBkZXBJZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZC5kZWZpbmVEZXAoaSwgZGVmaW5lZFtkZXBJZF0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmNoZWNrKCk7IC8vcGFzcyBmYWxzZT8KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrQ3ljbGUoZGVwLCB0cmFjZWQsIHByb2Nlc3NlZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHByb2Nlc3NlZFtpZF0gPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBjaGVja0xvYWRlZCgpIHsKICAgICAgICAgICAgdmFyIGVyciwgdXNpbmdQYXRoRmFsbGJhY2ssCiAgICAgICAgICAgICAgICB3YWl0SW50ZXJ2YWwgPSBjb25maWcud2FpdFNlY29uZHMgKiAxMDAwLAogICAgICAgICAgICAgICAgLy9JdCBpcyBwb3NzaWJsZSB0byBkaXNhYmxlIHRoZSB3YWl0IGludGVydmFsIGJ5IHVzaW5nIHdhaXRTZWNvbmRzIG9mIDAuCiAgICAgICAgICAgICAgICBleHBpcmVkID0gd2FpdEludGVydmFsICYmIChjb250ZXh0LnN0YXJ0VGltZSArIHdhaXRJbnRlcnZhbCkgPCBuZXcgRGF0ZSgpLmdldFRpbWUoKSwKICAgICAgICAgICAgICAgIG5vTG9hZHMgPSBbXSwKICAgICAgICAgICAgICAgIHJlcUNhbGxzID0gW10sCiAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSBmYWxzZSwKICAgICAgICAgICAgICAgIG5lZWRDeWNsZUNoZWNrID0gdHJ1ZTsKCiAgICAgICAgICAgIC8vRG8gbm90IGJvdGhlciBpZiB0aGlzIGNhbGwgd2FzIGEgcmVzdWx0IG9mIGEgY3ljbGUgYnJlYWsuCiAgICAgICAgICAgIGlmIChpbkNoZWNrTG9hZGVkKSB7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGluQ2hlY2tMb2FkZWQgPSB0cnVlOwoKICAgICAgICAgICAgLy9GaWd1cmUgb3V0IHRoZSBzdGF0ZSBvZiBhbGwgdGhlIG1vZHVsZXMuCiAgICAgICAgICAgIGVhY2hQcm9wKGVuYWJsZWRSZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgdmFyIG1hcCA9IG1vZC5tYXAsCiAgICAgICAgICAgICAgICAgICAgbW9kSWQgPSBtYXAuaWQ7CgogICAgICAgICAgICAgICAgLy9Ta2lwIHRoaW5ncyB0aGF0IGFyZSBub3QgZW5hYmxlZCBvciBpbiBlcnJvciBzdGF0ZS4KICAgICAgICAgICAgICAgIGlmICghbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICByZXFDYWxscy5wdXNoKG1vZCk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIHRoZSBtb2R1bGUgc2hvdWxkIGJlIGV4ZWN1dGVkLCBhbmQgaXQgaGFzIG5vdAogICAgICAgICAgICAgICAgICAgIC8vYmVlbiBpbml0ZWQgYW5kIHRpbWUgaXMgdXAsIHJlbWVtYmVyIGl0LgogICAgICAgICAgICAgICAgICAgIGlmICghbW9kLmluaXRlZCAmJiBleHBpcmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoYXNQYXRoRmFsbGJhY2sobW9kSWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2luZ1BhdGhGYWxsYmFjayA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9Mb2Fkcy5wdXNoKG1vZElkKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChtb2RJZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFtb2QuaW5pdGVkICYmIG1vZC5mZXRjaGVkICYmIG1hcC5pc0RlZmluZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW1hcC5wcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vTm8gcmVhc29uIHRvIGtlZXAgbG9va2luZyBmb3IgdW5maW5pc2hlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9sb2FkaW5nLiBJZiB0aGUgb25seSBzdGlsbExvYWRpbmcgaXMgYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9wbHVnaW4gcmVzb3VyY2UgdGhvdWdoLCBrZWVwIGdvaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iZWNhdXNlIGl0IG1heSBiZSB0aGF0IGEgcGx1Z2luIHJlc291cmNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL2lzIHdhaXRpbmcgb24gYSBub24tcGx1Z2luIGN5Y2xlLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChuZWVkQ3ljbGVDaGVjayA9IGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CgogICAgICAgICAgICBpZiAoZXhwaXJlZCAmJiBub0xvYWRzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgLy9JZiB3YWl0IHRpbWUgZXhwaXJlZCwgdGhyb3cgZXJyb3Igb2YgdW5sb2FkZWQgbW9kdWxlcy4KICAgICAgICAgICAgICAgIGVyciA9IG1ha2VFcnJvcigndGltZW91dCcsICdMb2FkIHRpbWVvdXQgZm9yIG1vZHVsZXM6ICcgKyBub0xvYWRzLCBudWxsLCBub0xvYWRzKTsKICAgICAgICAgICAgICAgIGVyci5jb250ZXh0TmFtZSA9IGNvbnRleHQuY29udGV4dE5hbWU7CiAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihlcnIpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL05vdCBleHBpcmVkLCBjaGVjayBmb3IgYSBjeWNsZS4KICAgICAgICAgICAgaWYgKG5lZWRDeWNsZUNoZWNrKSB7CiAgICAgICAgICAgICAgICBlYWNoKHJlcUNhbGxzLCBmdW5jdGlvbiAobW9kKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWtDeWNsZShtb2QsIHt9LCB7fSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiBzdGlsbCB3YWl0aW5nIG9uIGxvYWRzLCBhbmQgdGhlIHdhaXRpbmcgbG9hZCBpcyBzb21ldGhpbmcKICAgICAgICAgICAgLy9vdGhlciB0aGFuIGEgcGx1Z2luIHJlc291cmNlLCBvciB0aGVyZSBhcmUgc3RpbGwgb3V0c3RhbmRpbmcKICAgICAgICAgICAgLy9zY3JpcHRzLCB0aGVuIGp1c3QgdHJ5IGJhY2sgbGF0ZXIuCiAgICAgICAgICAgIGlmICgoIWV4cGlyZWQgfHwgdXNpbmdQYXRoRmFsbGJhY2spICYmIHN0aWxsTG9hZGluZykgewogICAgICAgICAgICAgICAgLy9Tb21ldGhpbmcgaXMgc3RpbGwgd2FpdGluZyB0byBsb2FkLiBXYWl0IGZvciBpdCwgYnV0IG9ubHkKICAgICAgICAgICAgICAgIC8vaWYgYSB0aW1lb3V0IGlzIG5vdCBhbHJlYWR5IGluIGVmZmVjdC4KICAgICAgICAgICAgICAgIGlmICgoaXNCcm93c2VyIHx8IGlzV2ViV29ya2VyKSAmJiAhY2hlY2tMb2FkZWRUaW1lb3V0SWQpIHsKICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrTG9hZGVkKCk7CiAgICAgICAgICAgICAgICAgICAgfSwgNTApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBpbkNoZWNrTG9hZGVkID0gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICBNb2R1bGUgPSBmdW5jdGlvbiAobWFwKSB7CiAgICAgICAgICAgIHRoaXMuZXZlbnRzID0gZ2V0T3duKHVuZGVmRXZlbnRzLCBtYXAuaWQpIHx8IHt9OwogICAgICAgICAgICB0aGlzLm1hcCA9IG1hcDsKICAgICAgICAgICAgdGhpcy5zaGltID0gZ2V0T3duKGNvbmZpZy5zaGltLCBtYXAuaWQpOwogICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHMgPSBbXTsKICAgICAgICAgICAgdGhpcy5kZXBNYXBzID0gW107CiAgICAgICAgICAgIHRoaXMuZGVwTWF0Y2hlZCA9IFtdOwogICAgICAgICAgICB0aGlzLnBsdWdpbk1hcHMgPSB7fTsKICAgICAgICAgICAgdGhpcy5kZXBDb3VudCA9IDA7CgogICAgICAgICAgICAvKiB0aGlzLmV4cG9ydHMgdGhpcy5mYWN0b3J5CiAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcyA9IFtdLAogICAgICAgICAgICAgICB0aGlzLmVuYWJsZWQsIHRoaXMuZmV0Y2hlZAogICAgICAgICAgICAqLwogICAgICAgIH07CgogICAgICAgIE1vZHVsZS5wcm90b3R5cGUgPSB7CiAgICAgICAgICAgIGluaXQ6IGZ1bmN0aW9uIChkZXBNYXBzLCBmYWN0b3J5LCBlcnJiYWNrLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIG5vdCBkbyBtb3JlIGluaXRzIGlmIGFscmVhZHkgZG9uZS4gQ2FuIGhhcHBlbiBpZiB0aGVyZQogICAgICAgICAgICAgICAgLy9hcmUgbXVsdGlwbGUgZGVmaW5lIGNhbGxzIGZvciB0aGUgc2FtZSBtb2R1bGUuIFRoYXQgaXMgbm90CiAgICAgICAgICAgICAgICAvL2Egbm9ybWFsLCBjb21tb24gY2FzZSwgYnV0IGl0IGlzIGFsc28gbm90IHVuZXhwZWN0ZWQuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgdGhpcy5mYWN0b3J5ID0gZmFjdG9yeTsKCiAgICAgICAgICAgICAgICBpZiAoZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgIC8vUmVnaXN0ZXIgZm9yIGVycm9ycyBvbiB0aGlzIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLm9uKCdlcnJvcicsIGVycmJhY2spOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgIC8vSWYgbm8gZXJyYmFjayBhbHJlYWR5LCBidXQgdGhlcmUgYXJlIGVycm9yIGxpc3RlbmVycwogICAgICAgICAgICAgICAgICAgIC8vb24gdGhpcyBtb2R1bGUsIHNldCB1cCBhbiBlcnJiYWNrIHRvIHBhc3MgdG8gdGhlIGRlcHMuCiAgICAgICAgICAgICAgICAgICAgZXJyYmFjayA9IGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0RvIGEgY29weSBvZiB0aGUgZGVwZW5kZW5jeSBhcnJheSwgc28gdGhhdAogICAgICAgICAgICAgICAgLy9zb3VyY2UgaW5wdXRzIGFyZSBub3QgbW9kaWZpZWQuIEZvciBleGFtcGxlCiAgICAgICAgICAgICAgICAvLyJzaGltIiBkZXBzIGFyZSBwYXNzZWQgaW4gaGVyZSBkaXJlY3RseSwgYW5kCiAgICAgICAgICAgICAgICAvL2RvaW5nIGEgZGlyZWN0IG1vZGlmaWNhdGlvbiBvZiB0aGUgZGVwTWFwcyBhcnJheQogICAgICAgICAgICAgICAgLy93b3VsZCBhZmZlY3QgdGhhdCBjb25maWcuCiAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMgPSBkZXBNYXBzICYmIGRlcE1hcHMuc2xpY2UoMCk7CgogICAgICAgICAgICAgICAgdGhpcy5lcnJiYWNrID0gZXJyYmFjazsKCiAgICAgICAgICAgICAgICAvL0luZGljYXRlIHRoaXMgbW9kdWxlIGhhcyBiZSBpbml0aWFsaXplZAogICAgICAgICAgICAgICAgdGhpcy5pbml0ZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIHRoaXMuaWdub3JlID0gb3B0aW9ucy5pZ25vcmU7CgogICAgICAgICAgICAgICAgLy9Db3VsZCBoYXZlIG9wdGlvbiB0byBpbml0IHRoaXMgbW9kdWxlIGluIGVuYWJsZWQgbW9kZSwKICAgICAgICAgICAgICAgIC8vb3IgY291bGQgaGF2ZSBiZWVuIHByZXZpb3VzbHkgbWFya2VkIGFzIGVuYWJsZWQuIEhvd2V2ZXIsCiAgICAgICAgICAgICAgICAvL3RoZSBkZXBlbmRlbmNpZXMgYXJlIG5vdCBrbm93biB1bnRpbCBpbml0IGlzIGNhbGxlZC4gU28KICAgICAgICAgICAgICAgIC8vaWYgZW5hYmxlZCBwcmV2aW91c2x5LCBub3cgdHJpZ2dlciBkZXBlbmRlbmNpZXMgYXMgZW5hYmxlZC4KICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVuYWJsZWQgfHwgdGhpcy5lbmFibGVkKSB7CiAgICAgICAgICAgICAgICAgICAgLy9FbmFibGUgdGhpcyBtb2R1bGUgYW5kIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAvL1dpbGwgY2FsbCB0aGlzLmNoZWNrKCkKICAgICAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmNoZWNrKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBkZWZpbmVEZXA6IGZ1bmN0aW9uIChpLCBkZXBFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAvL0JlY2F1c2Ugb2YgY3ljbGVzLCBkZWZpbmVkIGNhbGxiYWNrIGZvciBhIGdpdmVuCiAgICAgICAgICAgICAgICAvL2V4cG9ydCBjYW4gYmUgY2FsbGVkIG1vcmUgdGhhbiBvbmNlLgogICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRlcE1hdGNoZWRbaV0pIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hdGNoZWRbaV0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwQ291bnQgLT0gMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHNbaV0gPSBkZXBFeHBvcnRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLmZldGNoZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0aGlzLmZldGNoZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIGNvbnRleHQuc3RhcnRUaW1lID0gKG5ldyBEYXRlKCkpLmdldFRpbWUoKTsKCiAgICAgICAgICAgICAgICB2YXIgbWFwID0gdGhpcy5tYXA7CgogICAgICAgICAgICAgICAgLy9JZiB0aGUgbWFuYWdlciBpcyBmb3IgYSBwbHVnaW4gbWFuYWdlZCByZXNvdXJjZSwKICAgICAgICAgICAgICAgIC8vYXNrIHRoZSBwbHVnaW4gdG8gbG9hZCBpdCBub3cuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5tYWtlUmVxdWlyZSh0aGlzLm1hcCwgewogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVCdWlsZENhbGxiYWNrOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgfSkodGhpcy5zaGltLmRlcHMgfHwgW10sIGJpbmQodGhpcywgZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgfSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL1JlZ3VsYXIgZGVwZW5kZW5jeS4KICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBsb2FkOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICB2YXIgdXJsID0gdGhpcy5tYXAudXJsOwoKICAgICAgICAgICAgICAgIC8vUmVndWxhciBkZXBlbmRlbmN5LgogICAgICAgICAgICAgICAgaWYgKCF1cmxGZXRjaGVkW3VybF0pIHsKICAgICAgICAgICAgICAgICAgICB1cmxGZXRjaGVkW3VybF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIGNvbnRleHQubG9hZCh0aGlzLm1hcC5pZCwgdXJsKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBDaGVja3MgaWYgdGhlIG1vZHVsZSBpcyByZWFkeSB0byBkZWZpbmUgaXRzZWxmLCBhbmQgaWYgc28sCiAgICAgICAgICAgICAqIGRlZmluZSBpdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNoZWNrOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZW5hYmxlZCB8fCB0aGlzLmVuYWJsaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHZhciBlcnIsIGNqc01vZHVsZSwKICAgICAgICAgICAgICAgICAgICBpZCA9IHRoaXMubWFwLmlkLAogICAgICAgICAgICAgICAgICAgIGRlcEV4cG9ydHMgPSB0aGlzLmRlcEV4cG9ydHMsCiAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0cywKICAgICAgICAgICAgICAgICAgICBmYWN0b3J5ID0gdGhpcy5mYWN0b3J5OwoKICAgICAgICAgICAgICAgIGlmICghdGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGZldGNoIGlmIG5vdCBhbHJlYWR5IGluIHRoZSBkZWZRdWV1ZS4KICAgICAgICAgICAgICAgICAgICBpZiAoIWhhc1Byb3AoY29udGV4dC5kZWZRdWV1ZU1hcCwgaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZmV0Y2goKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgdGhpcy5lcnJvcik7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLmRlZmluaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgLy9UaGUgZmFjdG9yeSBjb3VsZCB0cmlnZ2VyIGFub3RoZXIgcmVxdWlyZSBjYWxsCiAgICAgICAgICAgICAgICAgICAgLy90aGF0IHdvdWxkIHJlc3VsdCBpbiBjaGVja2luZyB0aGlzIG1vZHVsZSB0bwogICAgICAgICAgICAgICAgICAgIC8vZGVmaW5lIGl0c2VsZiBhZ2Fpbi4gSWYgYWxyZWFkeSBpbiB0aGUgcHJvY2VzcwogICAgICAgICAgICAgICAgICAgIC8vb2YgZG9pbmcgdGhhdCwgc2tpcCB0aGlzIHdvcmsuCiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWZpbmluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlcENvdW50IDwgMSAmJiAhdGhpcy5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0Z1bmN0aW9uKGZhY3RvcnkpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjb250ZXh0LmV4ZWNDYihpZCwgZmFjdG9yeSwgZGVwRXhwb3J0cywgZXhwb3J0cyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyID0gZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGYXZvciByZXR1cm4gdmFsdWUgb3ZlciBleHBvcnRzLiBJZiBub2RlL2NqcyBpbiBwbGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlbiB3aWxsIG5vdCBoYXZlIGEgcmV0dXJuIHZhbHVlIGFueXdheS4gRmF2b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1vZHVsZS5leHBvcnRzIGFzc2lnbm1lbnQgb3ZlciBleHBvcnRzIG9iamVjdC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hcC5pc0RlZmluZSAmJiBleHBvcnRzID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjanNNb2R1bGUgPSB0aGlzLm1vZHVsZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2pzTW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjanNNb2R1bGUuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMudXNpbmdFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vZXhwb3J0cyBhbHJlYWR5IHNldCB0aGUgZGVmaW5lZCB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZXJlIGlzIGFuIGVycm9yIGxpc3RlbmVyLCBmYXZvciBwYXNzaW5nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdG8gdGhhdCBpbnN0ZWFkIG9mIHRocm93aW5nIGFuIGVycm9yLiBIb3dldmVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9ubHkgZG8gaXQgZm9yIGRlZmluZSgpJ2QgIG1vZHVsZXMuIHJlcXVpcmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBlcnJiYWNrcyBzaG91bGQgbm90IGJlIGNhbGxlZCBmb3IgZmFpbHVyZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGVpciBjYWxsYmFja3MgKCM2OTkpLiBIb3dldmVyIGlmIGEgZ2xvYmFsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb25FcnJvciBpcyBzZXQsIHVzZSB0aGF0LgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodGhpcy5ldmVudHMuZXJyb3IgJiYgdGhpcy5tYXAuaXNEZWZpbmUpIHx8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5vbkVycm9yICE9PSBkZWZhdWx0T25FcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1hcCA9IHRoaXMubWFwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1vZHVsZXMgPSB0aGlzLm1hcC5pc0RlZmluZSA/IFt0aGlzLm1hcC5pZF0gOiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZVR5cGUgPSB0aGlzLm1hcC5pc0RlZmluZSA/ICdkZWZpbmUnIDogJ3JlcXVpcmUnOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcigodGhpcy5lcnJvciA9IGVycikpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvZyB0aGUgZXJyb3IgZm9yIGRlYnVnZ2luZy4gSWYgcHJvbWlzZXMgY291bGQgYmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXNlZCwgdGhpcyB3b3VsZCBiZSBkaWZmZXJlbnQsIGJ1dCBtYWtpbmcgZG8uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBEbyBub3Qgd2FudCB0byBjb21wbGV0ZWx5IGxvc2UgdGhlIGVycm9yLiBXaGlsZSB0aGlzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpbGwgbWVzcyB1cCBwcm9jZXNzaW5nIGFuZCBsZWFkIHRvIHNpbWlsYXIgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcyBidWcgMTQ0MCwgaXQgYXQgbGVhc3Qgc3VyZmFjZXMgdGhlIGVycm9yLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIGxpdGVyYWwgdmFsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBmYWN0b3J5OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmV4cG9ydHMgPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubWFwLmlzRGVmaW5lICYmICF0aGlzLmlnbm9yZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmaW5lZFtpZF0gPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEub25SZXNvdXJjZUxvYWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzTG9hZE1hcHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNMb2FkTWFwcy5wdXNoKGRlcE1hcC5ub3JtYWxpemVkTWFwIHx8IGRlcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxLm9uUmVzb3VyY2VMb2FkKGNvbnRleHQsIHRoaXMubWFwLCByZXNMb2FkTWFwcyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQ2xlYW4gdXAKICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9GaW5pc2hlZCB0aGUgZGVmaW5lIHN0YWdlLiBBbGxvdyBjYWxsaW5nIGNoZWNrIGFnYWluCiAgICAgICAgICAgICAgICAgICAgLy90byBhbGxvdyBkZWZpbmUgbm90aWZpY2F0aW9ucyBiZWxvdyBpbiB0aGUgY2FzZSBvZiBhCiAgICAgICAgICAgICAgICAgICAgLy9jeWNsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluaW5nID0gZmFsc2U7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlZmluZWQgJiYgIXRoaXMuZGVmaW5lRW1pdHRlZCkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXR0ZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2RlZmluZWQnLCB0aGlzLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXRDb21wbGV0ZSA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGNhbGxQbHVnaW46IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHZhciBtYXAgPSB0aGlzLm1hcCwKICAgICAgICAgICAgICAgICAgICBpZCA9IG1hcC5pZCwKICAgICAgICAgICAgICAgICAgICAvL01hcCBhbHJlYWR5IG5vcm1hbGl6ZWQgdGhlIHByZWZpeC4KICAgICAgICAgICAgICAgICAgICBwbHVnaW5NYXAgPSBtYWtlTW9kdWxlTWFwKG1hcC5wcmVmaXgpOwoKICAgICAgICAgICAgICAgIC8vTWFyayB0aGlzIGFzIGEgZGVwZW5kZW5jeSBmb3IgdGhpcyBwbHVnaW4sIHNvIGl0CiAgICAgICAgICAgICAgICAvL2NhbiBiZSB0cmFjZWQgZm9yIGN5Y2xlcy4KICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcy5wdXNoKHBsdWdpbk1hcCk7CgogICAgICAgICAgICAgICAgb24ocGx1Z2luTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbikgewogICAgICAgICAgICAgICAgICAgIHZhciBsb2FkLCBub3JtYWxpemVkTWFwLCBub3JtYWxpemVkTW9kLAogICAgICAgICAgICAgICAgICAgICAgICBidW5kbGVJZCA9IGdldE93bihidW5kbGVzTWFwLCB0aGlzLm1hcC5pZCksCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSB0aGlzLm1hcC5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnROYW1lID0gdGhpcy5tYXAucGFyZW50TWFwID8gdGhpcy5tYXAucGFyZW50TWFwLm5hbWUgOiBudWxsLAogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKG1hcC5wYXJlbnRNYXAsIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZUJ1aWxkQ2FsbGJhY2s6IHRydWUKICAgICAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgICAgIC8vSWYgY3VycmVudCBtYXAgaXMgbm90IG5vcm1hbGl6ZWQsIHdhaXQgZm9yIHRoYXQKICAgICAgICAgICAgICAgICAgICAvL25vcm1hbGl6ZWQgbmFtZSB0byBsb2FkIGluc3RlYWQgb2YgY29udGludWluZy4KICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5tYXAudW5ub3JtYWxpemVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIHRoZSBJRCBpZiB0aGUgcGx1Z2luIGFsbG93cyBpdC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBsdWdpbi5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBwbHVnaW4ubm9ybWFsaXplKG5hbWUsIGZ1bmN0aW9uIChuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pIHx8ICcnOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL3ByZWZpeCBhbmQgbmFtZSBzaG91bGQgYWxyZWFkeSBiZSBub3JtYWxpemVkLCBubyBuZWVkCiAgICAgICAgICAgICAgICAgICAgICAgIC8vZm9yIGFwcGx5aW5nIG1hcCBjb25maWcgYWdhaW4gZWl0aGVyLgogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTWFwID0gbWFrZU1vZHVsZU1hcChtYXAucHJlZml4ICsgJyEnICsgbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXAucGFyZW50TWFwKTsKICAgICAgICAgICAgICAgICAgICAgICAgb24obm9ybWFsaXplZE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkZWZpbmVkJywgYmluZCh0aGlzLCBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hcC5ub3JtYWxpemVkTWFwID0gbm9ybWFsaXplZE1hcDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZTogdHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE1vZCA9IGdldE93bihyZWdpc3RyeSwgbm9ybWFsaXplZE1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkTW9kKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL01hcmsgdGhpcyBhcyBhIGRlcGVuZGVuY3kgZm9yIHRoaXMgcGx1Z2luLCBzbyBpdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9jYW4gYmUgdHJhY2VkIGZvciBjeWNsZXMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMucHVzaChub3JtYWxpemVkTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5ldmVudHMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLm9uKCdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0lmIGEgcGF0aHMgY29uZmlnLCB0aGVuIGp1c3QgbG9hZCB0aGF0IGZpbGUgaW5zdGVhZCB0bwogICAgICAgICAgICAgICAgICAgIC8vcmVzb2x2ZSB0aGUgcGx1Z2luLCBhcyBpdCBpcyBidWlsdCBpbnRvIHRoYXQgcGF0aHMgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWFwLnVybCA9IGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkKTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGxvYWQgPSBiaW5kKHRoaXMsIGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICBsb2FkLmVycm9yID0gYmluZCh0aGlzLCBmdW5jdGlvbiAoZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdGVkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycjsKICAgICAgICAgICAgICAgICAgICAgICAgZXJyLnJlcXVpcmVNb2R1bGVzID0gW2lkXTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vUmVtb3ZlIHRlbXAgdW5ub3JtYWxpemVkIG1vZHVsZXMgZm9yIHRoaXMgbW9kdWxlLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NpbmNlIHRoZXkgd2lsbCBuZXZlciBiZSByZXNvbHZlZCBvdGhlcndpc2Ugbm93LgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaWQuaW5kZXhPZihpZCArICdfdW5ub3JtYWxpemVkJykgPT09IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhblJlZ2lzdHJ5KG1vZC5tYXAuaWQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9BbGxvdyBwbHVnaW5zIHRvIGxvYWQgb3RoZXIgY29kZSB3aXRob3V0IGhhdmluZyB0byBrbm93IHRoZQogICAgICAgICAgICAgICAgICAgIC8vY29udGV4dCBvciBob3cgdG8gJ2NvbXBsZXRlJyB0aGUgbG9hZC4KICAgICAgICAgICAgICAgICAgICBsb2FkLmZyb21UZXh0ID0gYmluZCh0aGlzLCBmdW5jdGlvbiAodGV4dCwgdGV4dEFsdCkgewogICAgICAgICAgICAgICAgICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtb2R1bGVOYW1lID0gbWFwLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVNYXAgPSBtYWtlTW9kdWxlTWFwKG1vZHVsZU5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzSW50ZXJhY3RpdmUgPSB1c2VJbnRlcmFjdGl2ZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQXMgb2YgMi4xLjAsIHN1cHBvcnQganVzdCBwYXNzaW5nIHRoZSB0ZXh0LCB0byByZWluZm9yY2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9mcm9tVGV4dCBvbmx5IGJlaW5nIGNhbGxlZCBvbmNlIHBlciByZXNvdXJjZS4gU3RpbGwKICAgICAgICAgICAgICAgICAgICAgICAgLy9zdXBwb3J0IG9sZCBzdHlsZSBvZiBwYXNzaW5nIG1vZHVsZU5hbWUgYnV0IGRpc2NhcmQKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGF0IG1vZHVsZU5hbWUgaW4gZmF2b3Igb2YgdGhlIGludGVybmFsIHJlZi4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRleHRBbHQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQgPSB0ZXh0QWx0OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1R1cm4gb2ZmIGludGVyYWN0aXZlIHNjcmlwdCBtYXRjaGluZyBmb3IgSUUgZm9yIGFueSBkZWZpbmUKICAgICAgICAgICAgICAgICAgICAgICAgLy9jYWxscyBpbiB0aGUgdGV4dCwgdGhlbiB0dXJuIGl0IGJhY2sgb24gYXQgdGhlIGVuZC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0ludGVyYWN0aXZlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1ByaW1lIHRoZSBzeXN0ZW0gYnkgY3JlYXRpbmcgYSBtb2R1bGUgaW5zdGFuY2UgZm9yCiAgICAgICAgICAgICAgICAgICAgICAgIC8vaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGdldE1vZHVsZShtb2R1bGVNYXApOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9UcmFuc2ZlciBhbnkgY29uZmlnIHRvIHRoaXMgb3RoZXIgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzUHJvcChjb25maWcuY29uZmlnLCBpZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5jb25maWdbbW9kdWxlTmFtZV0gPSBjb25maWcuY29uZmlnW2lkXTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5leGVjKHRleHQpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ2Zyb210ZXh0ZXZhbCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdmcm9tVGV4dCBldmFsIGZvciAnICsgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcgZmFpbGVkOiAnICsgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2lkXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXJrIHRoaXMgYXMgYSBkZXBlbmRlbmN5IGZvciB0aGUgcGx1Z2luCiAgICAgICAgICAgICAgICAgICAgICAgIC8vcmVzb3VyY2UKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBNYXBzLnB1c2gobW9kdWxlTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3VwcG9ydCBhbm9ueW1vdXMgbW9kdWxlcy4KICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQobW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgdGhlIHZhbHVlIG9mIHRoYXQgbW9kdWxlIHRvIHRoZSB2YWx1ZSBmb3IgdGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvL3Jlc291cmNlIElELgogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUoW21vZHVsZU5hbWVdLCBsb2FkKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9Vc2UgcGFyZW50TmFtZSBoZXJlIHNpbmNlIHRoZSBwbHVnaW4ncyBuYW1lIGlzIG5vdCByZWxpYWJsZSwKICAgICAgICAgICAgICAgICAgICAvL2NvdWxkIGJlIHNvbWUgd2VpcmQgc3RyaW5nIHdpdGggbm8gcGF0aCB0aGF0IGFjdHVhbGx5IHdhbnRzIHRvCiAgICAgICAgICAgICAgICAgICAgLy9yZWZlcmVuY2UgdGhlIHBhcmVudE5hbWUncyBwYXRoLgogICAgICAgICAgICAgICAgICAgIHBsdWdpbi5sb2FkKG1hcC5uYW1lLCBsb2NhbFJlcXVpcmUsIGxvYWQsIGNvbmZpZyk7CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luTWFwc1twbHVnaW5NYXAuaWRdID0gcGx1Z2luTWFwOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZW5hYmxlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBlbmFibGVkUmVnaXN0cnlbdGhpcy5tYXAuaWRdID0gdGhpczsKICAgICAgICAgICAgICAgIHRoaXMuZW5hYmxlZCA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9TZXQgZmxhZyBtZW50aW9uaW5nIHRoYXQgdGhlIG1vZHVsZSBpcyBlbmFibGluZywKICAgICAgICAgICAgICAgIC8vc28gdGhhdCBpbW1lZGlhdGUgY2FsbHMgdG8gdGhlIGRlZmluZWQgY2FsbGJhY2tzCiAgICAgICAgICAgICAgICAvL2ZvciBkZXBlbmRlbmNpZXMgZG8gbm90IHRyaWdnZXIgaW5hZHZlcnRlbnQgbG9hZAogICAgICAgICAgICAgICAgLy93aXRoIHRoZSBkZXBDb3VudCBzdGlsbCBiZWluZyB6ZXJvLgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9FbmFibGUgZWFjaCBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgYmluZCh0aGlzLCBmdW5jdGlvbiAoZGVwTWFwLCBpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIGlkLCBtb2QsIGhhbmRsZXI7CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwTWFwID09PSAnc3RyaW5nJykgewogICAgICAgICAgICAgICAgICAgICAgICAvL0RlcGVuZGVuY3kgbmVlZHMgdG8gYmUgY29udmVydGVkIHRvIGEgZGVwTWFwCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYW5kIHdpcmVkIHVwIHRvIHRoaXMgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBkZXBNYXAgPSBtYWtlTW9kdWxlTWFwKGRlcE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5tYXAuaXNEZWZpbmUgPyB0aGlzLm1hcCA6IHRoaXMubWFwLnBhcmVudE1hcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIXRoaXMuc2tpcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwc1tpXSA9IGRlcE1hcDsKCiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZXIgPSBnZXRPd24oaGFuZGxlcnMsIGRlcE1hcC5pZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBFeHBvcnRzW2ldID0gaGFuZGxlcih0aGlzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBDb3VudCArPSAxOwoKICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKGRlcEV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnVuZGVmZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZURlcChpLCBkZXBFeHBvcnRzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZXJyb3InLCBiaW5kKHRoaXMsIHRoaXMuZXJyYmFjaykpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXZlbnRzLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBObyBkaXJlY3QgZXJyYmFjayBvbiB0aGlzIG1vZHVsZSwgYnV0IHNvbWV0aGluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWxzZSBpcyBsaXN0ZW5pbmcgZm9yIGVycm9ycywgc28gYmUgc3VyZSB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJvcGFnYXRlIHRoZSBlcnJvciBjb3JyZWN0bHkuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbihkZXBNYXAsICdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24oZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIGVycik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlkID0gZGVwTWFwLmlkOwogICAgICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXTsKCiAgICAgICAgICAgICAgICAgICAgLy9Ta2lwIHNwZWNpYWwgbW9kdWxlcyBsaWtlICdyZXF1aXJlJywgJ2V4cG9ydHMnLCAnbW9kdWxlJwogICAgICAgICAgICAgICAgICAgIC8vQWxzbywgZG9uJ3QgY2FsbCBlbmFibGUgaWYgaXQgaXMgYWxyZWFkeSBlbmFibGVkLAogICAgICAgICAgICAgICAgICAgIC8vaW1wb3J0YW50IGluIGNpcmN1bGFyIGRlcGVuZGVuY3kgY2FzZXMuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGhhbmRsZXJzLCBpZCkgJiYgbW9kICYmICFtb2QuZW5hYmxlZCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmVuYWJsZShkZXBNYXAsIHRoaXMpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pKTsKCiAgICAgICAgICAgICAgICAvL0VuYWJsZSBlYWNoIHBsdWdpbiB0aGF0IGlzIHVzZWQgaW4KICAgICAgICAgICAgICAgIC8vYSBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoUHJvcCh0aGlzLnBsdWdpbk1hcHMsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbk1hcCkgewogICAgICAgICAgICAgICAgICAgIHZhciBtb2QgPSBnZXRPd24ocmVnaXN0cnksIHBsdWdpbk1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCAmJiAhbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IGZhbHNlOwoKICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG9uOiBmdW5jdGlvbiAobmFtZSwgY2IpIHsKICAgICAgICAgICAgICAgIHZhciBjYnMgPSB0aGlzLmV2ZW50c1tuYW1lXTsKICAgICAgICAgICAgICAgIGlmICghY2JzKSB7CiAgICAgICAgICAgICAgICAgICAgY2JzID0gdGhpcy5ldmVudHNbbmFtZV0gPSBbXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNicy5wdXNoKGNiKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGVtaXQ6IGZ1bmN0aW9uIChuYW1lLCBldnQpIHsKICAgICAgICAgICAgICAgIGVhY2godGhpcy5ldmVudHNbbmFtZV0sIGZ1bmN0aW9uIChjYikgewogICAgICAgICAgICAgICAgICAgIGNiKGV2dCk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGlmIChuYW1lID09PSAnZXJyb3InKSB7CiAgICAgICAgICAgICAgICAgICAgLy9Ob3cgdGhhdCB0aGUgZXJyb3IgaGFuZGxlciB3YXMgdHJpZ2dlcmVkLCByZW1vdmUKICAgICAgICAgICAgICAgICAgICAvL3RoZSBsaXN0ZW5lcnMsIHNpbmNlIHRoaXMgYnJva2VuIE1vZHVsZSBpbnN0YW5jZQogICAgICAgICAgICAgICAgICAgIC8vY2FuIHN0YXkgYXJvdW5kIGZvciBhIHdoaWxlIGluIHRoZSByZWdpc3RyeS4KICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5ldmVudHNbbmFtZV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjYWxsR2V0TW9kdWxlKGFyZ3MpIHsKICAgICAgICAgICAgLy9Ta2lwIG1vZHVsZXMgYWxyZWFkeSBkZWZpbmVkLgogICAgICAgICAgICBpZiAoIWhhc1Byb3AoZGVmaW5lZCwgYXJnc1swXSkpIHsKICAgICAgICAgICAgICAgIGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKGFyZ3NbMF0sIG51bGwsIHRydWUpKS5pbml0KGFyZ3NbMV0sIGFyZ3NbMl0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihub2RlLCBmdW5jLCBuYW1lLCBpZU5hbWUpIHsKICAgICAgICAgICAgLy9GYXZvciBkZXRhY2hFdmVudCBiZWNhdXNlIG9mIElFOQogICAgICAgICAgICAvL2lzc3VlLCBzZWUgYXR0YWNoRXZlbnQvYWRkRXZlbnRMaXN0ZW5lciBjb21tZW50IGVsc2V3aGVyZQogICAgICAgICAgICAvL2luIHRoaXMgZmlsZS4KICAgICAgICAgICAgaWYgKG5vZGUuZGV0YWNoRXZlbnQgJiYgIWlzT3BlcmEpIHsKICAgICAgICAgICAgICAgIC8vUHJvYmFibHkgSUUuIElmIG5vdCBpdCB3aWxsIHRocm93IGFuIGVycm9yLCB3aGljaCB3aWxsIGJlCiAgICAgICAgICAgICAgICAvL3VzZWZ1bCB0byBrbm93LgogICAgICAgICAgICAgICAgaWYgKGllTmFtZSkgewogICAgICAgICAgICAgICAgICAgIG5vZGUuZGV0YWNoRXZlbnQoaWVOYW1lLCBmdW5jKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUucmVtb3ZlRXZlbnRMaXN0ZW5lcihuYW1lLCBmdW5jLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdpdmVuIGFuIGV2ZW50IGZyb20gYSBzY3JpcHQgbm9kZSwgZ2V0IHRoZSByZXF1aXJlanMgaW5mbyBmcm9tIGl0LAogICAgICAgICAqIGFuZCB0aGVuIHJlbW92ZXMgdGhlIGV2ZW50IGxpc3RlbmVycyBvbiB0aGUgbm9kZS4KICAgICAgICAgKiBAcGFyYW0ge0V2ZW50fSBldnQKICAgICAgICAgKiBAcmV0dXJucyB7T2JqZWN0fQogICAgICAgICAqLwogICAgICAgIGZ1bmN0aW9uIGdldFNjcmlwdERhdGEoZXZ0KSB7CiAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgLy9hbGwgb2xkIGJyb3dzZXJzIHdpbGwgYmUgc3VwcG9ydGVkLCBidXQgdGhpcyBvbmUgd2FzIGVhc3kgZW5vdWdoCiAgICAgICAgICAgIC8vdG8gc3VwcG9ydCBhbmQgc3RpbGwgbWFrZXMgc2Vuc2UuCiAgICAgICAgICAgIHZhciBub2RlID0gZXZ0LmN1cnJlbnRUYXJnZXQgfHwgZXZ0LnNyY0VsZW1lbnQ7CgogICAgICAgICAgICAvL1JlbW92ZSB0aGUgbGlzdGVuZXJzIG9uY2UgaGVyZS4KICAgICAgICAgICAgcmVtb3ZlTGlzdGVuZXIobm9kZSwgY29udGV4dC5vblNjcmlwdExvYWQsICdsb2FkJywgJ29ucmVhZHlzdGF0ZWNoYW5nZScpOwogICAgICAgICAgICByZW1vdmVMaXN0ZW5lcihub2RlLCBjb250ZXh0Lm9uU2NyaXB0RXJyb3IsICdlcnJvcicpOwoKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIG5vZGU6IG5vZGUsCiAgICAgICAgICAgICAgICBpZDogbm9kZSAmJiBub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJykKICAgICAgICAgICAgfTsKICAgICAgICB9CgogICAgICAgIGZ1bmN0aW9uIGludGFrZURlZmluZXMoKSB7CiAgICAgICAgICAgIHZhciBhcmdzOwoKICAgICAgICAgICAgLy9BbnkgZGVmaW5lZCBtb2R1bGVzIGluIHRoZSBnbG9iYWwgcXVldWUsIGludGFrZSB0aGVtIG5vdy4KICAgICAgICAgICAgdGFrZUdsb2JhbFF1ZXVlKCk7CgogICAgICAgICAgICAvL01ha2Ugc3VyZSBhbnkgcmVtYWluaW5nIGRlZlF1ZXVlIGl0ZW1zIGdldCBwcm9wZXJseSBwcm9jZXNzZWQuCiAgICAgICAgICAgIHdoaWxlIChkZWZRdWV1ZS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGFyZ3MgPSBkZWZRdWV1ZS5zaGlmdCgpOwogICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ21pc21hdGNoJywgJ01pc21hdGNoZWQgYW5vbnltb3VzIGRlZmluZSgpIG1vZHVsZTogJyArCiAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3NbYXJncy5sZW5ndGggLSAxXSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL2FyZ3MgYXJlIGlkLCBkZXBzLCBmYWN0b3J5LiBTaG91bGQgYmUgbm9ybWFsaXplZCBieSB0aGUKICAgICAgICAgICAgICAgICAgICAvL2RlZmluZSgpIGZ1bmN0aW9uLgogICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoYXJncyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcCA9IHt9OwogICAgICAgIH0KCiAgICAgICAgY29udGV4dCA9IHsKICAgICAgICAgICAgY29uZmlnOiBjb25maWcsCiAgICAgICAgICAgIGNvbnRleHROYW1lOiBjb250ZXh0TmFtZSwKICAgICAgICAgICAgcmVnaXN0cnk6IHJlZ2lzdHJ5LAogICAgICAgICAgICBkZWZpbmVkOiBkZWZpbmVkLAogICAgICAgICAgICB1cmxGZXRjaGVkOiB1cmxGZXRjaGVkLAogICAgICAgICAgICBkZWZRdWV1ZTogZGVmUXVldWUsCiAgICAgICAgICAgIGRlZlF1ZXVlTWFwOiB7fSwKICAgICAgICAgICAgTW9kdWxlOiBNb2R1bGUsCiAgICAgICAgICAgIG1ha2VNb2R1bGVNYXA6IG1ha2VNb2R1bGVNYXAsCiAgICAgICAgICAgIG5leHRUaWNrOiByZXEubmV4dFRpY2ssCiAgICAgICAgICAgIG9uRXJyb3I6IG9uRXJyb3IsCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogU2V0IGEgY29uZmlndXJhdGlvbiBmb3IgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgY29uZmlnIG9iamVjdCB0byBpbnRlZ3JhdGUuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBjb25maWd1cmU6IGZ1bmN0aW9uIChjZmcpIHsKICAgICAgICAgICAgICAgIC8vTWFrZSBzdXJlIHRoZSBiYXNlVXJsIGVuZHMgaW4gYSBzbGFzaC4KICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybC5jaGFyQXQoY2ZnLmJhc2VVcmwubGVuZ3RoIC0gMSkgIT09ICcvJykgewogICAgICAgICAgICAgICAgICAgICAgICBjZmcuYmFzZVVybCArPSAnLyc7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vU2F2ZSBvZmYgdGhlIHBhdGhzIHNpbmNlIHRoZXkgcmVxdWlyZSBzcGVjaWFsIHByb2Nlc3NpbmcsCiAgICAgICAgICAgICAgICAvL3RoZXkgYXJlIGFkZGl0aXZlLgogICAgICAgICAgICAgICAgdmFyIHNoaW0gPSBjb25maWcuc2hpbSwKICAgICAgICAgICAgICAgICAgICBvYmpzID0gewogICAgICAgICAgICAgICAgICAgICAgICBwYXRoczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnOiB0cnVlLAogICAgICAgICAgICAgICAgICAgICAgICBtYXA6IHRydWUKICAgICAgICAgICAgICAgICAgICB9OwoKICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZywgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG9ianNbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjb25maWdbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHt9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIG1peGluKGNvbmZpZ1twcm9wXSwgdmFsdWUsIHRydWUsIHRydWUpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHZhbHVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIC8vUmV2ZXJzZSBtYXAgdGhlIGJ1bmRsZXMKICAgICAgICAgICAgICAgIGlmIChjZmcuYnVuZGxlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZy5idW5kbGVzLCBmdW5jdGlvbiAodmFsdWUsIHByb3ApIHsKICAgICAgICAgICAgICAgICAgICAgICAgZWFjaCh2YWx1ZSwgZnVuY3Rpb24gKHYpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2ICE9PSBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlc01hcFt2XSA9IHByb3A7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vTWVyZ2Ugc2hpbQogICAgICAgICAgICAgICAgaWYgKGNmZy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgZWFjaFByb3AoY2ZnLnNoaW0sIGZ1bmN0aW9uICh2YWx1ZSwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9Ob3JtYWxpemUgdGhlIHN0cnVjdHVyZQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlcHM6IHZhbHVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodmFsdWUuZXhwb3J0cyB8fCB2YWx1ZS5pbml0KSAmJiAhdmFsdWUuZXhwb3J0c0ZuKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5leHBvcnRzRm4gPSBjb250ZXh0Lm1ha2VTaGltRXhwb3J0cyh2YWx1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgc2hpbVtpZF0gPSB2YWx1ZTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICBjb25maWcuc2hpbSA9IHNoaW07CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgLy9BZGp1c3QgcGFja2FnZXMgaWYgbmVjZXNzYXJ5LgogICAgICAgICAgICAgICAgaWYgKGNmZy5wYWNrYWdlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2goY2ZnLnBhY2thZ2VzLCBmdW5jdGlvbiAocGtnT2JqKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsb2NhdGlvbiwgbmFtZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHBrZ09iaiA9IHR5cGVvZiBwa2dPYmogPT09ICdzdHJpbmcnID8ge25hbWU6IHBrZ09ian0gOiBwa2dPYmo7CgogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gcGtnT2JqLm5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gcGtnT2JqLmxvY2F0aW9uOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9jYXRpb24pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5wYXRoc1tuYW1lXSA9IHBrZ09iai5sb2NhdGlvbjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TYXZlIHBvaW50ZXIgdG8gbWFpbiBtb2R1bGUgSUQgZm9yIHBrZyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAvL1JlbW92ZSBsZWFkaW5nIGRvdCBpbiBtYWluLCBzbyBtYWluIHBhdGhzIGFyZSBub3JtYWxpemVkLAogICAgICAgICAgICAgICAgICAgICAgICAvL2FuZCByZW1vdmUgYW55IHRyYWlsaW5nIC5qcywgc2luY2UgZGlmZmVyZW50IHBhY2thZ2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9lbnZzIGhhdmUgZGlmZmVyZW50IGNvbnZlbnRpb25zOiBzb21lIHVzZSBhIG1vZHVsZSBuYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NvbWUgdXNlIGEgZmlsZSBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICBjb25maWcucGtnc1tuYW1lXSA9IHBrZ09iai5uYW1lICsgJy8nICsgKHBrZ09iai5tYWluIHx8ICdtYWluJykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKGN1cnJEaXJSZWdFeHAsICcnKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0lmIHRoZXJlIGFyZSBhbnkgIndhaXRpbmcgdG8gZXhlY3V0ZSIgbW9kdWxlcyBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAvL3VwZGF0ZSB0aGUgbWFwcyBmb3IgdGhlbSwgc2luY2UgdGhlaXIgaW5mbywgbGlrZSBVUkxzIHRvIGxvYWQsCiAgICAgICAgICAgICAgICAvL21heSBoYXZlIGNoYW5nZWQuCiAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIG1vZHVsZSBhbHJlYWR5IGhhcyBpbml0IGNhbGxlZCwgc2luY2UgaXQgaXMgdG9vCiAgICAgICAgICAgICAgICAgICAgLy9sYXRlIHRvIG1vZGlmeSB0aGVtLCBhbmQgaWdub3JlIHVubm9ybWFsaXplZCBvbmVzCiAgICAgICAgICAgICAgICAgICAgLy9zaW5jZSB0aGV5IGFyZSB0cmFuc2llbnQuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFtb2QuaW5pdGVkICYmICFtb2QubWFwLnVubm9ybWFsaXplZCkgewogICAgICAgICAgICAgICAgICAgICAgICBtb2QubWFwID0gbWFrZU1vZHVsZU1hcChpZCwgbnVsbCwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9JZiBhIGRlcHMgYXJyYXkgb3IgYSBjb25maWcgY2FsbGJhY2sgaXMgc3BlY2lmaWVkLCB0aGVuIGNhbGwKICAgICAgICAgICAgICAgIC8vcmVxdWlyZSB3aXRoIHRob3NlIGFyZ3MuIFRoaXMgaXMgdXNlZnVsIHdoZW4gcmVxdWlyZSBpcyBkZWZpbmVkIGFzIGEKICAgICAgICAgICAgICAgIC8vY29uZmlnIG9iamVjdCBiZWZvcmUgcmVxdWlyZS5qcyBpcyBsb2FkZWQuCiAgICAgICAgICAgICAgICBpZiAoY2ZnLmRlcHMgfHwgY2ZnLmNhbGxiYWNrKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlKGNmZy5kZXBzIHx8IFtdLCBjZmcuY2FsbGJhY2spOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgbWFrZVNoaW1FeHBvcnRzOiBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgIGZ1bmN0aW9uIGZuKCkgewogICAgICAgICAgICAgICAgICAgIHZhciByZXQ7CiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlLmluaXQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0ID0gdmFsdWUuaW5pdC5hcHBseShnbG9iYWwsIGFyZ3VtZW50cyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIHJldHVybiByZXQgfHwgKHZhbHVlLmV4cG9ydHMgJiYgZ2V0R2xvYmFsKHZhbHVlLmV4cG9ydHMpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBmbjsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG1ha2VSZXF1aXJlOiBmdW5jdGlvbiAocmVsTWFwLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICBmdW5jdGlvbiBsb2NhbFJlcXVpcmUoZGVwcywgY2FsbGJhY2ssIGVycmJhY2spIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQsIG1hcCwgcmVxdWlyZU1vZDsKCiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZW5hYmxlQnVpbGRDYWxsYmFjayAmJiBjYWxsYmFjayAmJiBpc0Z1bmN0aW9uKGNhbGxiYWNrKSkgewogICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjay5fX3JlcXVpcmVKc0J1aWxkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwcyA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzRnVuY3Rpb24oY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0ludmFsaWQgY2FsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdyZXF1aXJlYXJncycsICdJbnZhbGlkIHJlcXVpcmUgY2FsbCcpLCBlcnJiYWNrKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiByZXF1aXJlfGV4cG9ydHN8bW9kdWxlIGFyZSByZXF1ZXN0ZWQsIGdldCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy92YWx1ZSBmb3IgdGhlbSBmcm9tIHRoZSBzcGVjaWFsIGhhbmRsZXJzLiBDYXZlYXQ6CiAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBvbmx5IHdvcmtzIHdoaWxlIG1vZHVsZSBpcyBiZWluZyBkZWZpbmVkLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVsTWFwICYmIGhhc1Byb3AoaGFuZGxlcnMsIGRlcHMpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlcnNbZGVwc10ocmVnaXN0cnlbcmVsTWFwLmlkXSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3luY2hyb25vdXMgYWNjZXNzIHRvIG9uZSBtb2R1bGUuIElmIHJlcXVpcmUuZ2V0IGlzCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYXZhaWxhYmxlIChhcyBpbiB0aGUgTm9kZSBhZGFwdGVyKSwgcHJlZmVyIHRoYXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEuZ2V0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVxLmdldChjb250ZXh0LCBkZXBzLCByZWxNYXAsIGxvY2FsUmVxdWlyZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIG1vZHVsZSBuYW1lLCBpZiBpdCBjb250YWlucyAuIG9yIC4uCiAgICAgICAgICAgICAgICAgICAgICAgIG1hcCA9IG1ha2VNb2R1bGVNYXAoZGVwcywgcmVsTWFwLCBmYWxzZSwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFwLmlkOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGRlZmluZWQsIGlkKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub3Rsb2FkZWQnLCAnTW9kdWxlIG5hbWUgIicgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIgaGFzIG5vdCBiZWVuIGxvYWRlZCB5ZXQgZm9yIGNvbnRleHQ6ICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dE5hbWUgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlbE1hcCA/ICcnIDogJy4gVXNlIHJlcXVpcmUoW10pJykpKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0dyYWIgZGVmaW5lcyB3YWl0aW5nIGluIHRoZSBnbG9iYWwgcXVldWUuCiAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAvL01hcmsgYWxsIHRoZSBkZXBlbmRlbmNpZXMgYXMgbmVlZGluZyB0byBiZSBsb2FkZWQuCiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5uZXh0VGljayhmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vU29tZSBkZWZpbmVzIGNvdWxkIGhhdmUgYmVlbiBhZGRlZCBzaW5jZSB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9yZXF1aXJlIGNhbGwsIGNvbGxlY3QgdGhlbS4KICAgICAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZCA9IGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKG51bGwsIHJlbE1hcCkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TdG9yZSBpZiBtYXAgY29uZmlnIHNob3VsZCBiZSBhcHBsaWVkIHRvIHRoaXMgcmVxdWlyZQogICAgICAgICAgICAgICAgICAgICAgICAvL2NhbGwgZm9yIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5za2lwTWFwID0gb3B0aW9ucy5za2lwTWFwOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5pbml0KGRlcHMsIGNhbGxiYWNrLCBlcnJiYWNrLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tMb2FkZWQoKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsUmVxdWlyZTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBtaXhpbihsb2NhbFJlcXVpcmUsIHsKICAgICAgICAgICAgICAgICAgICBpc0Jyb3dzZXI6IGlzQnJvd3NlciwKCiAgICAgICAgICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAgICAgICAgICogQ29udmVydHMgYSBtb2R1bGUgbmFtZSArIC5leHRlbnNpb24gaW50byBhbiBVUkwgcGF0aC4KICAgICAgICAgICAgICAgICAgICAgKiAqUmVxdWlyZXMqIHRoZSB1c2Ugb2YgYSBtb2R1bGUgbmFtZS4gSXQgZG9lcyBub3Qgc3VwcG9ydCB1c2luZwogICAgICAgICAgICAgICAgICAgICAqIHBsYWluIFVSTHMgbGlrZSBuYW1lVG9VcmwuCiAgICAgICAgICAgICAgICAgICAgICovCiAgICAgICAgICAgICAgICAgICAgdG9Vcmw6IGZ1bmN0aW9uIChtb2R1bGVOYW1lUGx1c0V4dCkgewogICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBtb2R1bGVOYW1lUGx1c0V4dC5sYXN0SW5kZXhPZignLicpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudCA9IG1vZHVsZU5hbWVQbHVzRXh0LnNwbGl0KCcvJylbMF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1JlbGF0aXZlID0gc2VnbWVudCA9PT0gJy4nIHx8IHNlZ21lbnQgPT09ICcuLic7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0hhdmUgYSBmaWxlIGV4dGVuc2lvbiBhbGlhcywgYW5kIGl0IGlzIG5vdCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9kb3RzIGZyb20gYSByZWxhdGl2ZSBwYXRoLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5kZXggIT09IC0xICYmICghaXNSZWxhdGl2ZSB8fCBpbmRleCA+IDEpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHQgPSBtb2R1bGVOYW1lUGx1c0V4dC5zdWJzdHJpbmcoaW5kZXgsIG1vZHVsZU5hbWVQbHVzRXh0Lmxlbmd0aCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lUGx1c0V4dCA9IG1vZHVsZU5hbWVQbHVzRXh0LnN1YnN0cmluZygwLCBpbmRleCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb250ZXh0Lm5hbWVUb1VybChub3JtYWxpemUobW9kdWxlTmFtZVBsdXNFeHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbE1hcCAmJiByZWxNYXAuaWQsIHRydWUpLCBleHQsICB0cnVlKTsKICAgICAgICAgICAgICAgICAgICB9LAoKICAgICAgICAgICAgICAgICAgICBkZWZpbmVkOiBmdW5jdGlvbiAoaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGhhc1Byb3AoZGVmaW5lZCwgbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQpOwogICAgICAgICAgICAgICAgICAgIH0sCgogICAgICAgICAgICAgICAgICAgIHNwZWNpZmllZDogZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQ7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBoYXNQcm9wKGRlZmluZWQsIGlkKSB8fCBoYXNQcm9wKHJlZ2lzdHJ5LCBpZCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9Pbmx5IGFsbG93IHVuZGVmIG9uIHRvcCBsZXZlbCByZXF1aXJlIGNhbGxzCiAgICAgICAgICAgICAgICBpZiAoIXJlbE1hcCkgewogICAgICAgICAgICAgICAgICAgIGxvY2FsUmVxdWlyZS51bmRlZiA9IGZ1bmN0aW9uIChpZCkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgYW55IHdhaXRpbmcgZGVmaW5lKCkgY2FsbHMgdG8gdGhpcyBjb250ZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAvL2ZpeCBmb3IgIzQwOAogICAgICAgICAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtYXAgPSBtYWtlTW9kdWxlTWFwKGlkLCByZWxNYXAsIHRydWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kID0gZ2V0T3duKHJlZ2lzdHJ5LCBpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBtb2QudW5kZWZlZCA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB1cmxGZXRjaGVkW21hcC51cmxdOwogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgdW5kZWZFdmVudHNbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9DbGVhbiBxdWV1ZWQgZGVmaW5lcyB0b28uIEdvIGJhY2t3YXJkcwogICAgICAgICAgICAgICAgICAgICAgICAvL2luIGFycmF5IHNvIHRoYXQgdGhlIHNwbGljZXMgZG8gbm90CiAgICAgICAgICAgICAgICAgICAgICAgIC8vbWVzcyB1cCB0aGUgaXRlcmF0aW9uLgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUmV2ZXJzZShkZWZRdWV1ZSwgZnVuY3Rpb24oYXJncywgaSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmUXVldWUuc3BsaWNlKGksIDEpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIGNvbnRleHQuZGVmUXVldWVNYXBbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9Ib2xkIG9uIHRvIGxpc3RlbmVycyBpbiBjYXNlIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9tb2R1bGUgd2lsbCBiZSBhdHRlbXB0ZWQgdG8gYmUgcmVsb2FkZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdXNpbmcgYSBkaWZmZXJlbnQgY29uZmlnLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5ldmVudHMuZGVmaW5lZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVmRXZlbnRzW2lkXSA9IG1vZC5ldmVudHM7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbFJlcXVpcmU7CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGVkIHRvIGVuYWJsZSBhIG1vZHVsZSBpZiBpdCBpcyBzdGlsbCBpbiB0aGUgcmVnaXN0cnkKICAgICAgICAgICAgICogYXdhaXRpbmcgZW5hYmxlbWVudC4gQSBzZWNvbmQgYXJnLCBwYXJlbnQsIHRoZSBwYXJlbnQgbW9kdWxlLAogICAgICAgICAgICAgKiBpcyBwYXNzZWQgaW4gZm9yIGNvbnRleHQsIHdoZW4gdGhpcyBtZXRob2QgaXMgb3ZlcnJpZGRlbiBieQogICAgICAgICAgICAgKiB0aGUgb3B0aW1pemVyLiBOb3Qgc2hvd24gaGVyZSB0byBrZWVwIGNvZGUgY29tcGFjdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGVuYWJsZTogZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgZGVwTWFwLmlkKTsKICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICBnZXRNb2R1bGUoZGVwTWFwKS5lbmFibGUoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdXNlZCBieSBlbnZpcm9ubWVudCBhZGFwdGVycyB0byBjb21wbGV0ZSBhIGxvYWQgZXZlbnQuCiAgICAgICAgICAgICAqIEEgbG9hZCBldmVudCBjb3VsZCBiZSBhIHNjcmlwdCBsb2FkIG9yIGp1c3QgYSBsb2FkIHBhc3MgZnJvbSBhIHN5bmNocm9ub3VzCiAgICAgICAgICAgICAqIGxvYWQgY2FsbC4KICAgICAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSB0byBwb3RlbnRpYWxseSBjb21wbGV0ZS4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNvbXBsZXRlTG9hZDogZnVuY3Rpb24gKG1vZHVsZU5hbWUpIHsKICAgICAgICAgICAgICAgIHZhciBmb3VuZCwgYXJncywgbW9kLAogICAgICAgICAgICAgICAgICAgIHNoaW0gPSBnZXRPd24oY29uZmlnLnNoaW0sIG1vZHVsZU5hbWUpIHx8IHt9LAogICAgICAgICAgICAgICAgICAgIHNoRXhwb3J0cyA9IHNoaW0uZXhwb3J0czsKCiAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICB3aGlsZSAoZGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgYXJncyA9IGRlZlF1ZXVlLnNoaWZ0KCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgYXJnc1swXSA9IG1vZHVsZU5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vSWYgYWxyZWFkeSBmb3VuZCBhbiBhbm9ueW1vdXMgbW9kdWxlIGFuZCBib3VuZCBpdAogICAgICAgICAgICAgICAgICAgICAgICAvL3RvIHRoaXMgbmFtZSwgdGhlbiB0aGlzIGlzIHNvbWUgb3RoZXIgYW5vbiBtb2R1bGUKICAgICAgICAgICAgICAgICAgICAgICAgLy93YWl0aW5nIGZvciBpdHMgY29tcGxldGVMb2FkIHRvIGZpcmUuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmb3VuZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJnc1swXSA9PT0gbW9kdWxlTmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0ZvdW5kIG1hdGNoaW5nIGRlZmluZSBjYWxsIGZvciB0aGlzIHNjcmlwdCEKICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgY2FsbEdldE1vZHVsZShhcmdzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQuZGVmUXVldWVNYXAgPSB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIHRoaXMgYWZ0ZXIgdGhlIGN5Y2xlIG9mIGNhbGxHZXRNb2R1bGUgaW4gY2FzZSB0aGUgcmVzdWx0CiAgICAgICAgICAgICAgICAvL29mIHRob3NlIGNhbGxzL2luaXQgY2FsbHMgY2hhbmdlcyB0aGUgcmVnaXN0cnkuCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmICghZm91bmQgJiYgIWhhc1Byb3AoZGVmaW5lZCwgbW9kdWxlTmFtZSkgJiYgbW9kICYmICFtb2QuaW5pdGVkKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbmZpZy5lbmZvcmNlRGVmaW5lICYmICghc2hFeHBvcnRzIHx8ICFnZXRHbG9iYWwoc2hFeHBvcnRzKSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc1BhdGhGYWxsYmFjayhtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub2RlZmluZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdObyBkZWZpbmUgY2FsbCBmb3IgJyArIG1vZHVsZU5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFttb2R1bGVOYW1lXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9BIHNjcmlwdCB0aGF0IGRvZXMgbm90IGNhbGwgZGVmaW5lKCksIHNvIGp1c3Qgc2ltdWxhdGUKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGUgY2FsbCBmb3IgaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoW21vZHVsZU5hbWUsIChzaGltLmRlcHMgfHwgW10pLCBzaGltLmV4cG9ydHNGbl0pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBjaGVja0xvYWRlZCgpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIENvbnZlcnRzIGEgbW9kdWxlIG5hbWUgdG8gYSBmaWxlIHBhdGguIFN1cHBvcnRzIGNhc2VzIHdoZXJlCiAgICAgICAgICAgICAqIG1vZHVsZU5hbWUgbWF5IGFjdHVhbGx5IGJlIGp1c3QgYW4gVVJMLgogICAgICAgICAgICAgKiBOb3RlIHRoYXQgaXQgKipkb2VzIG5vdCoqIGNhbGwgbm9ybWFsaXplIG9uIHRoZSBtb2R1bGVOYW1lLAogICAgICAgICAgICAgKiBpdCBpcyBhc3N1bWVkIHRvIGhhdmUgYWxyZWFkeSBiZWVuIG5vcm1hbGl6ZWQuIFRoaXMgaXMgYW4KICAgICAgICAgICAgICogaW50ZXJuYWwgQVBJLCBub3QgYSBwdWJsaWMgb25lLiBVc2UgdG9VcmwgZm9yIHRoZSBwdWJsaWMgQVBJLgogICAgICAgICAgICAgKi8KICAgICAgICAgICAgbmFtZVRvVXJsOiBmdW5jdGlvbiAobW9kdWxlTmFtZSwgZXh0LCBza2lwRXh0KSB7CiAgICAgICAgICAgICAgICB2YXIgcGF0aHMsIHN5bXMsIGksIHBhcmVudE1vZHVsZSwgdXJsLAogICAgICAgICAgICAgICAgICAgIHBhcmVudFBhdGgsIGJ1bmRsZUlkLAogICAgICAgICAgICAgICAgICAgIHBrZ01haW4gPSBnZXRPd24oY29uZmlnLnBrZ3MsIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmIChwa2dNYWluKSB7CiAgICAgICAgICAgICAgICAgICAgbW9kdWxlTmFtZSA9IHBrZ01haW47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgYnVuZGxlSWQgPSBnZXRPd24oYnVuZGxlc01hcCwgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkLCBleHQsIHNraXBFeHQpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vSWYgYSBjb2xvbiBpcyBpbiB0aGUgVVJMLCBpdCBpbmRpY2F0ZXMgYSBwcm90b2NvbCBpcyB1c2VkIGFuZCBpdCBpcyBqdXN0CiAgICAgICAgICAgICAgICAvL2FuIFVSTCB0byBhIGZpbGUsIG9yIGlmIGl0IHN0YXJ0cyB3aXRoIGEgc2xhc2gsIGNvbnRhaW5zIGEgcXVlcnkgYXJnIChpLmUuID8pCiAgICAgICAgICAgICAgICAvL29yIGVuZHMgd2l0aCAuanMsIHRoZW4gYXNzdW1lIHRoZSB1c2VyIG1lYW50IHRvIHVzZSBhbiB1cmwgYW5kIG5vdCBhIG1vZHVsZSBpZC4KICAgICAgICAgICAgICAgIC8vVGhlIHNsYXNoIGlzIGltcG9ydGFudCBmb3IgcHJvdG9jb2wtbGVzcyBVUkxzIGFzIHdlbGwgYXMgZnVsbCBwYXRocy4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIHBsYWluIHBhdGgsIG5vdCBtb2R1bGUgbmFtZSBsb29rdXAsIHNvIGp1c3QgcmV0dXJuIGl0LgogICAgICAgICAgICAgICAgICAgIC8vQWRkIGV4dGVuc2lvbiBpZiBpdCBpcyBpbmNsdWRlZC4gVGhpcyBpcyBhIGJpdCB3b25reSwgb25seSBub24tLmpzIHRoaW5ncyBwYXNzCiAgICAgICAgICAgICAgICAgICAgLy9hbiBleHRlbnNpb24sIHRoaXMgbWV0aG9kIHByb2JhYmx5IG5lZWRzIHRvIGJlIHJld29ya2VkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IG1vZHVsZU5hbWUgKyAoZXh0IHx8ICcnKTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgLy9BIG1vZHVsZSB0aGF0IG5lZWRzIHRvIGJlIGNvbnZlcnRlZCB0byBhIHBhdGguCiAgICAgICAgICAgICAgICAgICAgcGF0aHMgPSBjb25maWcucGF0aHM7CgogICAgICAgICAgICAgICAgICAgIHN5bXMgPSBtb2R1bGVOYW1lLnNwbGl0KCcvJyk7CiAgICAgICAgICAgICAgICAgICAgLy9Gb3IgZWFjaCBtb2R1bGUgbmFtZSBzZWdtZW50LCBzZWUgaWYgdGhlcmUgaXMgYSBwYXRoCiAgICAgICAgICAgICAgICAgICAgLy9yZWdpc3RlcmVkIGZvciBpdC4gU3RhcnQgd2l0aCBtb3N0IHNwZWNpZmljIG5hbWUKICAgICAgICAgICAgICAgICAgICAvL2FuZCB3b3JrIHVwIGZyb20gaXQuCiAgICAgICAgICAgICAgICAgICAgZm9yIChpID0gc3ltcy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50TW9kdWxlID0gc3ltcy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gZ2V0T3duKHBhdGhzLCBwYXJlbnRNb2R1bGUpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAocGFyZW50UGF0aCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiBhbiBhcnJheSwgaXQgbWVhbnMgdGhlcmUgYXJlIGEgZmV3IGNob2ljZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0Nob29zZSB0aGUgb25lIHRoYXQgaXMgZGVzaXJlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzQXJyYXkocGFyZW50UGF0aCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gcGFyZW50UGF0aFswXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXMuc3BsaWNlKDAsIGksIHBhcmVudFBhdGgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIC8vSm9pbiB0aGUgcGF0aCBwYXJ0cyB0b2dldGhlciwgdGhlbiBmaWd1cmUgb3V0IGlmIGJhc2VVcmwgaXMgbmVlZGVkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IHN5bXMuam9pbignLycpOwogICAgICAgICAgICAgICAgICAgIHVybCArPSAoZXh0IHx8ICgvXmRhdGFcOnxcPy8udGVzdCh1cmwpIHx8IHNraXBFeHQgPyAnJyA6ICcuanMnKSk7CiAgICAgICAgICAgICAgICAgICAgdXJsID0gKHVybC5jaGFyQXQoMCkgPT09ICcvJyB8fCB1cmwubWF0Y2goL15bXHdcK1wuXC1dKzovKSA/ICcnIDogY29uZmlnLmJhc2VVcmwpICsgdXJsOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBjb25maWcudXJsQXJncyA/IHVybCArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKHVybC5pbmRleE9mKCc/JykgPT09IC0xID8gJz8nIDogJyYnKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLnVybEFyZ3MpIDogdXJsOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLy9EZWxlZ2F0ZXMgdG8gcmVxLmxvYWQuIEJyb2tlbiBvdXQgYXMgYSBzZXBhcmF0ZSBmdW5jdGlvbiB0bwogICAgICAgICAgICAvL2FsbG93IG92ZXJyaWRpbmcgaW4gdGhlIG9wdGltaXplci4KICAgICAgICAgICAgbG9hZDogZnVuY3Rpb24gKGlkLCB1cmwpIHsKICAgICAgICAgICAgICAgIHJlcS5sb2FkKGNvbnRleHQsIGlkLCB1cmwpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIEV4ZWN1dGVzIGEgbW9kdWxlIGNhbGxiYWNrIGZ1bmN0aW9uLiBCcm9rZW4gb3V0IGFzIGEgc2VwYXJhdGUgZnVuY3Rpb24KICAgICAgICAgICAgICogc29sZWx5IHRvIGFsbG93IHRoZSBidWlsZCBzeXN0ZW0gdG8gc2VxdWVuY2UgdGhlIGZpbGVzIGluIHRoZSBidWlsdAogICAgICAgICAgICAgKiBsYXllciBpbiB0aGUgcmlnaHQgc2VxdWVuY2UuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBleGVjQ2I6IGZ1bmN0aW9uIChuYW1lLCBjYWxsYmFjaywgYXJncywgZXhwb3J0cykgewogICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrLmFwcGx5KGV4cG9ydHMsIGFyZ3MpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIGNhbGxiYWNrIGZvciBzY3JpcHQgbG9hZHMsIHVzZWQgdG8gY2hlY2sgc3RhdHVzIG9mIGxvYWRpbmcuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2dCB0aGUgZXZlbnQgZnJvbSB0aGUgYnJvd3NlciBmb3IgdGhlIHNjcmlwdAogICAgICAgICAgICAgKiB0aGF0IHdhcyBsb2FkZWQuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdExvYWQ6IGZ1bmN0aW9uIChldnQpIHsKICAgICAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgICAgIC8vYWxsIG9sZCBicm93c2VycyB3aWxsIGJlIHN1cHBvcnRlZCwgYnV0IHRoaXMgb25lIHdhcyBlYXN5IGVub3VnaAogICAgICAgICAgICAgICAgLy90byBzdXBwb3J0IGFuZCBzdGlsbCBtYWtlcyBzZW5zZS4KICAgICAgICAgICAgICAgIGlmIChldnQudHlwZSA9PT0gJ2xvYWQnIHx8CiAgICAgICAgICAgICAgICAgICAgICAgIChyZWFkeVJlZ0V4cC50ZXN0KChldnQuY3VycmVudFRhcmdldCB8fCBldnQuc3JjRWxlbWVudCkucmVhZHlTdGF0ZSkpKSB7CiAgICAgICAgICAgICAgICAgICAgLy9SZXNldCBpbnRlcmFjdGl2ZSBzY3JpcHQgc28gYSBzY3JpcHQgbm9kZSBpcyBub3QgaGVsZCBvbnRvIGZvcgogICAgICAgICAgICAgICAgICAgIC8vdG8gbG9uZy4KICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCA9IG51bGw7CgogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvdXQgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSBhbmQgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBnZXRTY3JpcHREYXRhKGV2dCk7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQoZGF0YS5pZCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGJhY2sgZm9yIHNjcmlwdCBlcnJvcnMuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdEVycm9yOiBmdW5jdGlvbiAoZXZ0KSB7CiAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IGdldFNjcmlwdERhdGEoZXZ0KTsKICAgICAgICAgICAgICAgIGlmICghaGFzUGF0aEZhbGxiYWNrKGRhdGEuaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmVudHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24odmFsdWUsIGtleSkgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoa2V5LmluZGV4T2YoJ19AcicpICE9PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHZhbHVlLmRlcE1hcHMsIGZ1bmN0aW9uKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZXBNYXAuaWQgPT09IGRhdGEuaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50cy5wdXNoKGtleSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ3NjcmlwdGVycm9yJywgJ1NjcmlwdCBlcnJvciBmb3IgIicgKyBkYXRhLmlkICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhcmVudHMubGVuZ3RoID8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIsIG5lZWRlZCBieTogJyArIHBhcmVudHMuam9pbignLCAnKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICciJyksIGV2dCwgW2RhdGEuaWRdKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBjb250ZXh0LnJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKCk7CiAgICAgICAgcmV0dXJuIGNvbnRleHQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBNYWluIGVudHJ5IHBvaW50LgogICAgICoKICAgICAqIElmIHRoZSBvbmx5IGFyZ3VtZW50IHRvIHJlcXVpcmUgaXMgYSBzdHJpbmcsIHRoZW4gdGhlIG1vZHVsZSB0aGF0CiAgICAgKiBpcyByZXByZXNlbnRlZCBieSB0aGF0IHN0cmluZyBpcyBmZXRjaGVkIGZvciB0aGUgYXBwcm9wcmlhdGUgY29udGV4dC4KICAgICAqCiAgICAgKiBJZiB0aGUgZmlyc3QgYXJndW1lbnQgaXMgYW4gYXJyYXksIHRoZW4gaXQgd2lsbCBiZSB0cmVhdGVkIGFzIGFuIGFycmF5CiAgICAgKiBvZiBkZXBlbmRlbmN5IHN0cmluZyBuYW1lcyB0byBmZXRjaC4gQW4gb3B0aW9uYWwgZnVuY3Rpb24gY2FsbGJhY2sgY2FuCiAgICAgKiBiZSBzcGVjaWZpZWQgdG8gZXhlY3V0ZSB3aGVuIGFsbCBvZiB0aG9zZSBkZXBlbmRlbmNpZXMgYXJlIGF2YWlsYWJsZS4KICAgICAqCiAgICAgKiBNYWtlIGEgbG9jYWwgcmVxIHZhcmlhYmxlIHRvIGhlbHAgQ2FqYSBjb21wbGlhbmNlIChpdCBhc3N1bWVzIHRoaW5ncwogICAgICogb24gYSByZXF1aXJlIHRoYXQgYXJlIG5vdCBzdGFuZGFyZGl6ZWQpLCBhbmQgdG8gZ2l2ZSBhIHNob3J0CiAgICAgKiBuYW1lIGZvciBtaW5pZmljYXRpb24vbG9jYWwgc2NvcGUgdXNlLgogICAgICovCiAgICByZXEgPSByZXF1aXJlanMgPSBmdW5jdGlvbiAoZGVwcywgY2FsbGJhY2ssIGVycmJhY2ssIG9wdGlvbmFsKSB7CgogICAgICAgIC8vRmluZCB0aGUgcmlnaHQgY29udGV4dCwgdXNlIGRlZmF1bHQKICAgICAgICB2YXIgY29udGV4dCwgY29uZmlnLAogICAgICAgICAgICBjb250ZXh0TmFtZSA9IGRlZkNvbnRleHROYW1lOwoKICAgICAgICAvLyBEZXRlcm1pbmUgaWYgaGF2ZSBjb25maWcgb2JqZWN0IGluIHRoZSBjYWxsLgogICAgICAgIGlmICghaXNBcnJheShkZXBzKSAmJiB0eXBlb2YgZGVwcyAhPT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgLy8gZGVwcyBpcyBhIGNvbmZpZyBvYmplY3QKICAgICAgICAgICAgY29uZmlnID0gZGVwczsKICAgICAgICAgICAgaWYgKGlzQXJyYXkoY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAvLyBBZGp1c3QgYXJncyBpZiB0aGVyZSBhcmUgZGVwZW5kZW5jaWVzCiAgICAgICAgICAgICAgICBkZXBzID0gY2FsbGJhY2s7CiAgICAgICAgICAgICAgICBjYWxsYmFjayA9IGVycmJhY2s7CiAgICAgICAgICAgICAgICBlcnJiYWNrID0gb3B0aW9uYWw7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBkZXBzID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmIChjb25maWcgJiYgY29uZmlnLmNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dE5hbWUgPSBjb25maWcuY29udGV4dDsKICAgICAgICB9CgogICAgICAgIGNvbnRleHQgPSBnZXRPd24oY29udGV4dHMsIGNvbnRleHROYW1lKTsKICAgICAgICBpZiAoIWNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dCA9IGNvbnRleHRzW2NvbnRleHROYW1lXSA9IHJlcS5zLm5ld0NvbnRleHQoY29udGV4dE5hbWUpOwogICAgICAgIH0KCiAgICAgICAgaWYgKGNvbmZpZykgewogICAgICAgICAgICBjb250ZXh0LmNvbmZpZ3VyZShjb25maWcpOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIGNvbnRleHQucmVxdWlyZShkZXBzLCBjYWxsYmFjaywgZXJyYmFjayk7CiAgICB9OwoKICAgIC8qKgogICAgICogU3VwcG9ydCByZXF1aXJlLmNvbmZpZygpIHRvIG1ha2UgaXQgZWFzaWVyIHRvIGNvb3BlcmF0ZSB3aXRoIG90aGVyCiAgICAgKiBBTUQgbG9hZGVycyBvbiBnbG9iYWxseSBhZ3JlZWQgbmFtZXMuCiAgICAgKi8KICAgIHJlcS5jb25maWcgPSBmdW5jdGlvbiAoY29uZmlnKSB7CiAgICAgICAgcmV0dXJuIHJlcShjb25maWcpOwogICAgfTsKCiAgICAvKioKICAgICAqIEV4ZWN1dGUgc29tZXRoaW5nIGFmdGVyIHRoZSBjdXJyZW50IHRpY2sKICAgICAqIG9mIHRoZSBldmVudCBsb29wLiBPdmVycmlkZSBmb3Igb3RoZXIgZW52cwogICAgICogdGhhdCBoYXZlIGEgYmV0dGVyIHNvbHV0aW9uIHRoYW4gc2V0VGltZW91dC4KICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBmbiBmdW5jdGlvbiB0byBleGVjdXRlIGxhdGVyLgogICAgICovCiAgICByZXEubmV4dFRpY2sgPSB0eXBlb2Ygc2V0VGltZW91dCAhPT0gJ3VuZGVmaW5lZCcgPyBmdW5jdGlvbiAoZm4pIHsKICAgICAgICBzZXRUaW1lb3V0KGZuLCA0KTsKICAgIH0gOiBmdW5jdGlvbiAoZm4pIHsgZm4oKTsgfTsKCiAgICAvKioKICAgICAqIEV4cG9ydCByZXF1aXJlIGFzIGEgZ2xvYmFsLCBidXQgb25seSBpZiBpdCBkb2VzIG5vdCBhbHJlYWR5IGV4aXN0LgogICAgICovCiAgICBpZiAoIXJlcXVpcmUpIHsKICAgICAgICByZXF1aXJlID0gcmVxOwogICAgfQoKICAgIHJlcS52ZXJzaW9uID0gdmVyc2lvbjsKCiAgICAvL1VzZWQgdG8gZmlsdGVyIG91dCBkZXBlbmRlbmNpZXMgdGhhdCBhcmUgYWxyZWFkeSBwYXRocy4KICAgIHJlcS5qc0V4dFJlZ0V4cCA9IC9eXC98OnxcP3xcLmpzJC87CiAgICByZXEuaXNCcm93c2VyID0gaXNCcm93c2VyOwogICAgcyA9IHJlcS5zID0gewogICAgICAgIGNvbnRleHRzOiBjb250ZXh0cywKICAgICAgICBuZXdDb250ZXh0OiBuZXdDb250ZXh0CiAgICB9OwoKICAgIC8vQ3JlYXRlIGRlZmF1bHQgY29udGV4dC4KICAgIHJlcSh7fSk7CgogICAgLy9FeHBvcnRzIHNvbWUgY29udGV4dC1zZW5zaXRpdmUgbWV0aG9kcyBvbiBnbG9iYWwgcmVxdWlyZS4KICAgIGVhY2goWwogICAgICAgICd0b1VybCcsCiAgICAgICAgJ3VuZGVmJywKICAgICAgICAnZGVmaW5lZCcsCiAgICAgICAgJ3NwZWNpZmllZCcKICAgIF0sIGZ1bmN0aW9uIChwcm9wKSB7CiAgICAgICAgLy9SZWZlcmVuY2UgZnJvbSBjb250ZXh0cyBpbnN0ZWFkIG9mIGVhcmx5IGJpbmRpbmcgdG8gZGVmYXVsdCBjb250ZXh0LAogICAgICAgIC8vc28gdGhhdCBkdXJpbmcgYnVpbGRzLCB0aGUgbGF0ZXN0IGluc3RhbmNlIG9mIHRoZSBkZWZhdWx0IGNvbnRleHQKICAgICAgICAvL3dpdGggaXRzIGNvbmZpZyBnZXRzIHVzZWQuCiAgICAgICAgcmVxW3Byb3BdID0gZnVuY3Rpb24gKCkgewogICAgICAgICAgICB2YXIgY3R4ID0gY29udGV4dHNbZGVmQ29udGV4dE5hbWVdOwogICAgICAgICAgICByZXR1cm4gY3R4LnJlcXVpcmVbcHJvcF0uYXBwbHkoY3R4LCBhcmd1bWVudHMpOwogICAgICAgIH07CiAgICB9KTsKCiAgICBpZiAoaXNCcm93c2VyKSB7CiAgICAgICAgaGVhZCA9IHMuaGVhZCA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdoZWFkJylbMF07CiAgICAgICAgLy9JZiBCQVNFIHRhZyBpcyBpbiBwbGF5LCB1c2luZyBhcHBlbmRDaGlsZCBpcyBhIHByb2JsZW0gZm9yIElFNi4KICAgICAgICAvL1doZW4gdGhhdCBicm93c2VyIGRpZXMsIHRoaXMgY2FuIGJlIHJlbW92ZWQuIERldGFpbHMgaW4gdGhpcyBqUXVlcnkgYnVnOgogICAgICAgIC8vaHR0cDovL2Rldi5qcXVlcnkuY29tL3RpY2tldC8yNzA5CiAgICAgICAgYmFzZUVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnYmFzZScpWzBdOwogICAgICAgIGlmIChiYXNlRWxlbWVudCkgewogICAgICAgICAgICBoZWFkID0gcy5oZWFkID0gYmFzZUVsZW1lbnQucGFyZW50Tm9kZTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBBbnkgZXJyb3JzIHRoYXQgcmVxdWlyZSBleHBsaWNpdGx5IGdlbmVyYXRlcyB3aWxsIGJlIHBhc3NlZCB0byB0aGlzCiAgICAgKiBmdW5jdGlvbi4gSW50ZXJjZXB0L292ZXJyaWRlIGl0IGlmIHlvdSB3YW50IGN1c3RvbSBlcnJvciBoYW5kbGluZy4KICAgICAqIEBwYXJhbSB7RXJyb3J9IGVyciB0aGUgZXJyb3Igb2JqZWN0LgogICAgICovCiAgICByZXEub25FcnJvciA9IGRlZmF1bHRPbkVycm9yOwoKICAgIC8qKgogICAgICogQ3JlYXRlcyB0aGUgbm9kZSBmb3IgdGhlIGxvYWQgY29tbWFuZC4gT25seSB1c2VkIGluIGJyb3dzZXIgZW52cy4KICAgICAqLwogICAgcmVxLmNyZWF0ZU5vZGUgPSBmdW5jdGlvbiAoY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgbm9kZSA9IGNvbmZpZy54aHRtbCA/CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCAnaHRtbDpzY3JpcHQnKSA6CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsKICAgICAgICBub2RlLnR5cGUgPSBjb25maWcuc2NyaXB0VHlwZSB8fCAndGV4dC9qYXZhc2NyaXB0JzsKICAgICAgICBub2RlLmNoYXJzZXQgPSAndXRmLTgnOwogICAgICAgIG5vZGUuYXN5bmMgPSB0cnVlOwogICAgICAgIHJldHVybiBub2RlOwogICAgfTsKCiAgICAvKioKICAgICAqIERvZXMgdGhlIHJlcXVlc3QgdG8gbG9hZCBhIG1vZHVsZSBmb3IgdGhlIGJyb3dzZXIgY2FzZS4KICAgICAqIE1ha2UgdGhpcyBhIHNlcGFyYXRlIGZ1bmN0aW9uIHRvIGFsbG93IG90aGVyIGVudmlyb25tZW50cwogICAgICogdG8gb3ZlcnJpZGUgaXQuCiAgICAgKgogICAgICogQHBhcmFtIHtPYmplY3R9IGNvbnRleHQgdGhlIHJlcXVpcmUgY29udGV4dCB0byBmaW5kIHN0YXRlLgogICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZS4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSB1cmwgdGhlIFVSTCB0byB0aGUgbW9kdWxlLgogICAgICovCiAgICByZXEubG9hZCA9IGZ1bmN0aW9uIChjb250ZXh0LCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgY29uZmlnID0gKGNvbnRleHQgJiYgY29udGV4dC5jb25maWcpIHx8IHt9LAogICAgICAgICAgICBub2RlOwogICAgICAgIGlmIChpc0Jyb3dzZXIpIHsKICAgICAgICAgICAgLy9JbiB0aGUgYnJvd3NlciBzbyB1c2UgYSBzY3JpcHQgdGFnCiAgICAgICAgICAgIG5vZGUgPSByZXEuY3JlYXRlTm9kZShjb25maWcsIG1vZHVsZU5hbWUsIHVybCk7CiAgICAgICAgICAgIGlmIChjb25maWcub25Ob2RlQ3JlYXRlZCkgewogICAgICAgICAgICAgICAgY29uZmlnLm9uTm9kZUNyZWF0ZWQobm9kZSwgY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcsIGNvbnRleHQuY29udGV4dE5hbWUpOwogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJywgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAvL1NldCB1cCBsb2FkIGxpc3RlbmVyLiBUZXN0IGF0dGFjaEV2ZW50IGZpcnN0IGJlY2F1c2UgSUU5IGhhcwogICAgICAgICAgICAvL2Egc3VidGxlIGlzc3VlIGluIGl0cyBhZGRFdmVudExpc3RlbmVyIGFuZCBzY3JpcHQgb25sb2FkIGZpcmluZ3MKICAgICAgICAgICAgLy90aGF0IGRvIG5vdCBtYXRjaCB0aGUgYmVoYXZpb3Igb2YgYWxsIG90aGVyIGJyb3dzZXJzIHdpdGgKICAgICAgICAgICAgLy9hZGRFdmVudExpc3RlbmVyIHN1cHBvcnQsIHdoaWNoIGZpcmUgdGhlIG9ubG9hZCBldmVudCBmb3IgYQogICAgICAgICAgICAvL3NjcmlwdCByaWdodCBhZnRlciB0aGUgc2NyaXB0IGV4ZWN1dGlvbi4gU2VlOgogICAgICAgICAgICAvL2h0dHBzOi8vY29ubmVjdC5taWNyb3NvZnQuY29tL0lFL2ZlZWRiYWNrL2RldGFpbHMvNjQ4MDU3L3NjcmlwdC1vbmxvYWQtZXZlbnQtaXMtbm90LWZpcmVkLWltbWVkaWF0ZWx5LWFmdGVyLXNjcmlwdC1leGVjdXRpb24KICAgICAgICAgICAgLy9VTkZPUlRVTkFURUxZIE9wZXJhIGltcGxlbWVudHMgYXR0YWNoRXZlbnQgYnV0IGRvZXMgbm90IGZvbGxvdyB0aGUgc2NyaXB0CiAgICAgICAgICAgIC8vc2NyaXB0IGV4ZWN1dGlvbiBtb2RlLgogICAgICAgICAgICBpZiAobm9kZS5hdHRhY2hFdmVudCAmJgogICAgICAgICAgICAgICAgICAgIC8vQ2hlY2sgaWYgbm9kZS5hdHRhY2hFdmVudCBpcyBhcnRpZmljaWFsbHkgYWRkZWQgYnkgY3VzdG9tIHNjcmlwdCBvcgogICAgICAgICAgICAgICAgICAgIC8vbmF0aXZlbHkgc3VwcG9ydGVkIGJ5IGJyb3dzZXIKICAgICAgICAgICAgICAgICAgICAvL3JlYWQgaHR0cHM6Ly9naXRodWIuY29tL2pyYnVya2UvcmVxdWlyZWpzL2lzc3Vlcy8xODcKICAgICAgICAgICAgICAgICAgICAvL2lmIHdlIGNhbiBOT1QgZmluZCBbbmF0aXZlIGNvZGVdIHRoZW4gaXQgbXVzdCBOT1QgbmF0aXZlbHkgc3VwcG9ydGVkLgogICAgICAgICAgICAgICAgICAgIC8vaW4gSUU4LCBub2RlLmF0dGFjaEV2ZW50IGRvZXMgbm90IGhhdmUgdG9TdHJpbmcoKQogICAgICAgICAgICAgICAgICAgIC8vTm90ZSB0aGUgdGVzdCBmb3IgIltuYXRpdmUgY29kZSIgd2l0aCBubyBjbG9zaW5nIGJyYWNlLCBzZWU6CiAgICAgICAgICAgICAgICAgICAgLy9odHRwczovL2dpdGh1Yi5jb20vanJidXJrZS9yZXF1aXJlanMvaXNzdWVzLzI3MwogICAgICAgICAgICAgICAgICAgICEobm9kZS5hdHRhY2hFdmVudC50b1N0cmluZyAmJiBub2RlLmF0dGFjaEV2ZW50LnRvU3RyaW5nKCkuaW5kZXhPZignW25hdGl2ZSBjb2RlJykgPCAwKSAmJgogICAgICAgICAgICAgICAgICAgICFpc09wZXJhKSB7CiAgICAgICAgICAgICAgICAvL1Byb2JhYmx5IElFLiBJRSAoYXQgbGVhc3QgNi04KSBkbyBub3QgZmlyZQogICAgICAgICAgICAgICAgLy9zY3JpcHQgb25sb2FkIHJpZ2h0IGFmdGVyIGV4ZWN1dGluZyB0aGUgc2NyaXB0LCBzbwogICAgICAgICAgICAgICAgLy93ZSBjYW5ub3QgdGllIHRoZSBhbm9ueW1vdXMgZGVmaW5lIGNhbGwgdG8gYSBuYW1lLgogICAgICAgICAgICAgICAgLy9Ib3dldmVyLCBJRSByZXBvcnRzIHRoZSBzY3JpcHQgYXMgYmVpbmcgaW4gJ2ludGVyYWN0aXZlJwogICAgICAgICAgICAgICAgLy9yZWFkeVN0YXRlIGF0IHRoZSB0aW1lIG9mIHRoZSBkZWZpbmUgY2FsbC4KICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKCiAgICAgICAgICAgICAgICBub2RlLmF0dGFjaEV2ZW50KCdvbnJlYWR5c3RhdGVjaGFuZ2UnLCBjb250ZXh0Lm9uU2NyaXB0TG9hZCk7CiAgICAgICAgICAgICAgICAvL0l0IHdvdWxkIGJlIGdyZWF0IHRvIGFkZCBhbiBlcnJvciBoYW5kbGVyIGhlcmUgdG8gY2F0Y2gKICAgICAgICAgICAgICAgIC8vNDA0cyBpbiBJRTkrLiBIb3dldmVyLCBvbnJlYWR5c3RhdGVjaGFuZ2Ugd2lsbCBmaXJlIGJlZm9yZQogICAgICAgICAgICAgICAgLy90aGUgZXJyb3IgaGFuZGxlciwgc28gdGhhdCBkb2VzIG5vdCBoZWxwLiBJZiBhZGRFdmVudExpc3RlbmVyCiAgICAgICAgICAgICAgICAvL2lzIHVzZWQsIHRoZW4gSUUgd2lsbCBmaXJlIGVycm9yIGJlZm9yZSBsb2FkLCBidXQgd2UgY2Fubm90CiAgICAgICAgICAgICAgICAvL3VzZSB0aGF0IHBhdGh3YXkgZ2l2ZW4gdGhlIGNvbm5lY3QubWljcm9zb2Z0LmNvbSBpc3N1ZQogICAgICAgICAgICAgICAgLy9tZW50aW9uZWQgYWJvdmUgYWJvdXQgbm90IGRvaW5nIHRoZSAnc2NyaXB0IGV4ZWN1dGUsCiAgICAgICAgICAgICAgICAvL3RoZW4gZmlyZSB0aGUgc2NyaXB0IGxvYWQgZXZlbnQgbGlzdGVuZXIgYmVmb3JlIGV4ZWN1dGUKICAgICAgICAgICAgICAgIC8vbmV4dCBzY3JpcHQnIHRoYXQgb3RoZXIgYnJvd3NlcnMgZG8uCiAgICAgICAgICAgICAgICAvL0Jlc3QgaG9wZTogSUUxMCBmaXhlcyB0aGUgaXNzdWVzLAogICAgICAgICAgICAgICAgLy9hbmQgdGhlbiBkZXN0cm95cyBhbGwgaW5zdGFsbHMgb2YgSUUgNi05LgogICAgICAgICAgICAgICAgLy9ub2RlLmF0dGFjaEV2ZW50KCdvbmVycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIGNvbnRleHQub25TY3JpcHRMb2FkLCBmYWxzZSk7CiAgICAgICAgICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbm9kZS5zcmMgPSB1cmw7CgogICAgICAgICAgICAvL0ZvciBzb21lIGNhY2hlIGNhc2VzIGluIElFIDYtOCwgdGhlIHNjcmlwdCBleGVjdXRlcyBiZWZvcmUgdGhlIGVuZAogICAgICAgICAgICAvL29mIHRoZSBhcHBlbmRDaGlsZCBleGVjdXRpb24sIHNvIHRvIHRpZSBhbiBhbm9ueW1vdXMgZGVmaW5lCiAgICAgICAgICAgIC8vY2FsbCB0byB0aGUgbW9kdWxlIG5hbWUgKHdoaWNoIGlzIHN0b3JlZCBvbiB0aGUgbm9kZSksIGhvbGQgb24KICAgICAgICAgICAgLy90byBhIHJlZmVyZW5jZSB0byB0aGlzIG5vZGUsIGJ1dCBjbGVhciBhZnRlciB0aGUgRE9NIGluc2VydGlvbi4KICAgICAgICAgICAgY3VycmVudGx5QWRkaW5nU2NyaXB0ID0gbm9kZTsKICAgICAgICAgICAgaWYgKGJhc2VFbGVtZW50KSB7CiAgICAgICAgICAgICAgICBoZWFkLmluc2VydEJlZm9yZShub2RlLCBiYXNlRWxlbWVudCk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBoZWFkLmFwcGVuZENoaWxkKG5vZGUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGN1cnJlbnRseUFkZGluZ1NjcmlwdCA9IG51bGw7CgogICAgICAgICAgICByZXR1cm4gbm9kZTsKICAgICAgICB9IGVsc2UgaWYgKGlzV2ViV29ya2VyKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAvL0luIGEgd2ViIHdvcmtlciwgdXNlIGltcG9ydFNjcmlwdHMuIFRoaXMgaXMgbm90IGEgdmVyeQogICAgICAgICAgICAgICAgLy9lZmZpY2llbnQgdXNlIG9mIGltcG9ydFNjcmlwdHMsIGltcG9ydFNjcmlwdHMgd2lsbCBibG9jayB1bnRpbAogICAgICAgICAgICAgICAgLy9pdHMgc2NyaXB0IGlzIGRvd25sb2FkZWQgYW5kIGV2YWx1YXRlZC4gSG93ZXZlciwgaWYgd2ViIHdvcmtlcnMKICAgICAgICAgICAgICAgIC8vYXJlIGluIHBsYXksIHRoZSBleHBlY3RhdGlvbiBpcyB0aGF0IGEgYnVpbGQgaGFzIGJlZW4gZG9uZSBzbwogICAgICAgICAgICAgICAgLy90aGF0IG9ubHkgb25lIHNjcmlwdCBuZWVkcyB0byBiZSBsb2FkZWQgYW55d2F5LiBUaGlzIG1heSBuZWVkCiAgICAgICAgICAgICAgICAvL3RvIGJlIHJlZXZhbHVhdGVkIGlmIG90aGVyIHVzZSBjYXNlcyBiZWNvbWUgY29tbW9uLgogICAgICAgICAgICAgICAgaW1wb3J0U2NyaXB0cyh1cmwpOwoKICAgICAgICAgICAgICAgIC8vQWNjb3VudCBmb3IgYW5vbnltb3VzIG1vZHVsZXMKICAgICAgICAgICAgICAgIGNvbnRleHQuY29tcGxldGVMb2FkKG1vZHVsZU5hbWUpOwogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICBjb250ZXh0Lm9uRXJyb3IobWFrZUVycm9yKCdpbXBvcnRzY3JpcHRzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaW1wb3J0U2NyaXB0cyBmYWlsZWQgZm9yICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lICsgJyBhdCAnICsgdXJsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW21vZHVsZU5hbWVdKSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9OwoKICAgIGZ1bmN0aW9uIGdldEludGVyYWN0aXZlU2NyaXB0KCkgewogICAgICAgIGlmIChpbnRlcmFjdGl2ZVNjcmlwdCAmJiBpbnRlcmFjdGl2ZVNjcmlwdC5yZWFkeVN0YXRlID09PSAnaW50ZXJhY3RpdmUnKSB7CiAgICAgICAgICAgIHJldHVybiBpbnRlcmFjdGl2ZVNjcmlwdDsKICAgICAgICB9CgogICAgICAgIGVhY2hSZXZlcnNlKHNjcmlwdHMoKSwgZnVuY3Rpb24gKHNjcmlwdCkgewogICAgICAgICAgICBpZiAoc2NyaXB0LnJlYWR5U3RhdGUgPT09ICdpbnRlcmFjdGl2ZScpIHsKICAgICAgICAgICAgICAgIHJldHVybiAoaW50ZXJhY3RpdmVTY3JpcHQgPSBzY3JpcHQpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgcmV0dXJuIGludGVyYWN0aXZlU2NyaXB0OwogICAgfQoKICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gc2NyaXB0IGF0dHJpYnV0ZSwgd2hpY2ggY291bGQgYWxzbyBhZGp1c3QgdGhlIGJhc2VVcmwuCiAgICBpZiAoaXNCcm93c2VyICYmICFjZmcuc2tpcERhdGFNYWluKSB7CiAgICAgICAgLy9GaWd1cmUgb3V0IGJhc2VVcmwuIEdldCBpdCBmcm9tIHRoZSBzY3JpcHQgdGFnIHdpdGggcmVxdWlyZS5qcyBpbiBpdC4KICAgICAgICBlYWNoUmV2ZXJzZShzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHQpIHsKICAgICAgICAgICAgLy9TZXQgdGhlICdoZWFkJyB3aGVyZSB3ZSBjYW4gYXBwZW5kIGNoaWxkcmVuIGJ5CiAgICAgICAgICAgIC8vdXNpbmcgdGhlIHNjcmlwdCdzIHBhcmVudC4KICAgICAgICAgICAgaWYgKCFoZWFkKSB7CiAgICAgICAgICAgICAgICBoZWFkID0gc2NyaXB0LnBhcmVudE5vZGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gYXR0cmlidXRlIHRvIHNldCBtYWluIHNjcmlwdCBmb3IgdGhlIHBhZ2UKICAgICAgICAgICAgLy90byBsb2FkLiBJZiBpdCBpcyB0aGVyZSwgdGhlIHBhdGggdG8gZGF0YSBtYWluIGJlY29tZXMgdGhlCiAgICAgICAgICAgIC8vYmFzZVVybCwgaWYgaXQgaXMgbm90IGFscmVhZHkgc2V0LgogICAgICAgICAgICBkYXRhTWFpbiA9IHNjcmlwdC5nZXRBdHRyaWJ1dGUoJ2RhdGEtbWFpbicpOwogICAgICAgICAgICBpZiAoZGF0YU1haW4pIHsKICAgICAgICAgICAgICAgIC8vUHJlc2VydmUgZGF0YU1haW4gaW4gY2FzZSBpdCBpcyBhIHBhdGggKGkuZS4gY29udGFpbnMgJz8nKQogICAgICAgICAgICAgICAgbWFpblNjcmlwdCA9IGRhdGFNYWluOwoKICAgICAgICAgICAgICAgIC8vU2V0IGZpbmFsIGJhc2VVcmwgaWYgdGhlcmUgaXMgbm90IGFscmVhZHkgYW4gZXhwbGljaXQgb25lLgogICAgICAgICAgICAgICAgaWYgKCFjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvZmYgdGhlIGRpcmVjdG9yeSBvZiBkYXRhLW1haW4gZm9yIHVzZSBhcyB0aGUKICAgICAgICAgICAgICAgICAgICAvL2Jhc2VVcmwuCiAgICAgICAgICAgICAgICAgICAgc3JjID0gbWFpblNjcmlwdC5zcGxpdCgnLycpOwogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBzcmMucG9wKCk7CiAgICAgICAgICAgICAgICAgICAgc3ViUGF0aCA9IHNyYy5sZW5ndGggPyBzcmMuam9pbignLycpICArICcvJyA6ICcuLyc7CgogICAgICAgICAgICAgICAgICAgIGNmZy5iYXNlVXJsID0gc3ViUGF0aDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1N0cmlwIG9mZiBhbnkgdHJhaWxpbmcgLmpzIHNpbmNlIG1haW5TY3JpcHQgaXMgbm93CiAgICAgICAgICAgICAgICAvL2xpa2UgYSBtb2R1bGUgbmFtZS4KICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBtYWluU2NyaXB0LnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKCiAgICAgICAgICAgICAgICAvL0lmIG1haW5TY3JpcHQgaXMgc3RpbGwgYSBwYXRoLCBmYWxsIGJhY2sgdG8gZGF0YU1haW4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtYWluU2NyaXB0KSkgewogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBkYXRhTWFpbjsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1B1dCB0aGUgZGF0YS1tYWluIHNjcmlwdCBpbiB0aGUgZmlsZXMgdG8gbG9hZC4KICAgICAgICAgICAgICAgIGNmZy5kZXBzID0gY2ZnLmRlcHMgPyBjZmcuZGVwcy5jb25jYXQobWFpblNjcmlwdCkgOiBbbWFpblNjcmlwdF07CgogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKICAgIH0KCiAgICAvKioKICAgICAqIFRoZSBmdW5jdGlvbiB0aGF0IGhhbmRsZXMgZGVmaW5pdGlvbnMgb2YgbW9kdWxlcy4gRGlmZmVycyBmcm9tCiAgICAgKiByZXF1aXJlKCkgaW4gdGhhdCBhIHN0cmluZyBmb3IgdGhlIG1vZHVsZSBzaG91bGQgYmUgdGhlIGZpcnN0IGFyZ3VtZW50LAogICAgICogYW5kIHRoZSBmdW5jdGlvbiB0byBleGVjdXRlIGFmdGVyIGRlcGVuZGVuY2llcyBhcmUgbG9hZGVkIHNob3VsZAogICAgICogcmV0dXJuIGEgdmFsdWUgdG8gZGVmaW5lIHRoZSBtb2R1bGUgY29ycmVzcG9uZGluZyB0byB0aGUgZmlyc3QgYXJndW1lbnQncwogICAgICogbmFtZS4KICAgICAqLwogICAgZGVmaW5lID0gZnVuY3Rpb24gKG5hbWUsIGRlcHMsIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIG5vZGUsIGNvbnRleHQ7CgogICAgICAgIC8vQWxsb3cgZm9yIGFub255bW91cyBtb2R1bGVzCiAgICAgICAgaWYgKHR5cGVvZiBuYW1lICE9PSAnc3RyaW5nJykgewogICAgICAgICAgICAvL0FkanVzdCBhcmdzIGFwcHJvcHJpYXRlbHkKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbmFtZTsKICAgICAgICAgICAgbmFtZSA9IG51bGw7CiAgICAgICAgfQoKICAgICAgICAvL1RoaXMgbW9kdWxlIG1heSBub3QgaGF2ZSBkZXBlbmRlbmNpZXMKICAgICAgICBpZiAoIWlzQXJyYXkoZGVwcykpIHsKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbnVsbDsKICAgICAgICB9CgogICAgICAgIC8vSWYgbm8gbmFtZSwgYW5kIGNhbGxiYWNrIGlzIGEgZnVuY3Rpb24sIHRoZW4gZmlndXJlIG91dCBpZiBpdCBhCiAgICAgICAgLy9Db21tb25KUyB0aGluZyB3aXRoIGRlcGVuZGVuY2llcy4KICAgICAgICBpZiAoIWRlcHMgJiYgaXNGdW5jdGlvbihjYWxsYmFjaykpIHsKICAgICAgICAgICAgZGVwcyA9IFtdOwogICAgICAgICAgICAvL1JlbW92ZSBjb21tZW50cyBmcm9tIHRoZSBjYWxsYmFjayBzdHJpbmcsCiAgICAgICAgICAgIC8vbG9vayBmb3IgcmVxdWlyZSBjYWxscywgYW5kIHB1bGwgdGhlbSBpbnRvIHRoZSBkZXBlbmRlbmNpZXMsCiAgICAgICAgICAgIC8vYnV0IG9ubHkgaWYgdGhlcmUgYXJlIGZ1bmN0aW9uIGFyZ3MuCiAgICAgICAgICAgIGlmIChjYWxsYmFjay5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGNhbGxiYWNrCiAgICAgICAgICAgICAgICAgICAgLnRvU3RyaW5nKCkKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjb21tZW50UmVnRXhwLCAnJykKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjanNSZXF1aXJlUmVnRXhwLCBmdW5jdGlvbiAobWF0Y2gsIGRlcCkgewogICAgICAgICAgICAgICAgICAgICAgICBkZXBzLnB1c2goZGVwKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAvL01heSBiZSBhIENvbW1vbkpTIHRoaW5nIGV2ZW4gd2l0aG91dCByZXF1aXJlIGNhbGxzLCBidXQgc3RpbGwKICAgICAgICAgICAgICAgIC8vY291bGQgdXNlIGV4cG9ydHMsIGFuZCBtb2R1bGUuIEF2b2lkIGRvaW5nIGV4cG9ydHMgYW5kIG1vZHVsZQogICAgICAgICAgICAgICAgLy93b3JrIHRob3VnaCBpZiBpdCBqdXN0IG5lZWRzIHJlcXVpcmUuCiAgICAgICAgICAgICAgICAvL1JFUVVJUkVTIHRoZSBmdW5jdGlvbiB0byBleHBlY3QgdGhlIENvbW1vbkpTIHZhcmlhYmxlcyBpbiB0aGUKICAgICAgICAgICAgICAgIC8vb3JkZXIgbGlzdGVkIGJlbG93LgogICAgICAgICAgICAgICAgZGVwcyA9IChjYWxsYmFjay5sZW5ndGggPT09IDEgPyBbJ3JlcXVpcmUnXSA6IFsncmVxdWlyZScsICdleHBvcnRzJywgJ21vZHVsZSddKS5jb25jYXQoZGVwcyk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8vSWYgaW4gSUUgNi04IGFuZCBoaXQgYW4gYW5vbnltb3VzIGRlZmluZSgpIGNhbGwsIGRvIHRoZSBpbnRlcmFjdGl2ZQogICAgICAgIC8vd29yay4KICAgICAgICBpZiAodXNlSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgbm9kZSA9IGN1cnJlbnRseUFkZGluZ1NjcmlwdCB8fCBnZXRJbnRlcmFjdGl2ZVNjcmlwdCgpOwogICAgICAgICAgICBpZiAobm9kZSkgewogICAgICAgICAgICAgICAgaWYgKCFuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQgPSBjb250ZXh0c1tub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy9BbHdheXMgc2F2ZSBvZmYgZXZhbHVhdGluZyB0aGUgZGVmIGNhbGwgdW50aWwgdGhlIHNjcmlwdCBvbmxvYWQgaGFuZGxlci4KICAgICAgICAvL1RoaXMgYWxsb3dzIG11bHRpcGxlIG1vZHVsZXMgdG8gYmUgaW4gYSBmaWxlIHdpdGhvdXQgcHJlbWF0dXJlbHkKICAgICAgICAvL3RyYWNpbmcgZGVwZW5kZW5jaWVzLCBhbmQgYWxsb3dzIGZvciBhbm9ueW1vdXMgbW9kdWxlIHN1cHBvcnQsCiAgICAgICAgLy93aGVyZSB0aGUgbW9kdWxlIG5hbWUgaXMgbm90IGtub3duIHVudGlsIHRoZSBzY3JpcHQgb25sb2FkIGV2ZW50CiAgICAgICAgLy9vY2N1cnMuIElmIG5vIGNvbnRleHQsIHVzZSB0aGUgZ2xvYmFsIHF1ZXVlLCBhbmQgZ2V0IGl0IHByb2Nlc3NlZAogICAgICAgIC8vaW4gdGhlIG9uc2NyaXB0IGxvYWQgY2FsbGJhY2suCiAgICAgICAgaWYgKGNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgICAgICBjb250ZXh0LmRlZlF1ZXVlTWFwW25hbWVdID0gdHJ1ZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBnbG9iYWxEZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgIH0KICAgIH07CgogICAgZGVmaW5lLmFtZCA9IHsKICAgICAgICBqUXVlcnk6IHRydWUKICAgIH07CgogICAgLyoqCiAgICAgKiBFeGVjdXRlcyB0aGUgdGV4dC4gTm9ybWFsbHkganVzdCB1c2VzIGV2YWwsIGJ1dCBjYW4gYmUgbW9kaWZpZWQKICAgICAqIHRvIHVzZSBhIGJldHRlciwgZW52aXJvbm1lbnQtc3BlY2lmaWMgY2FsbC4gT25seSB1c2VkIGZvciB0cmFuc3BpbGluZwogICAgICogbG9hZGVyIHBsdWdpbnMsIG5vdCBmb3IgcGxhaW4gSlMgbW9kdWxlcy4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IHRoZSB0ZXh0IHRvIGV4ZWN1dGUvZXZhbHVhdGUuCiAgICAgKi8KICAgIHJlcS5leGVjID0gZnVuY3Rpb24gKHRleHQpIHsKICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgcmV0dXJuIGV2YWwodGV4dCk7CiAgICB9OwoKICAgIC8vU2V0IHVwIHdpdGggY29uZmlnIGluZm8uCiAgICByZXEoY2ZnKTsKfSh0aGlzKSk7Cg==",
"ok": true,
"headers": [
[
"content-type",
"application/javascript"
]
],
"status": 200,
"status_text": ""
}
},
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"# You would expect it to perform worse, the other strategy looked into the future\n",
"configure_plotly_browser_state()\n",
"# do LASSO subset selection at each timestep \n",
"backtestmodel = BacktestModel(X, Y, \n",
" create_model=LinearRegression, \n",
" coef_dict_param=\"timestep\", # instead of feeding paper predictors, at each time step perform an online recalculation\n",
" startindex=FIRST_TRAIN_MONTHS,\n",
" fit_missing='mean',\n",
" scaler = None)\n",
"backtestmodel.gen_predictions(verbose=False)\n",
"backtestmodel.gen_returns(calc_returns, verbose=False)\n",
"backtestmodel.report_returns(start_date=start_date_str, freq='M')\n",
"backtestmodel.evaluate_predictions()\n",
"backtestmodel.evaluate_quantiles(chart=True, verbose=True)\n",
"perf_LASSO_each_timestep = backtestmodel.cumulative_return\n",
"mychart([perf_LASSO_each_timestep],[\"LASSO each timestep\"], title=\"LASSO each timestep\")\n",
"\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/html": [
"\n",
" <script src=\"/static/components/requirejs/require.js\"></script>\n",
" <script>\n",
" requirejs.config({\n",
" paths: {\n",
" base: '/static/base',\n",
" plotly: 'https://cdn.plot.ly/plotly-latest.min.js?noext',\n",
" },\n",
" });\n",
" </script>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
},
{
"output_type": "stream",
"text": [
"................................................................................\n",
"15:21:39 Still training step 80 of 563\n",
"................................................................................\n",
"15:21:56 Still training step 160 of 563\n",
"................................................................................\n",
"15:22:15 Still training step 240 of 563\n",
"................................................................................\n",
"15:22:35 Still training step 320 of 563\n",
"................................................................................\n",
"15:22:54 Still training step 400 of 563\n",
"................................................................................\n",
"15:23:14 Still training step 480 of 563\n",
"................................................................................\n",
"15:23:35 Still training step 560 of 563\n",
"...\n",
"Mean return: 3.545%\n",
"Monthly Sharpe ratio: 0.674\n",
"OOS MSE across all predictions: 41.4734\n",
"In-sample MSE: 35.7675\n",
"Variance: 39.4097\n",
"R-squared: -0.0524\n",
"Avg rank correlation (Kendall's tau): 0.0331 (Expected: 0)\n",
"5-quintile accuracy: 0.2163 (Expected: 0.2)\n",
"Long/short/flat accuracy: 0.4584 (Expected: 0.44)\n",
"Confusion matrix for quantile 0\n",
"[[10910 2602]\n",
" [ 2598 780]]\n",
"Chi-square: 24.8287 (p-value: 0.00001677)\n",
"Confusion matrix for quantile 1\n",
"[[10840 2672]\n",
" [ 2672 706]]\n",
"Chi-square: 2.1374 (p-value: 0.54439176)\n",
"Confusion matrix for quantile 2\n",
"[[10831 2681]\n",
" [ 2675 703]]\n",
"Chi-square: 1.6009 (p-value: 0.65918763)\n",
"Confusion matrix for quantile 3\n",
"[[10827 2685]\n",
" [ 2690 688]]\n",
"Chi-square: 0.4245 (p-value: 0.93512982)\n",
"Confusion matrix for quantile 4\n",
"[[10916 2596]\n",
" [ 2601 777]]\n",
"Chi-square: 24.2603 (p-value: 0.00002204)\n",
"Excess true positive in quintiles 1 + 5: 205.800000\n"
],
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"image/png": "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\nERER51DCIyIiIo6nIS0RERG30qRlEREREedQhUdERMStNGlZRERExDlU4REREXErzeERERERcQ5V\neERERNxKc3hEREREnEMVHhEREbdShUdEREQkNIwxrY0xa4psacaYCcaYe40x+4q0n1dknzuNMduN\nMVuMMYNP9hqq8IiIiLiVteGOAABr7RagM4AxxgPsA94BrgbmWGsfKdrfGNMOGAm0B+oDnxpjTrHW\nFhT3GqrwiIiISFkyENhhrd1TQp9hwCJrbY61dhewHehR0pMq4REREXErny9kmzFmlDFmZZFtVDFR\njQReL3J/jDFmnTHmOWNM9UBbA2BvkT7xgbZiKeERERGRoLPWzrfWdiuyzf9tH2NMFHAh8J9A01NA\nC/zDXQnAo3/09TWHR0RExK3K3iqtIcAqa20SwLH/AhhjFgDvB+7uAxoV2a9hoK1YqvCIiIhIWXEp\nRYazjDH1ijz2N+DnwO3FwEhjTAVjTDOgFfBDSU+sCo+IiIhblaFraRljKgGDgBuKNM8yxnQGLLD7\n2GPW2g3GmDeBjUA+MLqkFVqghEdERETKAGvtUaDmb9ouL6H/DGBGaZ9fQ1oiIiLieKrwiIiIuFXZ\nm7QcNKrwiIiIiOOpwiMiIuJWZeTSEqGgCo+IiIg4nio8IiIibuWiOTxlNuG5tOuEcIfgeI/UzAp3\nCI731oj64Q7BFbrN2RTuEBxvQv3+4Q5B5E8pswmPiIiIBJmLKjyawyMiIiKOpwqPiIiIW5WhS0sE\nmyo8IiIi4niq8IiIiLiU9ek8PCIiIiKOoQqPiIiIW2mVloiIiIhzqMIjIiLiVlqlJSIiIuIcSnhE\nRETE8TSkJSIi4lZali4iIiLiHKrwiIiIuJWWpYuIiIg4hyo8IiIibqUKj4iIiIhzqMIjIiLiVlar\ntEREREQcQxUeERERt9IcHhERERHnUIVHRETErXSmZRERERHnUIVHRETErazm8IiIiIg4hio8IiIi\nbqU5PCIiIiLOoYRHREREHE9DWiIiIi5ldeJBEREREedQhUdERMStNGlZRERExDlU4REREXErnXhQ\nRERExDlU4REREXErzeERERERcQ5VeERERNxK5+ERERERcQ5VeERERNxKc3hEREREnEMVHhEREbfS\neXhEREREnEMVHhEREbfSHB4RERER51DCIyIiIo6nIS0RERGXsjrxoIiIiIhzqMIjIiLiVpq0LCIi\n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\nB6Z8FvdZKyeoAAAAAElFTkSuQmCC\n",
"text/plain": [
"<Figure size 720x720 with 2 Axes>"
]
},
"metadata": {
"tags": []
}
},
{
"output_type": "display_data",
"data": {
"text/html": [
"<div id=\"7e0d57ea-fae1-41d9-bbca-d21986af0c7d\" style=\"height: 600px; width: 900px;\" class=\"plotly-graph-div\"></div><script type=\"text/javascript\">require([\"plotly\"], function(Plotly) { window.PLOTLYENV=window.PLOTLYENV || {};window.PLOTLYENV.BASE_URL=\"https://plot.ly\";Plotly.newPlot(\"7e0d57ea-fae1-41d9-bbca-d21986af0c7d\", [{\"type\": \"scatter\", \"x\": [1970.0, 1970.081850533808, 1970.1637010676156, 1970.2455516014236, 1970.3274021352313, 1970.4092526690392, 1970.491103202847, 1970.5729537366549, 1970.6548042704626, 1970.7366548042705, 1970.8185053380782, 1970.9003558718862, 1970.982206405694, 1971.0640569395018, 1971.1459074733095, 1971.2277580071175, 1971.3096085409252, 1971.3914590747331, 1971.4733096085408, 1971.5551601423488, 1971.6370106761565, 1971.7188612099644, 1971.8007117437724, 1971.88256227758, 1971.964412811388, 1972.0462633451957, 1972.1281138790036, 1972.2099644128114, 1972.2918149466193, 1972.373665480427, 1972.455516014235, 1972.5373665480427, 1972.6192170818506, 1972.7010676156583, 1972.7829181494662, 1972.864768683274, 1972.946619217082, 1973.0284697508896, 1973.1103202846975, 1973.1921708185052, 1973.2740213523132, 1973.355871886121, 1973.4377224199288, 1973.5195729537365, 1973.6014234875445, 1973.6832740213524, 1973.7651245551601, 1973.846975088968, 1973.9288256227758, 1974.0106761565837, 1974.0925266903914, 1974.1743772241994, 1974.256227758007, 1974.338078291815, 1974.4199288256227, 1974.5017793594307, 1974.5836298932384, 1974.6654804270463, 1974.747330960854, 1974.829181494662, 1974.9110320284697, 1974.9928825622776, 1975.0747330960853, 1975.1565836298932, 1975.238434163701, 1975.320284697509, 1975.4021352313168, 1975.4839857651245, 1975.5658362989325, 1975.6476868327402, 1975.7295373665481, 1975.8113879003558, 1975.8932384341638, 1975.9750889679715, 1976.0569395017794, 1976.1387900355871, 1976.220640569395, 1976.3024911032028, 1976.3843416370107, 1976.4661921708184, 1976.5480427046264, 1976.629893238434, 1976.711743772242, 1976.7935943060497, 1976.8754448398577, 1976.9572953736654, 1977.0391459074733, 1977.1209964412812, 1977.202846975089, 1977.284697508897, 1977.3665480427046, 1977.4483985765125, 1977.5302491103203, 1977.6120996441282, 1977.693950177936, 1977.7758007117438, 1977.8576512455516, 1977.9395017793595, 1978.0213523131672, 1978.1032028469751, 1978.1850533807828, 1978.2669039145908, 1978.3487544483985, 1978.4306049822064, 1978.5124555160141, 1978.594306049822, 1978.6761565836298, 1978.7580071174377, 1978.8398576512454, 1978.9217081850534, 1979.0035587188613, 1979.085409252669, 1979.167259786477, 1979.2491103202847, 1979.3309608540926, 1979.4128113879003, 1979.4946619217083, 1979.576512455516, 1979.658362989324, 1979.7402135231316, 1979.8220640569396, 1979.9039145907473, 1979.9857651245552, 1980.067615658363, 1980.1494661921708, 1980.2313167259786, 1980.3131672597865, 1980.3950177935942, 1980.4768683274021, 1980.5587188612099, 1980.6405693950178, 1980.7224199288257, 1980.8042704626334, 1980.8861209964414, 1980.967971530249, 1981.049822064057, 1981.1316725978647, 1981.2135231316727, 1981.2953736654804, 1981.3772241992883, 1981.459074733096, 1981.540925266904, 1981.6227758007117, 1981.7046263345196, 1981.7864768683273, 1981.8683274021353, 1981.950177935943, 1982.032028469751, 1982.1138790035586, 1982.1957295373666, 1982.2775800711743, 1982.3594306049822, 1982.4412811387901, 1982.5231316725979, 1982.6049822064058, 1982.6868327402135, 1982.7686832740214, 1982.8505338078292, 1982.932384341637, 1983.0142348754448, 1983.0960854092527, 1983.1779359430604, 1983.2597864768684, 1983.341637010676, 1983.423487544484, 1983.5053380782917, 1983.5871886120997, 1983.6690391459074, 1983.7508896797153, 1983.832740213523, 1983.914590747331, 1983.9964412811387, 1984.0782918149466, 1984.1601423487546, 1984.2419928825623, 1984.3238434163702, 1984.405693950178, 1984.4875444839859, 1984.5693950177936, 1984.6512455516015, 1984.7330960854092, 1984.8149466192172, 1984.8967971530249, 1984.9786476868328, 1985.0604982206405, 1985.1423487544484, 1985.2241992882562, 1985.306049822064, 1985.3879003558718, 1985.4697508896797, 1985.5516014234875, 1985.6334519572954, 1985.715302491103, 1985.797153024911, 1985.8790035587188, 1985.9608540925267, 1986.0427046263346, 1986.1245551601423, 1986.2064056939503, 1986.288256227758, 1986.370106761566, 1986.4519572953736, 1986.5338078291816, 1986.6156583629893, 1986.6975088967972, 1986.779359430605, 1986.8612099644129, 1986.9430604982206, 1987.0249110320285, 1987.1067615658362, 1987.1886120996442, 1987.2704626334519, 1987.3523131672598, 1987.4341637010675, 1987.5160142348755, 1987.5978647686832, 1987.679715302491, 1987.761565836299, 1987.8434163701068, 1987.9252669039147, 1988.0071174377224, 1988.0889679715303, 1988.170818505338, 1988.252669039146, 1988.3345195729537, 1988.4163701067616, 1988.4982206405693, 1988.5800711743773, 1988.661921708185, 1988.743772241993, 1988.8256227758006, 1988.9074733096086, 1988.9893238434163, 1989.0711743772242, 1989.153024911032, 1989.2348754448399, 1989.3167259786476, 1989.3985765124555, 1989.4804270462632, 1989.5622775800712, 1989.644128113879, 1989.7259786476868, 1989.8078291814948, 1989.8896797153025, 1989.9715302491104, 1990.053380782918, 1990.135231316726, 1990.2170818505338, 1990.2989323843417, 1990.3807829181494, 1990.4626334519573, 1990.544483985765, 1990.626334519573, 1990.7081850533807, 1990.7900355871886, 1990.8718861209964, 1990.9537366548043, 1991.035587188612, 1991.11743772242, 1991.1992882562276, 1991.2811387900356, 1991.3629893238435, 1991.4448398576512, 1991.5266903914592, 1991.6085409252669, 1991.6903914590748, 1991.7722419928825, 1991.8540925266905, 1991.9359430604982, 1992.017793594306, 1992.0996441281138, 1992.1814946619218, 1992.2633451957295, 1992.3451957295374, 1992.4270462633451, 1992.508896797153, 1992.5907473309608, 1992.6725978647687, 1992.7544483985764, 1992.8362989323844, 1992.918149466192, 1993.0, 1993.081850533808, 1993.1637010676156, 1993.2455516014236, 1993.3274021352313, 1993.4092526690392, 1993.491103202847, 1993.5729537366549, 1993.6548042704626, 1993.7366548042705, 1993.8185053380782, 1993.9003558718862, 1993.982206405694, 1994.0640569395018, 1994.1459074733095, 1994.2277580071175, 1994.3096085409252, 1994.3914590747331, 1994.4733096085408, 1994.5551601423488, 1994.6370106761565, 1994.7188612099644, 1994.8007117437724, 1994.88256227758, 1994.964412811388, 1995.0462633451957, 1995.1281138790036, 1995.2099644128114, 1995.2918149466193, 1995.373665480427, 1995.455516014235, 1995.5373665480427, 1995.6192170818506, 1995.7010676156583, 1995.7829181494662, 1995.864768683274, 1995.946619217082, 1996.0284697508896, 1996.1103202846975, 1996.1921708185052, 1996.2740213523132, 1996.355871886121, 1996.4377224199288, 1996.5195729537368, 1996.6014234875445, 1996.6832740213524, 1996.7651245551601, 1996.846975088968, 1996.9288256227758, 1997.0106761565837, 1997.0925266903914, 1997.1743772241994, 1997.256227758007, 1997.338078291815, 1997.4199288256227, 1997.5017793594307, 1997.5836298932384, 1997.6654804270463, 1997.747330960854, 1997.829181494662, 1997.9110320284697, 1997.9928825622776, 1998.0747330960853, 1998.1565836298932, 1998.238434163701, 1998.320284697509, 1998.4021352313168, 1998.4839857651245, 1998.5658362989325, 1998.6476868327402, 1998.7295373665481, 1998.8113879003558, 1998.8932384341638, 1998.9750889679715, 1999.0569395017794, 1999.1387900355871, 1999.220640569395, 1999.3024911032028, 1999.3843416370107, 1999.4661921708184, 1999.5480427046264, 1999.629893238434, 1999.711743772242, 1999.7935943060497, 1999.8754448398577, 1999.9572953736654, 2000.0391459074733, 2000.1209964412812, 2000.202846975089, 2000.284697508897, 2000.3665480427046, 2000.4483985765125, 2000.5302491103203, 2000.6120996441282, 2000.693950177936, 2000.7758007117438, 2000.8576512455516, 2000.9395017793595, 2001.0213523131672, 2001.1032028469751, 2001.1850533807828, 2001.2669039145908, 2001.3487544483985, 2001.4306049822064, 2001.5124555160141, 2001.594306049822, 2001.6761565836298, 2001.7580071174377, 2001.8398576512454, 2001.9217081850534, 2002.0035587188613, 2002.085409252669, 2002.167259786477, 2002.2491103202847, 2002.3309608540926, 2002.4128113879003, 2002.4946619217083, 2002.576512455516, 2002.658362989324, 2002.7402135231316, 2002.8220640569396, 2002.9039145907473, 2002.9857651245552, 2003.067615658363, 2003.1494661921708, 2003.2313167259786, 2003.3131672597865, 2003.3950177935942, 2003.4768683274021, 2003.5587188612099, 2003.6405693950178, 2003.7224199288257, 2003.8042704626334, 2003.8861209964414, 2003.967971530249, 2004.049822064057, 2004.1316725978647, 2004.2135231316727, 2004.2953736654804, 2004.3772241992883, 2004.459074733096, 2004.540925266904, 2004.6227758007117, 2004.7046263345196, 2004.7864768683273, 2004.8683274021353, 2004.950177935943, 2005.032028469751, 2005.1138790035586, 2005.1957295373666, 2005.2775800711743, 2005.3594306049822, 2005.4412811387901, 2005.5231316725979, 2005.6049822064058, 2005.6868327402135, 2005.7686832740214, 2005.8505338078292, 2005.932384341637, 2006.0142348754448, 2006.0960854092527, 2006.1779359430604, 2006.2597864768684, 2006.341637010676, 2006.423487544484, 2006.5053380782917, 2006.5871886120997, 2006.6690391459074, 2006.7508896797153, 2006.832740213523, 2006.914590747331, 2006.9964412811387, 2007.0782918149466, 2007.1601423487546, 2007.2419928825623, 2007.3238434163702, 2007.405693950178, 2007.4875444839859, 2007.5693950177936, 2007.6512455516015, 2007.7330960854092, 2007.8149466192172, 2007.8967971530249, 2007.9786476868328, 2008.0604982206405, 2008.1423487544484, 2008.2241992882562, 2008.306049822064, 2008.3879003558718, 2008.4697508896797, 2008.5516014234875, 2008.6334519572954, 2008.715302491103, 2008.797153024911, 2008.879003558719, 2008.9608540925267, 2009.0427046263346, 2009.1245551601423, 2009.2064056939503, 2009.288256227758, 2009.370106761566, 2009.4519572953736, 2009.5338078291816, 2009.6156583629893, 2009.6975088967972, 2009.779359430605, 2009.8612099644129, 2009.9430604982206, 2010.0249110320285, 2010.1067615658362, 2010.1886120996442, 2010.2704626334519, 2010.3523131672598, 2010.4341637010675, 2010.5160142348755, 2010.5978647686832, 2010.679715302491, 2010.761565836299, 2010.8434163701068, 2010.9252669039147, 2011.0071174377224, 2011.0889679715303, 2011.170818505338, 2011.252669039146, 2011.3345195729537, 2011.4163701067616, 2011.4982206405693, 2011.5800711743773, 2011.661921708185, 2011.743772241993, 2011.8256227758006, 2011.9074733096086, 2011.9893238434163, 2012.0711743772242, 2012.153024911032, 2012.2348754448399, 2012.3167259786476, 2012.3985765124555, 2012.4804270462632, 2012.5622775800712, 2012.644128113879, 2012.7259786476868, 2012.8078291814948, 2012.8896797153025, 2012.9715302491104, 2013.053380782918, 2013.135231316726, 2013.2170818505338, 2013.2989323843417, 2013.3807829181494, 2013.4626334519573, 2013.544483985765, 2013.626334519573, 2013.7081850533807, 2013.7900355871886, 2013.8718861209964, 2013.9537366548043, 2014.035587188612, 2014.11743772242, 2014.1992882562276, 2014.2811387900356, 2014.3629893238435, 2014.4448398576512, 2014.5266903914592, 2014.6085409252669, 2014.6903914590748, 2014.7722419928825, 2014.8540925266905, 2014.9359430604982, 2015.017793594306, 2015.0996441281138, 2015.1814946619218, 2015.2633451957295, 2015.3451957295374, 2015.4270462633451, 2015.508896797153, 2015.5907473309608, 2015.6725978647687, 2015.7544483985764, 2015.8362989323844, 2015.918149466192, 2016.0], \"y\": [100.0, 100.42833333333334, 100.02913070833334, 100.97774029788404, 101.78472073909796, 102.04511998298884, 100.4659717512521, 102.33715047511916, 105.96841369781129, 104.61643335305004, 104.56935595804117, 104.49790023146986, 105.49237191533933, 106.09455753835609, 108.06526394463106, 106.57036112673033, 106.78261376264106, 106.3554833075905, 107.52184844119708, 105.89558048352399, 105.94499842108296, 106.58243416158312, 107.04695593713735, 106.7543609242425, 108.40193656117331, 109.09028885833678, 110.01119271344923, 110.90686717412457, 113.36807540149701, 112.51025696429234, 113.54628891383851, 115.66581964023015, 115.94438148919704, 116.49511730127074, 116.5300658364611, 115.64637950386793, 115.99139120272115, 118.64469427648339, 120.02690496480442, 118.52156753170415, 120.40507277572881, 123.86671861803103, 122.82004484570868, 121.95416352954642, 123.25704050992042, 123.21595482975044, 123.47470833489294, 124.71048437414467, 124.37688382844382, 123.95607537149094, 122.96339380122423, 125.04864802110333, 124.68079658150792, 126.11358673555708, 126.8271794471691, 129.7885940872605, 131.484498383334, 134.53274733752096, 134.83880933771383, 137.14904760436667, 129.70756886309974, 133.22372487569692, 133.44798481257098, 136.0913669784, 136.63233016213917, 136.10515708826358, 138.3939921466312, 139.8113772828663, 140.30188219816702, 138.12720302409542, 139.16315704677615, 137.91416771228137, 138.70717417662698, 141.18656491503418, 140.22767282831958, 138.56013208560282, 141.54494826428018, 144.1493753123429, 143.79981307721047, 146.4852745864274, 147.5082300872893, 146.44248312490862, 145.17453529185212, 143.5376924064365, 142.34154496971618, 143.47434643176683, 144.104437936513, 146.25639754303157, 144.12105413890333, 143.39924785942432, 145.00890441664637, 145.73394893872958, 146.21851431895087, 146.0259932750976, 146.18418810114562, 147.09540287364277, 146.92992054540989, 146.12792806243286, 145.16713693542238, 148.10314227994127, 150.41231710665605, 149.7354616796761, 149.98002960041956, 152.5346894379467, 151.5826187513715, 151.97294399465628, 151.08896803708737, 152.9322534471398, 155.427598049219, 155.46515971874757, 155.68151539935616, 156.3029441149919, 156.7718529473369, 161.21894784260968, 164.3210690973479, 164.07595683594437, 164.97290539998087, 162.1807389760862, 165.15270101782298, 168.1846293540085, 172.51958817560808, 174.73502722042983, 168.63386251998315, 171.29546698342355, 169.60106932251253, 167.719910795277, 168.1168479174925, 169.33149214369638, 171.7275327575297, 172.5203415337603, 172.93870336197966, 169.61539794570695, 170.91436920164116, 173.21886461304328, 175.45050098547466, 176.81462863063672, 177.9182466043396, 175.33694937652166, 179.0964657994032, 179.75464531121602, 179.94788155492557, 180.27478687308366, 180.7795562763283, 181.45597311606224, 180.04061652575695, 182.16809647770296, 186.7147085522923, 187.91279459883617, 189.17494220255838, 187.50704979547248, 189.39930843965845, 188.51386667270305, 189.56326053051444, 190.60585846343227, 198.50488291458768, 194.23537372456641, 199.2547395072321, 193.65734178324143, 196.29915068740118, 197.9905950358243, 197.69525906489588, 201.6541066276704, 199.9770166408836, 206.28295856562616, 205.35468525208086, 206.96329695322214, 202.31524624248104, 202.49227208294323, 206.51680599059173, 210.2168987645898, 208.41253705019375, 206.50208879390027, 208.3296322797263, 208.18727369766847, 210.2205694041157, 206.2982039466506, 203.06104129638777, 203.87328546157332, 204.7380479807395, 205.71396600944766, 206.51453619383443, 204.24631820463884, 211.9702331380776, 210.94924318179585, 212.54542578853815, 214.87988304844893, 208.41199856869062, 208.77671956618582, 209.86061870193362, 212.67275099253956, 215.07595307875525, 218.1103163167747, 217.87766531270347, 221.32194807185516, 222.33634033385118, 222.6513168159908, 225.9113031797049, 230.52930673553672, 231.87982425749576, 232.27595229060233, 236.63499766192265, 231.5710087119575, 232.91605032089277, 233.27901116597616, 228.41319979140584, 234.01884040295323, 231.1033556829331, 234.44087331125414, 235.04846590791914, 236.43916933120767, 233.56249277101128, 231.69204647473677, 231.7403156510857, 226.960671640782, 224.1671640406701, 225.52524344281645, 226.27887363132118, 222.88657618413163, 224.27590250901267, 227.74470313448543, 228.71261812280702, 227.32318896771093, 225.22234382966766, 227.32817274447507, 227.75820187125, 226.16389445815125, 225.37985962402968, 226.43351046777204, 227.1656454849512, 227.3530571424763, 228.81948436104528, 227.42177867740656, 231.413030893195, 232.83043570741583, 232.79551114205975, 226.7893869545946, 224.07358404581333, 222.8243738147579, 224.26530476542666, 222.19271957388617, 226.84210223096972, 230.2617469221016, 228.26422626755237, 228.4506420523375, 227.15228090334008, 227.22989126598208, 226.25469631596556, 226.90894947947925, 237.333524800149, 242.73484026872575, 241.55757629342241, 244.26704710751363, 246.04612543394668, 249.39440312422695, 251.88626886877648, 250.9647849351649, 246.55826158634494, 245.95008454109865, 241.45124757803438, 240.93615158320122, 241.46621111668426, 242.07993773660584, 246.49991393311333, 249.90572107728917, 256.1846023193561, 255.05312032577896, 255.74814007866672, 251.38550305582478, 253.59769548271603, 253.9844319683272, 252.29966856960397, 254.15827612806675, 251.39430487517402, 253.3468006430379, 260.89442407886173, 260.8900758384604, 264.6990709457019, 263.15058138066956, 264.33695191839405, 264.7841219287227, 267.19807050697284, 264.9268869076636, 268.55196981018344, 271.0271237986006, 268.7301689244075, 268.0001186321628, 269.3847859117624, 268.55418282186776, 266.5176469354686, 265.3516322301259, 262.83300298754165, 264.95318921164113, 261.6169869708179, 259.38670215689166, 260.9948997102644, 259.2745083296743, 258.95905767787315, 256.3780990696837, 259.9631194883414, 256.4666155312232, 254.17123932221875, 255.2048690287958, 256.51917410429405, 252.91935502769712, 254.20292075446267, 255.9505658346496, 253.6256815283182, 251.44661421452076, 252.60745941681114, 257.1143975052395, 256.27234785340977, 252.68667058636086, 255.60309590937842, 255.82248856670066, 256.04420139012507, 258.9439019708683, 260.5752485532848, 262.1234998217722, 265.504892969473, 265.783673107091, 267.8767195328093, 265.7805842024651, 266.46939888318985, 261.7440082096613, 263.0679966511885, 270.4295160908109, 267.60352764766196, 269.47675234119555, 270.79269714846174, 269.44776008595767, 266.4501537550014, 269.11909612844727, 269.14825069719456, 273.25276152032677, 284.53126925207823, 290.79807045735527, 295.4944592952416, 292.17999644348, 291.0161461243134, 296.1113538160399, 288.66662086218173, 293.20109236489185, 295.1606529988639, 305.5330902796656, 299.417336255901, 295.3527459162271, 300.7601624393767, 301.6824936041908, 301.75037216525175, 305.2883952788893, 312.0276366046708, 311.7858151863022, 307.002501138319, 313.0939424317385, 309.5377170689514, 314.7843813732701, 312.8720662564275, 327.07906533168807, 325.4409443461519, 311.23544712544236, 327.0747377554013, 339.2964304561948, 320.57292243552047, 319.38947406352935, 336.0882203991508, 325.6638840964372, 325.85656856119425, 325.43295502206473, 321.0206265402239, 330.7127742898508, 337.40695202943454, 332.3824001687962, 316.289552293957, 319.4893482646643, 317.86261499975, 323.2265466278708, 321.0447674381327, 325.8283344729608, 331.57105886804675, 344.09615561678714, 350.5450910666384, 347.32299743791754, 343.2216917098382, 345.22953860634067, 346.7744407916041, 357.75274162966497, 362.67482309991976, 354.4118817136266, 356.49109808634654, 370.45069533557773, 375.99510740910017, 377.7654177064847, 383.18005536027766, 388.15820291283325, 384.35425252428746, 386.1799352237779, 382.5916799923236, 388.67488770420147, 384.65534157386054, 379.96254640665944, 377.65744029179234, 382.51033839954187, 375.2745178314839, 381.83869460588625, 377.05616495594757, 370.75932700118324, 371.81908074419493, 365.44858049411107, 361.89459304880586, 358.5892890989601, 356.88897821981584, 356.621311486151, 355.0224592729881, 359.20876577191547, 368.09618931838895, 368.93667561733264, 366.77532159267446, 361.5029263447797, 352.39606512527746, 350.4549501332124, 349.8737790075748, 354.47170358669933, 356.0934116306085, 360.41401169172656, 359.30273515567706, 359.4883749021742, 369.77872963374887, 371.35645221351956, 372.8294994739665, 369.29383305395504, 369.42308589552397, 371.06086157632745, 379.48703530795655, 381.4160944041053, 377.1251633420591, 386.0253171969318, 386.1057391380144, 391.0865031728948, 405.93475407669246, 413.0690573795903, 415.3443794373228, 409.70607948646114, 411.24589150186443, 416.9073766082068, 417.5084180761503, 423.6388333482351, 422.33261361207803, 421.12896566328357, 423.6522300492161, 423.5180735097005, 423.595718489844, 425.35011075725606, 423.8259395270426, 419.3015976225913, 415.38462186480024, 422.84769890430454, 408.37926014012896, 406.08552996234187, 402.2040291051185, 394.190113825199, 408.81128213049874, 414.0985747127198, 409.91617910812136, 408.3926573091028, 423.7720441289348, 448.08243372713133, 458.08214003980845, 450.79099931084147, 447.8984237319303, 463.48155639093704, 456.59113058592504, 508.10982982037024, 513.0977746497736, 507.2612874631323, 500.57389282341, 508.93764828266785, 510.0573111088897, 504.6507036111355, 506.32866720064254, 507.4003962128839, 503.92470349882564, 497.1973087071163, 495.37425190852355, 505.24458387780084, 502.58362906937776, 511.12336256664827, 505.2710000652602, 504.31940634847064, 494.3044634707339, 500.52858050660285, 507.91971921208363, 509.6381809287512, 517.0704044006288, 516.1181330725244, 513.0214242740892, 510.375088760542, 525.2822944780894, 528.0925547535472, 531.7980041794012, 541.1044692525409, 566.7934039303051, 544.2680894024415, 531.641069728305, 537.210009933709, 531.5290140786599, 525.9523888392846, 533.1447877566619, 527.9999405548101, 535.6251396963225, 531.8668366327867, 532.6114502040726, 524.3692880121645, 527.1178570301615, 535.2837911653205, 527.5221761934233, 519.6620957681413, 516.2279954186067, 524.6080965442354, 527.6814256431571, 533.5386894677961, 521.591868979463, 510.26463222479225, 510.12430945093047, 514.6049013022745, 506.3969531265032, 508.4436408120562, 501.3593260834082, 499.5335425375878, 500.07886665485796, 501.8624812792604, 494.0543375080239, 498.73550235591233, 498.90590365255065, 498.839382865397, 495.6800667739161, 499.76942732480103, 506.32473631321136, 514.9702311857593, 522.3600540032751, 523.3220671027311, 528.568370825436, 523.2959013264523, 517.5222032151504, 512.5367393241778, 515.3855893669213, 528.1327929439298, 546.6218418035752, 540.317469894774, 525.5127712196572, 537.5163587689328, 531.5768030045363, 523.2487664241318, 540.5159757161281, 530.5029172659868, 538.8097087788434, 559.8906386348157, 559.1674465599123, 548.1518478626821, 525.5953993231326, 529.2132476551402, 528.5076299916001, 530.9784031618108, 512.6021255923857], \"mode\": \"line\", \"name\": \"LASSO each timestep\"}], {\"title\": \"LASSO each timestep\", \"autosize\": false, \"width\": 900, \"height\": 600, \"yaxis\": {\"type\": \"log\", \"autorange\": true}}, {\"showLink\": true, \"linkText\": \"Export to plot.ly\"})});</script>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "BYPqcJmNfkZi",
"outputId": "f4fdb98d-9ede-4f0a-f1f1-2c7c90b93ce1",
"colab": {
"resources": {
"http://localhost:8080/static/components/requirejs/require.js": {
"data": "LyoqIHZpbTogZXQ6dHM9NDpzdz00OnN0cz00CiAqIEBsaWNlbnNlIFJlcXVpcmVKUyAyLjEuMjIgQ29weXJpZ2h0IChjKSAyMDEwLTIwMTUsIFRoZSBEb2pvIEZvdW5kYXRpb24gQWxsIFJpZ2h0cyBSZXNlcnZlZC4KICogQXZhaWxhYmxlIHZpYSB0aGUgTUlUIG9yIG5ldyBCU0QgbGljZW5zZS4KICogc2VlOiBodHRwOi8vZ2l0aHViLmNvbS9qcmJ1cmtlL3JlcXVpcmVqcyBmb3IgZGV0YWlscwogKi8KLy9Ob3QgdXNpbmcgc3RyaWN0OiB1bmV2ZW4gc3RyaWN0IHN1cHBvcnQgaW4gYnJvd3NlcnMsICMzOTIsIGFuZCBjYXVzZXMKLy9wcm9ibGVtcyB3aXRoIHJlcXVpcmVqcy5leGVjKCkvdHJhbnNwaWxlciBwbHVnaW5zIHRoYXQgbWF5IG5vdCBiZSBzdHJpY3QuCi8qanNsaW50IHJlZ2V4cDogdHJ1ZSwgbm9tZW46IHRydWUsIHNsb3BweTogdHJ1ZSAqLwovKmdsb2JhbCB3aW5kb3csIG5hdmlnYXRvciwgZG9jdW1lbnQsIGltcG9ydFNjcmlwdHMsIHNldFRpbWVvdXQsIG9wZXJhICovCgp2YXIgcmVxdWlyZWpzLCByZXF1aXJlLCBkZWZpbmU7CihmdW5jdGlvbiAoZ2xvYmFsKSB7CiAgICB2YXIgcmVxLCBzLCBoZWFkLCBiYXNlRWxlbWVudCwgZGF0YU1haW4sIHNyYywKICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCwgY3VycmVudGx5QWRkaW5nU2NyaXB0LCBtYWluU2NyaXB0LCBzdWJQYXRoLAogICAgICAgIHZlcnNpb24gPSAnMi4xLjIyJywKICAgICAgICBjb21tZW50UmVnRXhwID0gLyhcL1wqKFtcc1xTXSo/KVwqXC98KFteOl18XilcL1wvKC4qKSQpL21nLAogICAgICAgIGNqc1JlcXVpcmVSZWdFeHAgPSAvW14uXVxzKnJlcXVpcmVccypcKFxzKlsiJ10oW14nIlxzXSspWyInXVxzKlwpL2csCiAgICAgICAganNTdWZmaXhSZWdFeHAgPSAvXC5qcyQvLAogICAgICAgIGN1cnJEaXJSZWdFeHAgPSAvXlwuXC8vLAogICAgICAgIG9wID0gT2JqZWN0LnByb3RvdHlwZSwKICAgICAgICBvc3RyaW5nID0gb3AudG9TdHJpbmcsCiAgICAgICAgaGFzT3duID0gb3AuaGFzT3duUHJvcGVydHksCiAgICAgICAgYXAgPSBBcnJheS5wcm90b3R5cGUsCiAgICAgICAgaXNCcm93c2VyID0gISEodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmRvY3VtZW50KSwKICAgICAgICBpc1dlYldvcmtlciA9ICFpc0Jyb3dzZXIgJiYgdHlwZW9mIGltcG9ydFNjcmlwdHMgIT09ICd1bmRlZmluZWQnLAogICAgICAgIC8vUFMzIGluZGljYXRlcyBsb2FkZWQgYW5kIGNvbXBsZXRlLCBidXQgbmVlZCB0byB3YWl0IGZvciBjb21wbGV0ZQogICAgICAgIC8vc3BlY2lmaWNhbGx5LiBTZXF1ZW5jZSBpcyAnbG9hZGluZycsICdsb2FkZWQnLCBleGVjdXRpb24sCiAgICAgICAgLy8gdGhlbiAnY29tcGxldGUnLiBUaGUgVUEgY2hlY2sgaXMgdW5mb3J0dW5hdGUsIGJ1dCBub3Qgc3VyZSBob3cKICAgICAgICAvL3RvIGZlYXR1cmUgdGVzdCB3L28gY2F1c2luZyBwZXJmIGlzc3Vlcy4KICAgICAgICByZWFkeVJlZ0V4cCA9IGlzQnJvd3NlciAmJiBuYXZpZ2F0b3IucGxhdGZvcm0gPT09ICdQTEFZU1RBVElPTiAzJyA/CiAgICAgICAgICAgICAgICAgICAgICAvXmNvbXBsZXRlJC8gOiAvXihjb21wbGV0ZXxsb2FkZWQpJC8sCiAgICAgICAgZGVmQ29udGV4dE5hbWUgPSAnXycsCiAgICAgICAgLy9PaCB0aGUgdHJhZ2VkeSwgZGV0ZWN0aW5nIG9wZXJhLiBTZWUgdGhlIHVzYWdlIG9mIGlzT3BlcmEgZm9yIHJlYXNvbi4KICAgICAgICBpc09wZXJhID0gdHlwZW9mIG9wZXJhICE9PSAndW5kZWZpbmVkJyAmJiBvcGVyYS50b1N0cmluZygpID09PSAnW29iamVjdCBPcGVyYV0nLAogICAgICAgIGNvbnRleHRzID0ge30sCiAgICAgICAgY2ZnID0ge30sCiAgICAgICAgZ2xvYmFsRGVmUXVldWUgPSBbXSwKICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwoKICAgIGZ1bmN0aW9uIGlzRnVuY3Rpb24oaXQpIHsKICAgICAgICByZXR1cm4gb3N0cmluZy5jYWxsKGl0KSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJzsKICAgIH0KCiAgICBmdW5jdGlvbiBpc0FycmF5KGl0KSB7CiAgICAgICAgcmV0dXJuIG9zdHJpbmcuY2FsbChpdCkgPT09ICdbb2JqZWN0IEFycmF5XSc7CiAgICB9CgogICAgLyoqCiAgICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIGl0ZXJhdGluZyBvdmVyIGFuIGFycmF5LiBJZiB0aGUgZnVuYyByZXR1cm5zCiAgICAgKiBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoKGFyeSwgZnVuYykgewogICAgICAgIGlmIChhcnkpIHsKICAgICAgICAgICAgdmFyIGk7CiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBhcnkubGVuZ3RoOyBpICs9IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhlbHBlciBmdW5jdGlvbiBmb3IgaXRlcmF0aW5nIG92ZXIgYW4gYXJyYXkgYmFja3dhcmRzLiBJZiB0aGUgZnVuYwogICAgICogcmV0dXJucyBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoUmV2ZXJzZShhcnksIGZ1bmMpIHsKICAgICAgICBpZiAoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpOwogICAgICAgICAgICBmb3IgKGkgPSBhcnkubGVuZ3RoIC0gMTsgaSA+IC0xOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBoYXNQcm9wKG9iaiwgcHJvcCkgewogICAgICAgIHJldHVybiBoYXNPd24uY2FsbChvYmosIHByb3ApOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldE93bihvYmosIHByb3ApIHsKICAgICAgICByZXR1cm4gaGFzUHJvcChvYmosIHByb3ApICYmIG9ialtwcm9wXTsKICAgIH0KCiAgICAvKioKICAgICAqIEN5Y2xlcyBvdmVyIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGFuZCBjYWxscyBhIGZ1bmN0aW9uIGZvciBlYWNoCiAgICAgKiBwcm9wZXJ0eSB2YWx1ZS4gSWYgdGhlIGZ1bmN0aW9uIHJldHVybnMgYSB0cnV0aHkgdmFsdWUsIHRoZW4gdGhlCiAgICAgKiBpdGVyYXRpb24gaXMgc3RvcHBlZC4KICAgICAqLwogICAgZnVuY3Rpb24gZWFjaFByb3Aob2JqLCBmdW5jKSB7CiAgICAgICAgdmFyIHByb3A7CiAgICAgICAgZm9yIChwcm9wIGluIG9iaikgewogICAgICAgICAgICBpZiAoaGFzUHJvcChvYmosIHByb3ApKSB7CiAgICAgICAgICAgICAgICBpZiAoZnVuYyhvYmpbcHJvcF0sIHByb3ApKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBTaW1wbGUgZnVuY3Rpb24gdG8gbWl4IGluIHByb3BlcnRpZXMgZnJvbSBzb3VyY2UgaW50byB0YXJnZXQsCiAgICAgKiBidXQgb25seSBpZiB0YXJnZXQgZG9lcyBub3QgYWxyZWFkeSBoYXZlIGEgcHJvcGVydHkgb2YgdGhlIHNhbWUgbmFtZS4KICAgICAqLwogICAgZnVuY3Rpb24gbWl4aW4odGFyZ2V0LCBzb3VyY2UsIGZvcmNlLCBkZWVwU3RyaW5nTWl4aW4pIHsKICAgICAgICBpZiAoc291cmNlKSB7CiAgICAgICAgICAgIGVhY2hQcm9wKHNvdXJjZSwgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICBpZiAoZm9yY2UgfHwgIWhhc1Byb3AodGFyZ2V0LCBwcm9wKSkgewogICAgICAgICAgICAgICAgICAgIGlmIChkZWVwU3RyaW5nTWl4aW4gJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAhaXNBcnJheSh2YWx1ZSkgJiYgIWlzRnVuY3Rpb24odmFsdWUpICYmCiAgICAgICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApKSB7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRhcmdldFtwcm9wXSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0ge307CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgbWl4aW4odGFyZ2V0W3Byb3BdLCB2YWx1ZSwgZm9yY2UsIGRlZXBTdHJpbmdNaXhpbik7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0gdmFsdWU7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRhcmdldDsKICAgIH0KCiAgICAvL1NpbWlsYXIgdG8gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQsIGJ1dCB0aGUgJ3RoaXMnIG9iamVjdCBpcyBzcGVjaWZpZWQKICAgIC8vZmlyc3QsIHNpbmNlIGl0IGlzIGVhc2llciB0byByZWFkL2ZpZ3VyZSBvdXQgd2hhdCAndGhpcycgd2lsbCBiZS4KICAgIGZ1bmN0aW9uIGJpbmQob2JqLCBmbikgewogICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHJldHVybiBmbi5hcHBseShvYmosIGFyZ3VtZW50cyk7CiAgICAgICAgfTsKICAgIH0KCiAgICBmdW5jdGlvbiBzY3JpcHRzKCkgewogICAgICAgIHJldHVybiBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7CiAgICB9CgogICAgZnVuY3Rpb24gZGVmYXVsdE9uRXJyb3IoZXJyKSB7CiAgICAgICAgdGhyb3cgZXJyOwogICAgfQoKICAgIC8vQWxsb3cgZ2V0dGluZyBhIGdsb2JhbCB0aGF0IGlzIGV4cHJlc3NlZCBpbgogICAgLy9kb3Qgbm90YXRpb24sIGxpa2UgJ2EuYi5jJy4KICAgIGZ1bmN0aW9uIGdldEdsb2JhbCh2YWx1ZSkgewogICAgICAgIGlmICghdmFsdWUpIHsKICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgIH0KICAgICAgICB2YXIgZyA9IGdsb2JhbDsKICAgICAgICBlYWNoKHZhbHVlLnNwbGl0KCcuJyksIGZ1bmN0aW9uIChwYXJ0KSB7CiAgICAgICAgICAgIGcgPSBnW3BhcnRdOwogICAgICAgIH0pOwogICAgICAgIHJldHVybiBnOwogICAgfQoKICAgIC8qKgogICAgICogQ29uc3RydWN0cyBhbiBlcnJvciB3aXRoIGEgcG9pbnRlciB0byBhbiBVUkwgd2l0aCBtb3JlIGluZm9ybWF0aW9uLgogICAgICogQHBhcmFtIHtTdHJpbmd9IGlkIHRoZSBlcnJvciBJRCB0aGF0IG1hcHMgdG8gYW4gSUQgb24gYSB3ZWIgcGFnZS4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGh1bWFuIHJlYWRhYmxlIGVycm9yLgogICAgICogQHBhcmFtIHtFcnJvcn0gW2Vycl0gdGhlIG9yaWdpbmFsIGVycm9yLCBpZiB0aGVyZSBpcyBvbmUuCiAgICAgKgogICAgICogQHJldHVybnMge0Vycm9yfQogICAgICovCiAgICBmdW5jdGlvbiBtYWtlRXJyb3IoaWQsIG1zZywgZXJyLCByZXF1aXJlTW9kdWxlcykgewogICAgICAgIHZhciBlID0gbmV3IEVycm9yKG1zZyArICdcbmh0dHA6Ly9yZXF1aXJlanMub3JnL2RvY3MvZXJyb3JzLmh0bWwjJyArIGlkKTsKICAgICAgICBlLnJlcXVpcmVUeXBlID0gaWQ7CiAgICAgICAgZS5yZXF1aXJlTW9kdWxlcyA9IHJlcXVpcmVNb2R1bGVzOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgZS5vcmlnaW5hbEVycm9yID0gZXJyOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZTsKICAgIH0KCiAgICBpZiAodHlwZW9mIGRlZmluZSAhPT0gJ3VuZGVmaW5lZCcpIHsKICAgICAgICAvL0lmIGEgZGVmaW5lIGlzIGFscmVhZHkgaW4gcGxheSB2aWEgYW5vdGhlciBBTUQgbG9hZGVyLAogICAgICAgIC8vZG8gbm90IG92ZXJ3cml0ZS4KICAgICAgICByZXR1cm47CiAgICB9CgogICAgaWYgKHR5cGVvZiByZXF1aXJlanMgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgaWYgKGlzRnVuY3Rpb24ocmVxdWlyZWpzKSkgewogICAgICAgICAgICAvL0RvIG5vdCBvdmVyd3JpdGUgYW4gZXhpc3RpbmcgcmVxdWlyZWpzIGluc3RhbmNlLgogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNmZyA9IHJlcXVpcmVqczsKICAgICAgICByZXF1aXJlanMgPSB1bmRlZmluZWQ7CiAgICB9CgogICAgLy9BbGxvdyBmb3IgYSByZXF1aXJlIGNvbmZpZyBvYmplY3QKICAgIGlmICh0eXBlb2YgcmVxdWlyZSAhPT0gJ3VuZGVmaW5lZCcgJiYgIWlzRnVuY3Rpb24ocmVxdWlyZSkpIHsKICAgICAgICAvL2Fzc3VtZSBpdCBpcyBhIGNvbmZpZyBvYmplY3QuCiAgICAgICAgY2ZnID0gcmVxdWlyZTsKICAgICAgICByZXF1aXJlID0gdW5kZWZpbmVkOwogICAgfQoKICAgIGZ1bmN0aW9uIG5ld0NvbnRleHQoY29udGV4dE5hbWUpIHsKICAgICAgICB2YXIgaW5DaGVja0xvYWRlZCwgTW9kdWxlLCBjb250ZXh0LCBoYW5kbGVycywKICAgICAgICAgICAgY2hlY2tMb2FkZWRUaW1lb3V0SWQsCiAgICAgICAgICAgIGNvbmZpZyA9IHsKICAgICAgICAgICAgICAgIC8vRGVmYXVsdHMuIERvIG5vdCBzZXQgYSBkZWZhdWx0IGZvciBtYXAKICAgICAgICAgICAgICAgIC8vY29uZmlnIHRvIHNwZWVkIHVwIG5vcm1hbGl6ZSgpLCB3aGljaAogICAgICAgICAgICAgICAgLy93aWxsIHJ1biBmYXN0ZXIgaWYgdGhlcmUgaXMgbm8gZGVmYXVsdC4KICAgICAgICAgICAgICAgIHdhaXRTZWNvbmRzOiA3LAogICAgICAgICAgICAgICAgYmFzZVVybDogJy4vJywKICAgICAgICAgICAgICAgIHBhdGhzOiB7fSwKICAgICAgICAgICAgICAgIGJ1bmRsZXM6IHt9LAogICAgICAgICAgICAgICAgcGtnczoge30sCiAgICAgICAgICAgICAgICBzaGltOiB7fSwKICAgICAgICAgICAgICAgIGNvbmZpZzoge30KICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgLy9yZWdpc3RyeSBvZiBqdXN0IGVuYWJsZWQgbW9kdWxlcywgdG8gc3BlZWQKICAgICAgICAgICAgLy9jeWNsZSBicmVha2luZyBjb2RlIHdoZW4gbG90cyBvZiBtb2R1bGVzCiAgICAgICAgICAgIC8vYXJlIHJlZ2lzdGVyZWQsIGJ1dCBub3QgYWN0aXZhdGVkLgogICAgICAgICAgICBlbmFibGVkUmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgdW5kZWZFdmVudHMgPSB7fSwKICAgICAgICAgICAgZGVmUXVldWUgPSBbXSwKICAgICAgICAgICAgZGVmaW5lZCA9IHt9LAogICAgICAgICAgICB1cmxGZXRjaGVkID0ge30sCiAgICAgICAgICAgIGJ1bmRsZXNNYXAgPSB7fSwKICAgICAgICAgICAgcmVxdWlyZUNvdW50ZXIgPSAxLAogICAgICAgICAgICB1bm5vcm1hbGl6ZWRDb3VudGVyID0gMTsKCiAgICAgICAgLyoqCiAgICAgICAgICogVHJpbXMgdGhlIC4gYW5kIC4uIGZyb20gYW4gYXJyYXkgb2YgcGF0aCBzZWdtZW50cy4KICAgICAgICAgKiBJdCB3aWxsIGtlZXAgYSBsZWFkaW5nIHBhdGggc2VnbWVudCBpZiBhIC4uIHdpbGwgYmVjb21lCiAgICAgICAgICogdGhlIGZpcnN0IHBhdGggc2VnbWVudCwgdG8gaGVscCB3aXRoIG1vZHVsZSBuYW1lIGxvb2t1cHMsCiAgICAgICAgICogd2hpY2ggYWN0IGxpa2UgcGF0aHMsIGJ1dCBjYW4gYmUgcmVtYXBwZWQuIEJ1dCB0aGUgZW5kIHJlc3VsdCwKICAgICAgICAgKiBhbGwgcGF0aHMgdGhhdCB1c2UgdGhpcyBmdW5jdGlvbiBzaG91bGQgbG9vayBub3JtYWxpemVkLgogICAgICAgICAqIE5PVEU6IHRoaXMgbWV0aG9kIE1PRElGSUVTIHRoZSBpbnB1dCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnkgdGhlIGFycmF5IG9mIHBhdGggc2VnbWVudHMuCiAgICAgICAgICovCiAgICAgICAgZnVuY3Rpb24gdHJpbURvdHMoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpLCBwYXJ0OwogICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYXJ5Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBwYXJ0ID0gYXJ5W2ldOwogICAgICAgICAgICAgICAgaWYgKHBhcnQgPT09ICcuJykgewogICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSwgMSk7CiAgICAgICAgICAgICAgICAgICAgaSAtPSAxOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0ID09PSAnLi4nKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gSWYgYXQgdGhlIHN0YXJ0LCBvciBwcmV2aW91cyB2YWx1ZSBpcyBzdGlsbCAuLiwKICAgICAgICAgICAgICAgICAgICAvLyBrZWVwIHRoZW0gc28gdGhhdCB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGggaXQgbWF5CiAgICAgICAgICAgICAgICAgICAgLy8gc3RpbGwgd29yayB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGgsIGV2ZW4gdGhvdWdoCiAgICAgICAgICAgICAgICAgICAgLy8gYXMgYW4gSUQgaXQgaXMgbGVzcyB0aGFuIGlkZWFsLiBJbiBsYXJnZXIgcG9pbnQKICAgICAgICAgICAgICAgICAgICAvLyByZWxlYXNlcywgbWF5IGJlIGJldHRlciB0byBqdXN0IGtpY2sgb3V0IGFuIGVycm9yLgogICAgICAgICAgICAgICAgICAgIGlmIChpID09PSAwIHx8IChpID09PSAxICYmIGFyeVsyXSA9PT0gJy4uJykgfHwgYXJ5W2kgLSAxXSA9PT0gJy4uJykgewogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSAtIDEsIDIpOwogICAgICAgICAgICAgICAgICAgICAgICBpIC09IDI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHaXZlbiBhIHJlbGF0aXZlIG1vZHVsZSBuYW1lLCBsaWtlIC4vc29tZXRoaW5nLCBub3JtYWxpemUgaXQgdG8KICAgICAgICAgKiBhIHJlYWwgbmFtZSB0aGF0IGNhbiBiZSBtYXBwZWQgdG8gYSBwYXRoLgogICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSByZWxhdGl2ZSBuYW1lCiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGJhc2VOYW1lIGEgcmVhbCBuYW1lIHRoYXQgdGhlIG5hbWUgYXJnIGlzIHJlbGF0aXZlCiAgICAgICAgICogdG8uCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBhcHBseU1hcCBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgdmFsdWUuIFNob3VsZAogICAgICAgICAqIG9ubHkgYmUgZG9uZSBpZiB0aGlzIG5vcm1hbGl6YXRpb24gaXMgZm9yIGEgZGVwZW5kZW5jeSBJRC4KICAgICAgICAgKiBAcmV0dXJucyB7U3RyaW5nfSBub3JtYWxpemVkIG5hbWUKICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBub3JtYWxpemUobmFtZSwgYmFzZU5hbWUsIGFwcGx5TWFwKSB7CiAgICAgICAgICAgIHZhciBwa2dNYWluLCBtYXBWYWx1ZSwgbmFtZVBhcnRzLCBpLCBqLCBuYW1lU2VnbWVudCwgbGFzdEluZGV4LAogICAgICAgICAgICAgICAgZm91bmRNYXAsIGZvdW5kSSwgZm91bmRTdGFyTWFwLCBzdGFySSwgbm9ybWFsaXplZEJhc2VQYXJ0cywKICAgICAgICAgICAgICAgIGJhc2VQYXJ0cyA9IChiYXNlTmFtZSAmJiBiYXNlTmFtZS5zcGxpdCgnLycpKSwKICAgICAgICAgICAgICAgIG1hcCA9IGNvbmZpZy5tYXAsCiAgICAgICAgICAgICAgICBzdGFyTWFwID0gbWFwICYmIG1hcFsnKiddOwoKICAgICAgICAgICAgLy9BZGp1c3QgYW55IHJlbGF0aXZlIHBhdGhzLgogICAgICAgICAgICBpZiAobmFtZSkgewogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3BsaXQoJy8nKTsKICAgICAgICAgICAgICAgIGxhc3RJbmRleCA9IG5hbWUubGVuZ3RoIC0gMTsKCiAgICAgICAgICAgICAgICAvLyBJZiB3YW50aW5nIG5vZGUgSUQgY29tcGF0aWJpbGl0eSwgc3RyaXAgLmpzIGZyb20gZW5kCiAgICAgICAgICAgICAgICAvLyBvZiBJRHMuIEhhdmUgdG8gZG8gdGhpcyBoZXJlLCBhbmQgbm90IGluIG5hbWVUb1VybAogICAgICAgICAgICAgICAgLy8gYmVjYXVzZSBub2RlIGFsbG93cyBlaXRoZXIgLmpzIG9yIG5vbiAuanMgdG8gbWFwCiAgICAgICAgICAgICAgICAvLyB0byBzYW1lIGZpbGUuCiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm5vZGVJZENvbXBhdCAmJiBqc1N1ZmZpeFJlZ0V4cC50ZXN0KG5hbWVbbGFzdEluZGV4XSkpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lW2xhc3RJbmRleF0gPSBuYW1lW2xhc3RJbmRleF0ucmVwbGFjZShqc1N1ZmZpeFJlZ0V4cCwgJycpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIFN0YXJ0cyB3aXRoIGEgJy4nIHNvIG5lZWQgdGhlIGJhc2VOYW1lCiAgICAgICAgICAgICAgICBpZiAobmFtZVswXS5jaGFyQXQoMCkgPT09ICcuJyAmJiBiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAvL0NvbnZlcnQgYmFzZU5hbWUgdG8gYXJyYXksIGFuZCBsb3Agb2ZmIHRoZSBsYXN0IHBhcnQsCiAgICAgICAgICAgICAgICAgICAgLy9zbyB0aGF0IC4gbWF0Y2hlcyB0aGF0ICdkaXJlY3RvcnknIGFuZCBub3QgbmFtZSBvZiB0aGUgYmFzZU5hbWUncwogICAgICAgICAgICAgICAgICAgIC8vbW9kdWxlLiBGb3IgaW5zdGFuY2UsIGJhc2VOYW1lIG9mICdvbmUvdHdvL3RocmVlJywgbWFwcyB0bwogICAgICAgICAgICAgICAgICAgIC8vJ29uZS90d28vdGhyZWUuanMnLCBidXQgd2Ugd2FudCB0aGUgZGlyZWN0b3J5LCAnb25lL3R3bycgZm9yCiAgICAgICAgICAgICAgICAgICAgLy90aGlzIG5vcm1hbGl6YXRpb24uCiAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZEJhc2VQYXJ0cyA9IGJhc2VQYXJ0cy5zbGljZSgwLCBiYXNlUGFydHMubGVuZ3RoIC0gMSk7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vcm1hbGl6ZWRCYXNlUGFydHMuY29uY2F0KG5hbWUpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHRyaW1Eb3RzKG5hbWUpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuam9pbignLycpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL0FwcGx5IG1hcCBjb25maWcgaWYgYXZhaWxhYmxlLgogICAgICAgICAgICBpZiAoYXBwbHlNYXAgJiYgbWFwICYmIChiYXNlUGFydHMgfHwgc3Rhck1hcCkpIHsKICAgICAgICAgICAgICAgIG5hbWVQYXJ0cyA9IG5hbWUuc3BsaXQoJy8nKTsKCiAgICAgICAgICAgICAgICBvdXRlckxvb3A6IGZvciAoaSA9IG5hbWVQYXJ0cy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lU2VnbWVudCA9IG5hbWVQYXJ0cy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9GaW5kIHRoZSBsb25nZXN0IGJhc2VOYW1lIHNlZ21lbnQgbWF0Y2ggaW4gdGhlIGNvbmZpZy4KICAgICAgICAgICAgICAgICAgICAgICAgLy9TbywgZG8gam9pbnMgb24gdGhlIGJpZ2dlc3QgdG8gc21hbGxlc3QgbGVuZ3RocyBvZiBiYXNlUGFydHMuCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaiA9IGJhc2VQYXJ0cy5sZW5ndGg7IGogPiAwOyBqIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcFZhbHVlID0gZ2V0T3duKG1hcCwgYmFzZVBhcnRzLnNsaWNlKDAsIGopLmpvaW4oJy8nKSk7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iYXNlTmFtZSBzZWdtZW50IGhhcyBjb25maWcsIGZpbmQgaWYgaXQgaGFzIG9uZSBmb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hcFZhbHVlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwVmFsdWUgPSBnZXRPd24obWFwVmFsdWUsIG5hbWVTZWdtZW50KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWFwVmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXRjaCwgdXBkYXRlIG5hbWUgdG8gdGhlIG5ldyB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRNYXAgPSBtYXBWYWx1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRJID0gaTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsgb3V0ZXJMb29wOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9DaGVjayBmb3IgYSBzdGFyIG1hcCBtYXRjaCwgYnV0IGp1c3QgaG9sZCBvbiB0byBpdCwKICAgICAgICAgICAgICAgICAgICAvL2lmIHRoZXJlIGlzIGEgc2hvcnRlciBzZWdtZW50IG1hdGNoIGxhdGVyIGluIGEgbWF0Y2hpbmcKICAgICAgICAgICAgICAgICAgICAvL2NvbmZpZywgdGhlbiBmYXZvciBvdmVyIHRoaXMgc3RhciBtYXAuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFmb3VuZFN0YXJNYXAgJiYgc3Rhck1hcCAmJiBnZXRPd24oc3Rhck1hcCwgbmFtZVNlZ21lbnQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvdW5kU3Rhck1hcCA9IGdldE93bihzdGFyTWFwLCBuYW1lU2VnbWVudCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJJID0gaTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFmb3VuZE1hcCAmJiBmb3VuZFN0YXJNYXApIHsKICAgICAgICAgICAgICAgICAgICBmb3VuZE1hcCA9IGZvdW5kU3Rhck1hcDsKICAgICAgICAgICAgICAgICAgICBmb3VuZEkgPSBzdGFySTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBpZiAoZm91bmRNYXApIHsKICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMuc3BsaWNlKDAsIGZvdW5kSSwgZm91bmRNYXApOwogICAgICAgICAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHMuam9pbignLycpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBJZiB0aGUgbmFtZSBwb2ludHMgdG8gYSBwYWNrYWdlJ3MgbmFtZSwgdXNlCiAgICAgICAgICAgIC8vIHRoZSBwYWNrYWdlIG1haW4gaW5zdGVhZC4KICAgICAgICAgICAgcGtnTWFpbiA9IGdldE93bihjb25maWcucGtncywgbmFtZSk7CgogICAgICAgICAgICByZXR1cm4gcGtnTWFpbiA/IHBrZ01haW4gOiBuYW1lOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gcmVtb3ZlU2NyaXB0KG5hbWUpIHsKICAgICAgICAgICAgaWYgKGlzQnJvd3NlcikgewogICAgICAgICAgICAgICAgZWFjaChzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHROb2RlKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKHNjcmlwdE5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKSA9PT0gbmFtZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NyaXB0Tm9kZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcmVxdWlyZWNvbnRleHQnKSA9PT0gY29udGV4dC5jb250ZXh0TmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzY3JpcHROb2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoc2NyaXB0Tm9kZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBoYXNQYXRoRmFsbGJhY2soaWQpIHsKICAgICAgICAgICAgdmFyIHBhdGhDb25maWcgPSBnZXRPd24oY29uZmlnLnBhdGhzLCBpZCk7CiAgICAgICAgICAgIGlmIChwYXRoQ29uZmlnICYmIGlzQXJyYXkocGF0aENvbmZpZykgJiYgcGF0aENvbmZpZy5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAvL1BvcCBvZmYgdGhlIGZpcnN0IGFycmF5IHZhbHVlLCBzaW5jZSBpdCBmYWlsZWQsIGFuZAogICAgICAgICAgICAgICAgLy9yZXRyeQogICAgICAgICAgICAgICAgcGF0aENvbmZpZy5zaGlmdCgpOwogICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlLnVuZGVmKGlkKTsKCiAgICAgICAgICAgICAgICAvL0N1c3RvbSByZXF1aXJlIHRoYXQgZG9lcyBub3QgZG8gbWFwIHRyYW5zbGF0aW9uLCBzaW5jZQogICAgICAgICAgICAgICAgLy9JRCBpcyAiYWJzb2x1dGUiLCBhbHJlYWR5IG1hcHBlZC9yZXNvbHZlZC4KICAgICAgICAgICAgICAgIGNvbnRleHQubWFrZVJlcXVpcmUobnVsbCwgewogICAgICAgICAgICAgICAgICAgIHNraXBNYXA6IHRydWUKICAgICAgICAgICAgICAgIH0pKFtpZF0pOwoKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvL1R1cm5zIGEgcGx1Z2luIXJlc291cmNlIHRvIFtwbHVnaW4sIHJlc291cmNlXQogICAgICAgIC8vd2l0aCB0aGUgcGx1Z2luIGJlaW5nIHVuZGVmaW5lZCBpZiB0aGUgbmFtZQogICAgICAgIC8vZGlkIG5vdCBoYXZlIGEgcGx1Z2luIHByZWZpeC4KICAgICAgICBmdW5jdGlvbiBzcGxpdFByZWZpeChuYW1lKSB7CiAgICAgICAgICAgIHZhciBwcmVmaXgsCiAgICAgICAgICAgICAgICBpbmRleCA9IG5hbWUgPyBuYW1lLmluZGV4T2YoJyEnKSA6IC0xOwogICAgICAgICAgICBpZiAoaW5kZXggPiAtMSkgewogICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZS5zdWJzdHJpbmcoMCwgaW5kZXgpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyaW5nKGluZGV4ICsgMSwgbmFtZS5sZW5ndGgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBbcHJlZml4LCBuYW1lXTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBtb2R1bGUgbWFwcGluZyB0aGF0IGluY2x1ZGVzIHBsdWdpbiBwcmVmaXgsIG1vZHVsZQogICAgICAgICAqIG5hbWUsIGFuZCBwYXRoLiBJZiBwYXJlbnRNb2R1bGVNYXAgaXMgcHJvdmlkZWQgaXQgd2lsbAogICAgICAgICAqIGFsc28gbm9ybWFsaXplIHRoZSBuYW1lIHZpYSByZXF1aXJlLm5vcm1hbGl6ZSgpCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSB0aGUgbW9kdWxlIG5hbWUKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gW3BhcmVudE1vZHVsZU1hcF0gcGFyZW50IG1vZHVsZSBtYXAKICAgICAgICAgKiBmb3IgdGhlIG1vZHVsZSBuYW1lLCB1c2VkIHRvIHJlc29sdmUgcmVsYXRpdmUgbmFtZXMuCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBpc05vcm1hbGl6ZWQ6IGlzIHRoZSBJRCBhbHJlYWR5IG5vcm1hbGl6ZWQuCiAgICAgICAgICogVGhpcyBpcyB0cnVlIGlmIHRoaXMgY2FsbCBpcyBkb25lIGZvciBhIGRlZmluZSgpIG1vZHVsZSBJRC4KICAgICAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGx5TWFwOiBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgSUQuCiAgICAgICAgICogU2hvdWxkIG9ubHkgYmUgdHJ1ZSBpZiB0aGlzIG1hcCBpcyBmb3IgYSBkZXBlbmRlbmN5LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge09iamVjdH0KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBtYWtlTW9kdWxlTWFwKG5hbWUsIHBhcmVudE1vZHVsZU1hcCwgaXNOb3JtYWxpemVkLCBhcHBseU1hcCkgewogICAgICAgICAgICB2YXIgdXJsLCBwbHVnaW5Nb2R1bGUsIHN1ZmZpeCwgbmFtZVBhcnRzLAogICAgICAgICAgICAgICAgcHJlZml4ID0gbnVsbCwKICAgICAgICAgICAgICAgIHBhcmVudE5hbWUgPSBwYXJlbnRNb2R1bGVNYXAgPyBwYXJlbnRNb2R1bGVNYXAubmFtZSA6IG51bGwsCiAgICAgICAgICAgICAgICBvcmlnaW5hbE5hbWUgPSBuYW1lLAogICAgICAgICAgICAgICAgaXNEZWZpbmUgPSB0cnVlLAogICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUgPSAnJzsKCiAgICAgICAgICAgIC8vSWYgbm8gbmFtZSwgdGhlbiBpdCBtZWFucyBpdCBpcyBhIHJlcXVpcmUgY2FsbCwgZ2VuZXJhdGUgYW4KICAgICAgICAgICAgLy9pbnRlcm5hbCBuYW1lLgogICAgICAgICAgICBpZiAoIW5hbWUpIHsKICAgICAgICAgICAgICAgIGlzRGVmaW5lID0gZmFsc2U7CiAgICAgICAgICAgICAgICBuYW1lID0gJ19AcicgKyAocmVxdWlyZUNvdW50ZXIgKz0gMSk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIG5hbWVQYXJ0cyA9IHNwbGl0UHJlZml4KG5hbWUpOwogICAgICAgICAgICBwcmVmaXggPSBuYW1lUGFydHNbMF07CiAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHNbMV07CgogICAgICAgICAgICBpZiAocHJlZml4KSB7CiAgICAgICAgICAgICAgICBwcmVmaXggPSBub3JtYWxpemUocHJlZml4LCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICBwbHVnaW5Nb2R1bGUgPSBnZXRPd24oZGVmaW5lZCwgcHJlZml4KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9BY2NvdW50IGZvciByZWxhdGl2ZSBwYXRocyBpZiB0aGVyZSBpcyBhIGJhc2UgbmFtZS4KICAgICAgICAgICAgaWYgKG5hbWUpIHsKICAgICAgICAgICAgICAgIGlmIChwcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICBpZiAocGx1Z2luTW9kdWxlICYmIHBsdWdpbk1vZHVsZS5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9QbHVnaW4gaXMgbG9hZGVkLCB1c2UgaXRzIG5vcm1hbGl6ZSBtZXRob2QuCiAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gcGx1Z2luTW9kdWxlLm5vcm1hbGl6ZShuYW1lLCBmdW5jdGlvbiAobmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIG5lc3RlZCBwbHVnaW4gcmVmZXJlbmNlcywgdGhlbiBkbyBub3QgdHJ5IHRvCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSwgYXMgaXQgd2lsbCBub3Qgbm9ybWFsaXplIGNvcnJlY3RseS4gVGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvLyBwbGFjZXMgYSByZXN0cmljdGlvbiBvbiByZXNvdXJjZUlkcywgYW5kIHRoZSBsb25nZXIKICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGVybSBzb2x1dGlvbiBpcyBub3QgdG8gbm9ybWFsaXplIHVudGlsIHBsdWdpbnMgYXJlCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvYWRlZCBhbmQgYWxsIG5vcm1hbGl6YXRpb25zIHRvIGFsbG93IGZvciBhc3luYwogICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2FkaW5nIG9mIGEgbG9hZGVyIHBsdWdpbi4gQnV0IGZvciBub3csIGZpeGVzIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAvLyBjb21tb24gdXNlcy4gRGV0YWlscyBpbiAjMTEzMQogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5hbWUuaW5kZXhPZignIScpID09PSAtMSA/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplKG5hbWUsIHBhcmVudE5hbWUsIGFwcGx5TWFwKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIC8vQSByZWd1bGFyIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CgogICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplZCBuYW1lIG1heSBiZSBhIHBsdWdpbiBJRCBkdWUgdG8gbWFwIGNvbmZpZwogICAgICAgICAgICAgICAgICAgIC8vYXBwbGljYXRpb24gaW4gbm9ybWFsaXplLiBUaGUgbWFwIGNvbmZpZyB2YWx1ZXMgbXVzdAogICAgICAgICAgICAgICAgICAgIC8vYWxyZWFkeSBiZSBub3JtYWxpemVkLCBzbyBkbyBub3QgbmVlZCB0byByZWRvIHRoYXQgcGFydC4KICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMgPSBzcGxpdFByZWZpeChub3JtYWxpemVkTmFtZSk7CiAgICAgICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZVBhcnRzWzBdOwogICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gbmFtZVBhcnRzWzFdOwogICAgICAgICAgICAgICAgICAgIGlzTm9ybWFsaXplZCA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIHVybCA9IGNvbnRleHQubmFtZVRvVXJsKG5vcm1hbGl6ZWROYW1lKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiB0aGUgaWQgaXMgYSBwbHVnaW4gaWQgdGhhdCBjYW5ub3QgYmUgZGV0ZXJtaW5lZCBpZiBpdCBuZWVkcwogICAgICAgICAgICAvL25vcm1hbGl6YXRpb24sIHN0YW1wIGl0IHdpdGggYSB1bmlxdWUgSUQgc28gdHdvIG1hdGNoaW5nIHJlbGF0aXZlCiAgICAgICAgICAgIC8vaWRzIHRoYXQgbWF5IGNvbmZsaWN0IGNhbiBiZSBzZXBhcmF0ZS4KICAgICAgICAgICAgc3VmZml4ID0gcHJlZml4ICYmICFwbHVnaW5Nb2R1bGUgJiYgIWlzTm9ybWFsaXplZCA/CiAgICAgICAgICAgICAgICAgICAgICdfdW5ub3JtYWxpemVkJyArICh1bm5vcm1hbGl6ZWRDb3VudGVyICs9IDEpIDoKICAgICAgICAgICAgICAgICAgICAgJyc7CgogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcHJlZml4OiBwcmVmaXgsCiAgICAgICAgICAgICAgICBuYW1lOiBub3JtYWxpemVkTmFtZSwKICAgICAgICAgICAgICAgIHBhcmVudE1hcDogcGFyZW50TW9kdWxlTWFwLAogICAgICAgICAgICAgICAgdW5ub3JtYWxpemVkOiAhIXN1ZmZpeCwKICAgICAgICAgICAgICAgIHVybDogdXJsLAogICAgICAgICAgICAgICAgb3JpZ2luYWxOYW1lOiBvcmlnaW5hbE5hbWUsCiAgICAgICAgICAgICAgICBpc0RlZmluZTogaXNEZWZpbmUsCiAgICAgICAgICAgICAgICBpZDogKHByZWZpeCA/CiAgICAgICAgICAgICAgICAgICAgICAgIHByZWZpeCArICchJyArIG5vcm1hbGl6ZWROYW1lIDoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUpICsgc3VmZml4CiAgICAgICAgICAgIH07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBnZXRNb2R1bGUoZGVwTWFwKSB7CiAgICAgICAgICAgIHZhciBpZCA9IGRlcE1hcC5pZCwKICAgICAgICAgICAgICAgIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwoKICAgICAgICAgICAgaWYgKCFtb2QpIHsKICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXSA9IG5ldyBjb250ZXh0Lk1vZHVsZShkZXBNYXApOwogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gbW9kOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gb24oZGVwTWFwLCBuYW1lLCBmbikgewogICAgICAgICAgICB2YXIgaWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIGlkKTsKCiAgICAgICAgICAgIGlmIChoYXNQcm9wKGRlZmluZWQsIGlkKSAmJgogICAgICAgICAgICAgICAgICAgICghbW9kIHx8IG1vZC5kZWZpbmVFbWl0Q29tcGxldGUpKSB7CiAgICAgICAgICAgICAgICBpZiAobmFtZSA9PT0gJ2RlZmluZWQnKSB7CiAgICAgICAgICAgICAgICAgICAgZm4oZGVmaW5lZFtpZF0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgbW9kID0gZ2V0TW9kdWxlKGRlcE1hcCk7CiAgICAgICAgICAgICAgICBpZiAobW9kLmVycm9yICYmIG5hbWUgPT09ICdlcnJvcicpIHsKICAgICAgICAgICAgICAgICAgICBmbihtb2QuZXJyb3IpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBtb2Qub24obmFtZSwgZm4pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBvbkVycm9yKGVyciwgZXJyYmFjaykgewogICAgICAgICAgICB2YXIgaWRzID0gZXJyLnJlcXVpcmVNb2R1bGVzLAogICAgICAgICAgICAgICAgbm90aWZpZWQgPSBmYWxzZTsKCiAgICAgICAgICAgIGlmIChlcnJiYWNrKSB7CiAgICAgICAgICAgICAgICBlcnJiYWNrKGVycik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBlYWNoKGlkcywgZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwogICAgICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9TZXQgZXJyb3Igb24gbW9kdWxlLCBzbyBpdCBza2lwcyB0aW1lb3V0IGNoZWNrcy4KICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVycm9yID0gZXJyOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90aWZpZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIGlmICghbm90aWZpZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdG8gdHJhbnNmZXIgZ2xvYmFsUXVldWUgaXRlbXMgdG8gdGhpcyBjb250ZXh0J3MKICAgICAgICAgKiBkZWZRdWV1ZS4KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiB0YWtlR2xvYmFsUXVldWUoKSB7CiAgICAgICAgICAgIC8vUHVzaCBhbGwgdGhlIGdsb2JhbERlZlF1ZXVlIGl0ZW1zIGludG8gdGhlIGNvbnRleHQncyBkZWZRdWV1ZQogICAgICAgICAgICBpZiAoZ2xvYmFsRGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBlYWNoKGdsb2JhbERlZlF1ZXVlLCBmdW5jdGlvbihxdWV1ZUl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQgPSBxdWV1ZUl0ZW1bMF07CiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcFtpZF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBkZWZRdWV1ZS5wdXNoKHF1ZXVlSXRlbSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGdsb2JhbERlZlF1ZXVlID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGhhbmRsZXJzID0gewogICAgICAgICAgICAncmVxdWlyZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QucmVxdWlyZSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBtb2QucmVxdWlyZTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChtb2QucmVxdWlyZSA9IGNvbnRleHQubWFrZVJlcXVpcmUobW9kLm1hcCkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAnZXhwb3J0cyc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIG1vZC51c2luZ0V4cG9ydHMgPSB0cnVlOwogICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChkZWZpbmVkW21vZC5tYXAuaWRdID0gbW9kLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLmV4cG9ydHMgPSBkZWZpbmVkW21vZC5tYXAuaWRdID0ge30pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgJ21vZHVsZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QubW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vZC5tb2R1bGU7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLm1vZHVsZSA9IHsKICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IG1vZC5tYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIHVyaTogbW9kLm1hcC51cmwsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZzogZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdldE93bihjb25maWcuY29uZmlnLCBtb2QubWFwLmlkKSB8fCB7fTsKICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0czogbW9kLmV4cG9ydHMgfHwgKG1vZC5leHBvcnRzID0ge30pCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjbGVhblJlZ2lzdHJ5KGlkKSB7CiAgICAgICAgICAgIC8vQ2xlYW4gdXAgbWFjaGluZXJ5IHVzZWQgZm9yIHdhaXRpbmcgbW9kdWxlcy4KICAgICAgICAgICAgZGVsZXRlIHJlZ2lzdHJ5W2lkXTsKICAgICAgICAgICAgZGVsZXRlIGVuYWJsZWRSZWdpc3RyeVtpZF07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBicmVha0N5Y2xlKG1vZCwgdHJhY2VkLCBwcm9jZXNzZWQpIHsKICAgICAgICAgICAgdmFyIGlkID0gbW9kLm1hcC5pZDsKCiAgICAgICAgICAgIGlmIChtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgIG1vZC5lbWl0KCdlcnJvcicsIG1vZC5lcnJvcik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB0cmFjZWRbaWRdID0gdHJ1ZTsKICAgICAgICAgICAgICAgIGVhY2gobW9kLmRlcE1hcHMsIGZ1bmN0aW9uIChkZXBNYXAsIGkpIHsKICAgICAgICAgICAgICAgICAgICB2YXIgZGVwSWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlcCA9IGdldE93bihyZWdpc3RyeSwgZGVwSWQpOwoKICAgICAgICAgICAgICAgICAgICAvL09ubHkgZm9yY2UgdGhpbmdzIHRoYXQgaGF2ZSBub3QgY29tcGxldGVkCiAgICAgICAgICAgICAgICAgICAgLy9iZWluZyBkZWZpbmVkLCBzbyBzdGlsbCBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAgICAgLy9hbmQgb25seSBpZiBpdCBoYXMgbm90IGJlZW4gbWF0Y2hlZCB1cAogICAgICAgICAgICAgICAgICAgIC8vaW4gdGhlIG1vZHVsZSBhbHJlYWR5LgogICAgICAgICAgICAgICAgICAgIGlmIChkZXAgJiYgIW1vZC5kZXBNYXRjaGVkW2ldICYmICFwcm9jZXNzZWRbZGVwSWRdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChnZXRPd24odHJhY2VkLCBkZXBJZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZC5kZWZpbmVEZXAoaSwgZGVmaW5lZFtkZXBJZF0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmNoZWNrKCk7IC8vcGFzcyBmYWxzZT8KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrQ3ljbGUoZGVwLCB0cmFjZWQsIHByb2Nlc3NlZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHByb2Nlc3NlZFtpZF0gPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBjaGVja0xvYWRlZCgpIHsKICAgICAgICAgICAgdmFyIGVyciwgdXNpbmdQYXRoRmFsbGJhY2ssCiAgICAgICAgICAgICAgICB3YWl0SW50ZXJ2YWwgPSBjb25maWcud2FpdFNlY29uZHMgKiAxMDAwLAogICAgICAgICAgICAgICAgLy9JdCBpcyBwb3NzaWJsZSB0byBkaXNhYmxlIHRoZSB3YWl0IGludGVydmFsIGJ5IHVzaW5nIHdhaXRTZWNvbmRzIG9mIDAuCiAgICAgICAgICAgICAgICBleHBpcmVkID0gd2FpdEludGVydmFsICYmIChjb250ZXh0LnN0YXJ0VGltZSArIHdhaXRJbnRlcnZhbCkgPCBuZXcgRGF0ZSgpLmdldFRpbWUoKSwKICAgICAgICAgICAgICAgIG5vTG9hZHMgPSBbXSwKICAgICAgICAgICAgICAgIHJlcUNhbGxzID0gW10sCiAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSBmYWxzZSwKICAgICAgICAgICAgICAgIG5lZWRDeWNsZUNoZWNrID0gdHJ1ZTsKCiAgICAgICAgICAgIC8vRG8gbm90IGJvdGhlciBpZiB0aGlzIGNhbGwgd2FzIGEgcmVzdWx0IG9mIGEgY3ljbGUgYnJlYWsuCiAgICAgICAgICAgIGlmIChpbkNoZWNrTG9hZGVkKSB7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGluQ2hlY2tMb2FkZWQgPSB0cnVlOwoKICAgICAgICAgICAgLy9GaWd1cmUgb3V0IHRoZSBzdGF0ZSBvZiBhbGwgdGhlIG1vZHVsZXMuCiAgICAgICAgICAgIGVhY2hQcm9wKGVuYWJsZWRSZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgdmFyIG1hcCA9IG1vZC5tYXAsCiAgICAgICAgICAgICAgICAgICAgbW9kSWQgPSBtYXAuaWQ7CgogICAgICAgICAgICAgICAgLy9Ta2lwIHRoaW5ncyB0aGF0IGFyZSBub3QgZW5hYmxlZCBvciBpbiBlcnJvciBzdGF0ZS4KICAgICAgICAgICAgICAgIGlmICghbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICByZXFDYWxscy5wdXNoKG1vZCk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIHRoZSBtb2R1bGUgc2hvdWxkIGJlIGV4ZWN1dGVkLCBhbmQgaXQgaGFzIG5vdAogICAgICAgICAgICAgICAgICAgIC8vYmVlbiBpbml0ZWQgYW5kIHRpbWUgaXMgdXAsIHJlbWVtYmVyIGl0LgogICAgICAgICAgICAgICAgICAgIGlmICghbW9kLmluaXRlZCAmJiBleHBpcmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoYXNQYXRoRmFsbGJhY2sobW9kSWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2luZ1BhdGhGYWxsYmFjayA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9Mb2Fkcy5wdXNoKG1vZElkKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChtb2RJZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFtb2QuaW5pdGVkICYmIG1vZC5mZXRjaGVkICYmIG1hcC5pc0RlZmluZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW1hcC5wcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vTm8gcmVhc29uIHRvIGtlZXAgbG9va2luZyBmb3IgdW5maW5pc2hlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9sb2FkaW5nLiBJZiB0aGUgb25seSBzdGlsbExvYWRpbmcgaXMgYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9wbHVnaW4gcmVzb3VyY2UgdGhvdWdoLCBrZWVwIGdvaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iZWNhdXNlIGl0IG1heSBiZSB0aGF0IGEgcGx1Z2luIHJlc291cmNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL2lzIHdhaXRpbmcgb24gYSBub24tcGx1Z2luIGN5Y2xlLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChuZWVkQ3ljbGVDaGVjayA9IGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CgogICAgICAgICAgICBpZiAoZXhwaXJlZCAmJiBub0xvYWRzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgLy9JZiB3YWl0IHRpbWUgZXhwaXJlZCwgdGhyb3cgZXJyb3Igb2YgdW5sb2FkZWQgbW9kdWxlcy4KICAgICAgICAgICAgICAgIGVyciA9IG1ha2VFcnJvcigndGltZW91dCcsICdMb2FkIHRpbWVvdXQgZm9yIG1vZHVsZXM6ICcgKyBub0xvYWRzLCBudWxsLCBub0xvYWRzKTsKICAgICAgICAgICAgICAgIGVyci5jb250ZXh0TmFtZSA9IGNvbnRleHQuY29udGV4dE5hbWU7CiAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihlcnIpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL05vdCBleHBpcmVkLCBjaGVjayBmb3IgYSBjeWNsZS4KICAgICAgICAgICAgaWYgKG5lZWRDeWNsZUNoZWNrKSB7CiAgICAgICAgICAgICAgICBlYWNoKHJlcUNhbGxzLCBmdW5jdGlvbiAobW9kKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWtDeWNsZShtb2QsIHt9LCB7fSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiBzdGlsbCB3YWl0aW5nIG9uIGxvYWRzLCBhbmQgdGhlIHdhaXRpbmcgbG9hZCBpcyBzb21ldGhpbmcKICAgICAgICAgICAgLy9vdGhlciB0aGFuIGEgcGx1Z2luIHJlc291cmNlLCBvciB0aGVyZSBhcmUgc3RpbGwgb3V0c3RhbmRpbmcKICAgICAgICAgICAgLy9zY3JpcHRzLCB0aGVuIGp1c3QgdHJ5IGJhY2sgbGF0ZXIuCiAgICAgICAgICAgIGlmICgoIWV4cGlyZWQgfHwgdXNpbmdQYXRoRmFsbGJhY2spICYmIHN0aWxsTG9hZGluZykgewogICAgICAgICAgICAgICAgLy9Tb21ldGhpbmcgaXMgc3RpbGwgd2FpdGluZyB0byBsb2FkLiBXYWl0IGZvciBpdCwgYnV0IG9ubHkKICAgICAgICAgICAgICAgIC8vaWYgYSB0aW1lb3V0IGlzIG5vdCBhbHJlYWR5IGluIGVmZmVjdC4KICAgICAgICAgICAgICAgIGlmICgoaXNCcm93c2VyIHx8IGlzV2ViV29ya2VyKSAmJiAhY2hlY2tMb2FkZWRUaW1lb3V0SWQpIHsKICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrTG9hZGVkKCk7CiAgICAgICAgICAgICAgICAgICAgfSwgNTApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBpbkNoZWNrTG9hZGVkID0gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICBNb2R1bGUgPSBmdW5jdGlvbiAobWFwKSB7CiAgICAgICAgICAgIHRoaXMuZXZlbnRzID0gZ2V0T3duKHVuZGVmRXZlbnRzLCBtYXAuaWQpIHx8IHt9OwogICAgICAgICAgICB0aGlzLm1hcCA9IG1hcDsKICAgICAgICAgICAgdGhpcy5zaGltID0gZ2V0T3duKGNvbmZpZy5zaGltLCBtYXAuaWQpOwogICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHMgPSBbXTsKICAgICAgICAgICAgdGhpcy5kZXBNYXBzID0gW107CiAgICAgICAgICAgIHRoaXMuZGVwTWF0Y2hlZCA9IFtdOwogICAgICAgICAgICB0aGlzLnBsdWdpbk1hcHMgPSB7fTsKICAgICAgICAgICAgdGhpcy5kZXBDb3VudCA9IDA7CgogICAgICAgICAgICAvKiB0aGlzLmV4cG9ydHMgdGhpcy5mYWN0b3J5CiAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcyA9IFtdLAogICAgICAgICAgICAgICB0aGlzLmVuYWJsZWQsIHRoaXMuZmV0Y2hlZAogICAgICAgICAgICAqLwogICAgICAgIH07CgogICAgICAgIE1vZHVsZS5wcm90b3R5cGUgPSB7CiAgICAgICAgICAgIGluaXQ6IGZ1bmN0aW9uIChkZXBNYXBzLCBmYWN0b3J5LCBlcnJiYWNrLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIG5vdCBkbyBtb3JlIGluaXRzIGlmIGFscmVhZHkgZG9uZS4gQ2FuIGhhcHBlbiBpZiB0aGVyZQogICAgICAgICAgICAgICAgLy9hcmUgbXVsdGlwbGUgZGVmaW5lIGNhbGxzIGZvciB0aGUgc2FtZSBtb2R1bGUuIFRoYXQgaXMgbm90CiAgICAgICAgICAgICAgICAvL2Egbm9ybWFsLCBjb21tb24gY2FzZSwgYnV0IGl0IGlzIGFsc28gbm90IHVuZXhwZWN0ZWQuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgdGhpcy5mYWN0b3J5ID0gZmFjdG9yeTsKCiAgICAgICAgICAgICAgICBpZiAoZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgIC8vUmVnaXN0ZXIgZm9yIGVycm9ycyBvbiB0aGlzIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLm9uKCdlcnJvcicsIGVycmJhY2spOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgIC8vSWYgbm8gZXJyYmFjayBhbHJlYWR5LCBidXQgdGhlcmUgYXJlIGVycm9yIGxpc3RlbmVycwogICAgICAgICAgICAgICAgICAgIC8vb24gdGhpcyBtb2R1bGUsIHNldCB1cCBhbiBlcnJiYWNrIHRvIHBhc3MgdG8gdGhlIGRlcHMuCiAgICAgICAgICAgICAgICAgICAgZXJyYmFjayA9IGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0RvIGEgY29weSBvZiB0aGUgZGVwZW5kZW5jeSBhcnJheSwgc28gdGhhdAogICAgICAgICAgICAgICAgLy9zb3VyY2UgaW5wdXRzIGFyZSBub3QgbW9kaWZpZWQuIEZvciBleGFtcGxlCiAgICAgICAgICAgICAgICAvLyJzaGltIiBkZXBzIGFyZSBwYXNzZWQgaW4gaGVyZSBkaXJlY3RseSwgYW5kCiAgICAgICAgICAgICAgICAvL2RvaW5nIGEgZGlyZWN0IG1vZGlmaWNhdGlvbiBvZiB0aGUgZGVwTWFwcyBhcnJheQogICAgICAgICAgICAgICAgLy93b3VsZCBhZmZlY3QgdGhhdCBjb25maWcuCiAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMgPSBkZXBNYXBzICYmIGRlcE1hcHMuc2xpY2UoMCk7CgogICAgICAgICAgICAgICAgdGhpcy5lcnJiYWNrID0gZXJyYmFjazsKCiAgICAgICAgICAgICAgICAvL0luZGljYXRlIHRoaXMgbW9kdWxlIGhhcyBiZSBpbml0aWFsaXplZAogICAgICAgICAgICAgICAgdGhpcy5pbml0ZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIHRoaXMuaWdub3JlID0gb3B0aW9ucy5pZ25vcmU7CgogICAgICAgICAgICAgICAgLy9Db3VsZCBoYXZlIG9wdGlvbiB0byBpbml0IHRoaXMgbW9kdWxlIGluIGVuYWJsZWQgbW9kZSwKICAgICAgICAgICAgICAgIC8vb3IgY291bGQgaGF2ZSBiZWVuIHByZXZpb3VzbHkgbWFya2VkIGFzIGVuYWJsZWQuIEhvd2V2ZXIsCiAgICAgICAgICAgICAgICAvL3RoZSBkZXBlbmRlbmNpZXMgYXJlIG5vdCBrbm93biB1bnRpbCBpbml0IGlzIGNhbGxlZC4gU28KICAgICAgICAgICAgICAgIC8vaWYgZW5hYmxlZCBwcmV2aW91c2x5LCBub3cgdHJpZ2dlciBkZXBlbmRlbmNpZXMgYXMgZW5hYmxlZC4KICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVuYWJsZWQgfHwgdGhpcy5lbmFibGVkKSB7CiAgICAgICAgICAgICAgICAgICAgLy9FbmFibGUgdGhpcyBtb2R1bGUgYW5kIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAvL1dpbGwgY2FsbCB0aGlzLmNoZWNrKCkKICAgICAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmNoZWNrKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBkZWZpbmVEZXA6IGZ1bmN0aW9uIChpLCBkZXBFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAvL0JlY2F1c2Ugb2YgY3ljbGVzLCBkZWZpbmVkIGNhbGxiYWNrIGZvciBhIGdpdmVuCiAgICAgICAgICAgICAgICAvL2V4cG9ydCBjYW4gYmUgY2FsbGVkIG1vcmUgdGhhbiBvbmNlLgogICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRlcE1hdGNoZWRbaV0pIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hdGNoZWRbaV0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwQ291bnQgLT0gMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHNbaV0gPSBkZXBFeHBvcnRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLmZldGNoZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0aGlzLmZldGNoZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIGNvbnRleHQuc3RhcnRUaW1lID0gKG5ldyBEYXRlKCkpLmdldFRpbWUoKTsKCiAgICAgICAgICAgICAgICB2YXIgbWFwID0gdGhpcy5tYXA7CgogICAgICAgICAgICAgICAgLy9JZiB0aGUgbWFuYWdlciBpcyBmb3IgYSBwbHVnaW4gbWFuYWdlZCByZXNvdXJjZSwKICAgICAgICAgICAgICAgIC8vYXNrIHRoZSBwbHVnaW4gdG8gbG9hZCBpdCBub3cuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5tYWtlUmVxdWlyZSh0aGlzLm1hcCwgewogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVCdWlsZENhbGxiYWNrOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgfSkodGhpcy5zaGltLmRlcHMgfHwgW10sIGJpbmQodGhpcywgZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgfSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL1JlZ3VsYXIgZGVwZW5kZW5jeS4KICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBsb2FkOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICB2YXIgdXJsID0gdGhpcy5tYXAudXJsOwoKICAgICAgICAgICAgICAgIC8vUmVndWxhciBkZXBlbmRlbmN5LgogICAgICAgICAgICAgICAgaWYgKCF1cmxGZXRjaGVkW3VybF0pIHsKICAgICAgICAgICAgICAgICAgICB1cmxGZXRjaGVkW3VybF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIGNvbnRleHQubG9hZCh0aGlzLm1hcC5pZCwgdXJsKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBDaGVja3MgaWYgdGhlIG1vZHVsZSBpcyByZWFkeSB0byBkZWZpbmUgaXRzZWxmLCBhbmQgaWYgc28sCiAgICAgICAgICAgICAqIGRlZmluZSBpdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNoZWNrOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZW5hYmxlZCB8fCB0aGlzLmVuYWJsaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHZhciBlcnIsIGNqc01vZHVsZSwKICAgICAgICAgICAgICAgICAgICBpZCA9IHRoaXMubWFwLmlkLAogICAgICAgICAgICAgICAgICAgIGRlcEV4cG9ydHMgPSB0aGlzLmRlcEV4cG9ydHMsCiAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0cywKICAgICAgICAgICAgICAgICAgICBmYWN0b3J5ID0gdGhpcy5mYWN0b3J5OwoKICAgICAgICAgICAgICAgIGlmICghdGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGZldGNoIGlmIG5vdCBhbHJlYWR5IGluIHRoZSBkZWZRdWV1ZS4KICAgICAgICAgICAgICAgICAgICBpZiAoIWhhc1Byb3AoY29udGV4dC5kZWZRdWV1ZU1hcCwgaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZmV0Y2goKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgdGhpcy5lcnJvcik7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLmRlZmluaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgLy9UaGUgZmFjdG9yeSBjb3VsZCB0cmlnZ2VyIGFub3RoZXIgcmVxdWlyZSBjYWxsCiAgICAgICAgICAgICAgICAgICAgLy90aGF0IHdvdWxkIHJlc3VsdCBpbiBjaGVja2luZyB0aGlzIG1vZHVsZSB0bwogICAgICAgICAgICAgICAgICAgIC8vZGVmaW5lIGl0c2VsZiBhZ2Fpbi4gSWYgYWxyZWFkeSBpbiB0aGUgcHJvY2VzcwogICAgICAgICAgICAgICAgICAgIC8vb2YgZG9pbmcgdGhhdCwgc2tpcCB0aGlzIHdvcmsuCiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWZpbmluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlcENvdW50IDwgMSAmJiAhdGhpcy5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0Z1bmN0aW9uKGZhY3RvcnkpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjb250ZXh0LmV4ZWNDYihpZCwgZmFjdG9yeSwgZGVwRXhwb3J0cywgZXhwb3J0cyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyID0gZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGYXZvciByZXR1cm4gdmFsdWUgb3ZlciBleHBvcnRzLiBJZiBub2RlL2NqcyBpbiBwbGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlbiB3aWxsIG5vdCBoYXZlIGEgcmV0dXJuIHZhbHVlIGFueXdheS4gRmF2b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1vZHVsZS5leHBvcnRzIGFzc2lnbm1lbnQgb3ZlciBleHBvcnRzIG9iamVjdC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hcC5pc0RlZmluZSAmJiBleHBvcnRzID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjanNNb2R1bGUgPSB0aGlzLm1vZHVsZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2pzTW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjanNNb2R1bGUuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMudXNpbmdFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vZXhwb3J0cyBhbHJlYWR5IHNldCB0aGUgZGVmaW5lZCB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZXJlIGlzIGFuIGVycm9yIGxpc3RlbmVyLCBmYXZvciBwYXNzaW5nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdG8gdGhhdCBpbnN0ZWFkIG9mIHRocm93aW5nIGFuIGVycm9yLiBIb3dldmVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9ubHkgZG8gaXQgZm9yIGRlZmluZSgpJ2QgIG1vZHVsZXMuIHJlcXVpcmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBlcnJiYWNrcyBzaG91bGQgbm90IGJlIGNhbGxlZCBmb3IgZmFpbHVyZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGVpciBjYWxsYmFja3MgKCM2OTkpLiBIb3dldmVyIGlmIGEgZ2xvYmFsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb25FcnJvciBpcyBzZXQsIHVzZSB0aGF0LgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodGhpcy5ldmVudHMuZXJyb3IgJiYgdGhpcy5tYXAuaXNEZWZpbmUpIHx8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5vbkVycm9yICE9PSBkZWZhdWx0T25FcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1hcCA9IHRoaXMubWFwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1vZHVsZXMgPSB0aGlzLm1hcC5pc0RlZmluZSA/IFt0aGlzLm1hcC5pZF0gOiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZVR5cGUgPSB0aGlzLm1hcC5pc0RlZmluZSA/ICdkZWZpbmUnIDogJ3JlcXVpcmUnOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcigodGhpcy5lcnJvciA9IGVycikpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvZyB0aGUgZXJyb3IgZm9yIGRlYnVnZ2luZy4gSWYgcHJvbWlzZXMgY291bGQgYmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXNlZCwgdGhpcyB3b3VsZCBiZSBkaWZmZXJlbnQsIGJ1dCBtYWtpbmcgZG8uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBEbyBub3Qgd2FudCB0byBjb21wbGV0ZWx5IGxvc2UgdGhlIGVycm9yLiBXaGlsZSB0aGlzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpbGwgbWVzcyB1cCBwcm9jZXNzaW5nIGFuZCBsZWFkIHRvIHNpbWlsYXIgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcyBidWcgMTQ0MCwgaXQgYXQgbGVhc3Qgc3VyZmFjZXMgdGhlIGVycm9yLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIGxpdGVyYWwgdmFsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBmYWN0b3J5OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmV4cG9ydHMgPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubWFwLmlzRGVmaW5lICYmICF0aGlzLmlnbm9yZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmaW5lZFtpZF0gPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEub25SZXNvdXJjZUxvYWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzTG9hZE1hcHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNMb2FkTWFwcy5wdXNoKGRlcE1hcC5ub3JtYWxpemVkTWFwIHx8IGRlcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxLm9uUmVzb3VyY2VMb2FkKGNvbnRleHQsIHRoaXMubWFwLCByZXNMb2FkTWFwcyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQ2xlYW4gdXAKICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9GaW5pc2hlZCB0aGUgZGVmaW5lIHN0YWdlLiBBbGxvdyBjYWxsaW5nIGNoZWNrIGFnYWluCiAgICAgICAgICAgICAgICAgICAgLy90byBhbGxvdyBkZWZpbmUgbm90aWZpY2F0aW9ucyBiZWxvdyBpbiB0aGUgY2FzZSBvZiBhCiAgICAgICAgICAgICAgICAgICAgLy9jeWNsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluaW5nID0gZmFsc2U7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlZmluZWQgJiYgIXRoaXMuZGVmaW5lRW1pdHRlZCkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXR0ZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2RlZmluZWQnLCB0aGlzLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXRDb21wbGV0ZSA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGNhbGxQbHVnaW46IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHZhciBtYXAgPSB0aGlzLm1hcCwKICAgICAgICAgICAgICAgICAgICBpZCA9IG1hcC5pZCwKICAgICAgICAgICAgICAgICAgICAvL01hcCBhbHJlYWR5IG5vcm1hbGl6ZWQgdGhlIHByZWZpeC4KICAgICAgICAgICAgICAgICAgICBwbHVnaW5NYXAgPSBtYWtlTW9kdWxlTWFwKG1hcC5wcmVmaXgpOwoKICAgICAgICAgICAgICAgIC8vTWFyayB0aGlzIGFzIGEgZGVwZW5kZW5jeSBmb3IgdGhpcyBwbHVnaW4sIHNvIGl0CiAgICAgICAgICAgICAgICAvL2NhbiBiZSB0cmFjZWQgZm9yIGN5Y2xlcy4KICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcy5wdXNoKHBsdWdpbk1hcCk7CgogICAgICAgICAgICAgICAgb24ocGx1Z2luTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbikgewogICAgICAgICAgICAgICAgICAgIHZhciBsb2FkLCBub3JtYWxpemVkTWFwLCBub3JtYWxpemVkTW9kLAogICAgICAgICAgICAgICAgICAgICAgICBidW5kbGVJZCA9IGdldE93bihidW5kbGVzTWFwLCB0aGlzLm1hcC5pZCksCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSB0aGlzLm1hcC5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnROYW1lID0gdGhpcy5tYXAucGFyZW50TWFwID8gdGhpcy5tYXAucGFyZW50TWFwLm5hbWUgOiBudWxsLAogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKG1hcC5wYXJlbnRNYXAsIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZUJ1aWxkQ2FsbGJhY2s6IHRydWUKICAgICAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgICAgIC8vSWYgY3VycmVudCBtYXAgaXMgbm90IG5vcm1hbGl6ZWQsIHdhaXQgZm9yIHRoYXQKICAgICAgICAgICAgICAgICAgICAvL25vcm1hbGl6ZWQgbmFtZSB0byBsb2FkIGluc3RlYWQgb2YgY29udGludWluZy4KICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5tYXAudW5ub3JtYWxpemVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIHRoZSBJRCBpZiB0aGUgcGx1Z2luIGFsbG93cyBpdC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBsdWdpbi5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBwbHVnaW4ubm9ybWFsaXplKG5hbWUsIGZ1bmN0aW9uIChuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pIHx8ICcnOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL3ByZWZpeCBhbmQgbmFtZSBzaG91bGQgYWxyZWFkeSBiZSBub3JtYWxpemVkLCBubyBuZWVkCiAgICAgICAgICAgICAgICAgICAgICAgIC8vZm9yIGFwcGx5aW5nIG1hcCBjb25maWcgYWdhaW4gZWl0aGVyLgogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTWFwID0gbWFrZU1vZHVsZU1hcChtYXAucHJlZml4ICsgJyEnICsgbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXAucGFyZW50TWFwKTsKICAgICAgICAgICAgICAgICAgICAgICAgb24obm9ybWFsaXplZE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkZWZpbmVkJywgYmluZCh0aGlzLCBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hcC5ub3JtYWxpemVkTWFwID0gbm9ybWFsaXplZE1hcDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZTogdHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE1vZCA9IGdldE93bihyZWdpc3RyeSwgbm9ybWFsaXplZE1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkTW9kKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL01hcmsgdGhpcyBhcyBhIGRlcGVuZGVuY3kgZm9yIHRoaXMgcGx1Z2luLCBzbyBpdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9jYW4gYmUgdHJhY2VkIGZvciBjeWNsZXMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMucHVzaChub3JtYWxpemVkTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5ldmVudHMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLm9uKCdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0lmIGEgcGF0aHMgY29uZmlnLCB0aGVuIGp1c3QgbG9hZCB0aGF0IGZpbGUgaW5zdGVhZCB0bwogICAgICAgICAgICAgICAgICAgIC8vcmVzb2x2ZSB0aGUgcGx1Z2luLCBhcyBpdCBpcyBidWlsdCBpbnRvIHRoYXQgcGF0aHMgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWFwLnVybCA9IGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkKTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGxvYWQgPSBiaW5kKHRoaXMsIGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICBsb2FkLmVycm9yID0gYmluZCh0aGlzLCBmdW5jdGlvbiAoZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdGVkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycjsKICAgICAgICAgICAgICAgICAgICAgICAgZXJyLnJlcXVpcmVNb2R1bGVzID0gW2lkXTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vUmVtb3ZlIHRlbXAgdW5ub3JtYWxpemVkIG1vZHVsZXMgZm9yIHRoaXMgbW9kdWxlLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NpbmNlIHRoZXkgd2lsbCBuZXZlciBiZSByZXNvbHZlZCBvdGhlcndpc2Ugbm93LgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaWQuaW5kZXhPZihpZCArICdfdW5ub3JtYWxpemVkJykgPT09IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhblJlZ2lzdHJ5KG1vZC5tYXAuaWQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9BbGxvdyBwbHVnaW5zIHRvIGxvYWQgb3RoZXIgY29kZSB3aXRob3V0IGhhdmluZyB0byBrbm93IHRoZQogICAgICAgICAgICAgICAgICAgIC8vY29udGV4dCBvciBob3cgdG8gJ2NvbXBsZXRlJyB0aGUgbG9hZC4KICAgICAgICAgICAgICAgICAgICBsb2FkLmZyb21UZXh0ID0gYmluZCh0aGlzLCBmdW5jdGlvbiAodGV4dCwgdGV4dEFsdCkgewogICAgICAgICAgICAgICAgICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtb2R1bGVOYW1lID0gbWFwLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVNYXAgPSBtYWtlTW9kdWxlTWFwKG1vZHVsZU5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzSW50ZXJhY3RpdmUgPSB1c2VJbnRlcmFjdGl2ZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQXMgb2YgMi4xLjAsIHN1cHBvcnQganVzdCBwYXNzaW5nIHRoZSB0ZXh0LCB0byByZWluZm9yY2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9mcm9tVGV4dCBvbmx5IGJlaW5nIGNhbGxlZCBvbmNlIHBlciByZXNvdXJjZS4gU3RpbGwKICAgICAgICAgICAgICAgICAgICAgICAgLy9zdXBwb3J0IG9sZCBzdHlsZSBvZiBwYXNzaW5nIG1vZHVsZU5hbWUgYnV0IGRpc2NhcmQKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGF0IG1vZHVsZU5hbWUgaW4gZmF2b3Igb2YgdGhlIGludGVybmFsIHJlZi4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRleHRBbHQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQgPSB0ZXh0QWx0OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1R1cm4gb2ZmIGludGVyYWN0aXZlIHNjcmlwdCBtYXRjaGluZyBmb3IgSUUgZm9yIGFueSBkZWZpbmUKICAgICAgICAgICAgICAgICAgICAgICAgLy9jYWxscyBpbiB0aGUgdGV4dCwgdGhlbiB0dXJuIGl0IGJhY2sgb24gYXQgdGhlIGVuZC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0ludGVyYWN0aXZlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1ByaW1lIHRoZSBzeXN0ZW0gYnkgY3JlYXRpbmcgYSBtb2R1bGUgaW5zdGFuY2UgZm9yCiAgICAgICAgICAgICAgICAgICAgICAgIC8vaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGdldE1vZHVsZShtb2R1bGVNYXApOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9UcmFuc2ZlciBhbnkgY29uZmlnIHRvIHRoaXMgb3RoZXIgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzUHJvcChjb25maWcuY29uZmlnLCBpZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5jb25maWdbbW9kdWxlTmFtZV0gPSBjb25maWcuY29uZmlnW2lkXTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5leGVjKHRleHQpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ2Zyb210ZXh0ZXZhbCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdmcm9tVGV4dCBldmFsIGZvciAnICsgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcgZmFpbGVkOiAnICsgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2lkXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXJrIHRoaXMgYXMgYSBkZXBlbmRlbmN5IGZvciB0aGUgcGx1Z2luCiAgICAgICAgICAgICAgICAgICAgICAgIC8vcmVzb3VyY2UKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBNYXBzLnB1c2gobW9kdWxlTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3VwcG9ydCBhbm9ueW1vdXMgbW9kdWxlcy4KICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQobW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgdGhlIHZhbHVlIG9mIHRoYXQgbW9kdWxlIHRvIHRoZSB2YWx1ZSBmb3IgdGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvL3Jlc291cmNlIElELgogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUoW21vZHVsZU5hbWVdLCBsb2FkKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9Vc2UgcGFyZW50TmFtZSBoZXJlIHNpbmNlIHRoZSBwbHVnaW4ncyBuYW1lIGlzIG5vdCByZWxpYWJsZSwKICAgICAgICAgICAgICAgICAgICAvL2NvdWxkIGJlIHNvbWUgd2VpcmQgc3RyaW5nIHdpdGggbm8gcGF0aCB0aGF0IGFjdHVhbGx5IHdhbnRzIHRvCiAgICAgICAgICAgICAgICAgICAgLy9yZWZlcmVuY2UgdGhlIHBhcmVudE5hbWUncyBwYXRoLgogICAgICAgICAgICAgICAgICAgIHBsdWdpbi5sb2FkKG1hcC5uYW1lLCBsb2NhbFJlcXVpcmUsIGxvYWQsIGNvbmZpZyk7CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luTWFwc1twbHVnaW5NYXAuaWRdID0gcGx1Z2luTWFwOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZW5hYmxlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBlbmFibGVkUmVnaXN0cnlbdGhpcy5tYXAuaWRdID0gdGhpczsKICAgICAgICAgICAgICAgIHRoaXMuZW5hYmxlZCA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9TZXQgZmxhZyBtZW50aW9uaW5nIHRoYXQgdGhlIG1vZHVsZSBpcyBlbmFibGluZywKICAgICAgICAgICAgICAgIC8vc28gdGhhdCBpbW1lZGlhdGUgY2FsbHMgdG8gdGhlIGRlZmluZWQgY2FsbGJhY2tzCiAgICAgICAgICAgICAgICAvL2ZvciBkZXBlbmRlbmNpZXMgZG8gbm90IHRyaWdnZXIgaW5hZHZlcnRlbnQgbG9hZAogICAgICAgICAgICAgICAgLy93aXRoIHRoZSBkZXBDb3VudCBzdGlsbCBiZWluZyB6ZXJvLgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9FbmFibGUgZWFjaCBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgYmluZCh0aGlzLCBmdW5jdGlvbiAoZGVwTWFwLCBpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIGlkLCBtb2QsIGhhbmRsZXI7CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwTWFwID09PSAnc3RyaW5nJykgewogICAgICAgICAgICAgICAgICAgICAgICAvL0RlcGVuZGVuY3kgbmVlZHMgdG8gYmUgY29udmVydGVkIHRvIGEgZGVwTWFwCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYW5kIHdpcmVkIHVwIHRvIHRoaXMgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBkZXBNYXAgPSBtYWtlTW9kdWxlTWFwKGRlcE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5tYXAuaXNEZWZpbmUgPyB0aGlzLm1hcCA6IHRoaXMubWFwLnBhcmVudE1hcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIXRoaXMuc2tpcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwc1tpXSA9IGRlcE1hcDsKCiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZXIgPSBnZXRPd24oaGFuZGxlcnMsIGRlcE1hcC5pZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBFeHBvcnRzW2ldID0gaGFuZGxlcih0aGlzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBDb3VudCArPSAxOwoKICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKGRlcEV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnVuZGVmZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZURlcChpLCBkZXBFeHBvcnRzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZXJyb3InLCBiaW5kKHRoaXMsIHRoaXMuZXJyYmFjaykpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXZlbnRzLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBObyBkaXJlY3QgZXJyYmFjayBvbiB0aGlzIG1vZHVsZSwgYnV0IHNvbWV0aGluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWxzZSBpcyBsaXN0ZW5pbmcgZm9yIGVycm9ycywgc28gYmUgc3VyZSB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJvcGFnYXRlIHRoZSBlcnJvciBjb3JyZWN0bHkuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbihkZXBNYXAsICdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24oZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIGVycik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlkID0gZGVwTWFwLmlkOwogICAgICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXTsKCiAgICAgICAgICAgICAgICAgICAgLy9Ta2lwIHNwZWNpYWwgbW9kdWxlcyBsaWtlICdyZXF1aXJlJywgJ2V4cG9ydHMnLCAnbW9kdWxlJwogICAgICAgICAgICAgICAgICAgIC8vQWxzbywgZG9uJ3QgY2FsbCBlbmFibGUgaWYgaXQgaXMgYWxyZWFkeSBlbmFibGVkLAogICAgICAgICAgICAgICAgICAgIC8vaW1wb3J0YW50IGluIGNpcmN1bGFyIGRlcGVuZGVuY3kgY2FzZXMuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGhhbmRsZXJzLCBpZCkgJiYgbW9kICYmICFtb2QuZW5hYmxlZCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmVuYWJsZShkZXBNYXAsIHRoaXMpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pKTsKCiAgICAgICAgICAgICAgICAvL0VuYWJsZSBlYWNoIHBsdWdpbiB0aGF0IGlzIHVzZWQgaW4KICAgICAgICAgICAgICAgIC8vYSBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoUHJvcCh0aGlzLnBsdWdpbk1hcHMsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbk1hcCkgewogICAgICAgICAgICAgICAgICAgIHZhciBtb2QgPSBnZXRPd24ocmVnaXN0cnksIHBsdWdpbk1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCAmJiAhbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IGZhbHNlOwoKICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG9uOiBmdW5jdGlvbiAobmFtZSwgY2IpIHsKICAgICAgICAgICAgICAgIHZhciBjYnMgPSB0aGlzLmV2ZW50c1tuYW1lXTsKICAgICAgICAgICAgICAgIGlmICghY2JzKSB7CiAgICAgICAgICAgICAgICAgICAgY2JzID0gdGhpcy5ldmVudHNbbmFtZV0gPSBbXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNicy5wdXNoKGNiKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGVtaXQ6IGZ1bmN0aW9uIChuYW1lLCBldnQpIHsKICAgICAgICAgICAgICAgIGVhY2godGhpcy5ldmVudHNbbmFtZV0sIGZ1bmN0aW9uIChjYikgewogICAgICAgICAgICAgICAgICAgIGNiKGV2dCk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGlmIChuYW1lID09PSAnZXJyb3InKSB7CiAgICAgICAgICAgICAgICAgICAgLy9Ob3cgdGhhdCB0aGUgZXJyb3IgaGFuZGxlciB3YXMgdHJpZ2dlcmVkLCByZW1vdmUKICAgICAgICAgICAgICAgICAgICAvL3RoZSBsaXN0ZW5lcnMsIHNpbmNlIHRoaXMgYnJva2VuIE1vZHVsZSBpbnN0YW5jZQogICAgICAgICAgICAgICAgICAgIC8vY2FuIHN0YXkgYXJvdW5kIGZvciBhIHdoaWxlIGluIHRoZSByZWdpc3RyeS4KICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5ldmVudHNbbmFtZV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjYWxsR2V0TW9kdWxlKGFyZ3MpIHsKICAgICAgICAgICAgLy9Ta2lwIG1vZHVsZXMgYWxyZWFkeSBkZWZpbmVkLgogICAgICAgICAgICBpZiAoIWhhc1Byb3AoZGVmaW5lZCwgYXJnc1swXSkpIHsKICAgICAgICAgICAgICAgIGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKGFyZ3NbMF0sIG51bGwsIHRydWUpKS5pbml0KGFyZ3NbMV0sIGFyZ3NbMl0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihub2RlLCBmdW5jLCBuYW1lLCBpZU5hbWUpIHsKICAgICAgICAgICAgLy9GYXZvciBkZXRhY2hFdmVudCBiZWNhdXNlIG9mIElFOQogICAgICAgICAgICAvL2lzc3VlLCBzZWUgYXR0YWNoRXZlbnQvYWRkRXZlbnRMaXN0ZW5lciBjb21tZW50IGVsc2V3aGVyZQogICAgICAgICAgICAvL2luIHRoaXMgZmlsZS4KICAgICAgICAgICAgaWYgKG5vZGUuZGV0YWNoRXZlbnQgJiYgIWlzT3BlcmEpIHsKICAgICAgICAgICAgICAgIC8vUHJvYmFibHkgSUUuIElmIG5vdCBpdCB3aWxsIHRocm93IGFuIGVycm9yLCB3aGljaCB3aWxsIGJlCiAgICAgICAgICAgICAgICAvL3VzZWZ1bCB0byBrbm93LgogICAgICAgICAgICAgICAgaWYgKGllTmFtZSkgewogICAgICAgICAgICAgICAgICAgIG5vZGUuZGV0YWNoRXZlbnQoaWVOYW1lLCBmdW5jKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUucmVtb3ZlRXZlbnRMaXN0ZW5lcihuYW1lLCBmdW5jLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdpdmVuIGFuIGV2ZW50IGZyb20gYSBzY3JpcHQgbm9kZSwgZ2V0IHRoZSByZXF1aXJlanMgaW5mbyBmcm9tIGl0LAogICAgICAgICAqIGFuZCB0aGVuIHJlbW92ZXMgdGhlIGV2ZW50IGxpc3RlbmVycyBvbiB0aGUgbm9kZS4KICAgICAgICAgKiBAcGFyYW0ge0V2ZW50fSBldnQKICAgICAgICAgKiBAcmV0dXJucyB7T2JqZWN0fQogICAgICAgICAqLwogICAgICAgIGZ1bmN0aW9uIGdldFNjcmlwdERhdGEoZXZ0KSB7CiAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgLy9hbGwgb2xkIGJyb3dzZXJzIHdpbGwgYmUgc3VwcG9ydGVkLCBidXQgdGhpcyBvbmUgd2FzIGVhc3kgZW5vdWdoCiAgICAgICAgICAgIC8vdG8gc3VwcG9ydCBhbmQgc3RpbGwgbWFrZXMgc2Vuc2UuCiAgICAgICAgICAgIHZhciBub2RlID0gZXZ0LmN1cnJlbnRUYXJnZXQgfHwgZXZ0LnNyY0VsZW1lbnQ7CgogICAgICAgICAgICAvL1JlbW92ZSB0aGUgbGlzdGVuZXJzIG9uY2UgaGVyZS4KICAgICAgICAgICAgcmVtb3ZlTGlzdGVuZXIobm9kZSwgY29udGV4dC5vblNjcmlwdExvYWQsICdsb2FkJywgJ29ucmVhZHlzdGF0ZWNoYW5nZScpOwogICAgICAgICAgICByZW1vdmVMaXN0ZW5lcihub2RlLCBjb250ZXh0Lm9uU2NyaXB0RXJyb3IsICdlcnJvcicpOwoKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIG5vZGU6IG5vZGUsCiAgICAgICAgICAgICAgICBpZDogbm9kZSAmJiBub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJykKICAgICAgICAgICAgfTsKICAgICAgICB9CgogICAgICAgIGZ1bmN0aW9uIGludGFrZURlZmluZXMoKSB7CiAgICAgICAgICAgIHZhciBhcmdzOwoKICAgICAgICAgICAgLy9BbnkgZGVmaW5lZCBtb2R1bGVzIGluIHRoZSBnbG9iYWwgcXVldWUsIGludGFrZSB0aGVtIG5vdy4KICAgICAgICAgICAgdGFrZUdsb2JhbFF1ZXVlKCk7CgogICAgICAgICAgICAvL01ha2Ugc3VyZSBhbnkgcmVtYWluaW5nIGRlZlF1ZXVlIGl0ZW1zIGdldCBwcm9wZXJseSBwcm9jZXNzZWQuCiAgICAgICAgICAgIHdoaWxlIChkZWZRdWV1ZS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGFyZ3MgPSBkZWZRdWV1ZS5zaGlmdCgpOwogICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ21pc21hdGNoJywgJ01pc21hdGNoZWQgYW5vbnltb3VzIGRlZmluZSgpIG1vZHVsZTogJyArCiAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3NbYXJncy5sZW5ndGggLSAxXSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL2FyZ3MgYXJlIGlkLCBkZXBzLCBmYWN0b3J5LiBTaG91bGQgYmUgbm9ybWFsaXplZCBieSB0aGUKICAgICAgICAgICAgICAgICAgICAvL2RlZmluZSgpIGZ1bmN0aW9uLgogICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoYXJncyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcCA9IHt9OwogICAgICAgIH0KCiAgICAgICAgY29udGV4dCA9IHsKICAgICAgICAgICAgY29uZmlnOiBjb25maWcsCiAgICAgICAgICAgIGNvbnRleHROYW1lOiBjb250ZXh0TmFtZSwKICAgICAgICAgICAgcmVnaXN0cnk6IHJlZ2lzdHJ5LAogICAgICAgICAgICBkZWZpbmVkOiBkZWZpbmVkLAogICAgICAgICAgICB1cmxGZXRjaGVkOiB1cmxGZXRjaGVkLAogICAgICAgICAgICBkZWZRdWV1ZTogZGVmUXVldWUsCiAgICAgICAgICAgIGRlZlF1ZXVlTWFwOiB7fSwKICAgICAgICAgICAgTW9kdWxlOiBNb2R1bGUsCiAgICAgICAgICAgIG1ha2VNb2R1bGVNYXA6IG1ha2VNb2R1bGVNYXAsCiAgICAgICAgICAgIG5leHRUaWNrOiByZXEubmV4dFRpY2ssCiAgICAgICAgICAgIG9uRXJyb3I6IG9uRXJyb3IsCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogU2V0IGEgY29uZmlndXJhdGlvbiBmb3IgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgY29uZmlnIG9iamVjdCB0byBpbnRlZ3JhdGUuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBjb25maWd1cmU6IGZ1bmN0aW9uIChjZmcpIHsKICAgICAgICAgICAgICAgIC8vTWFrZSBzdXJlIHRoZSBiYXNlVXJsIGVuZHMgaW4gYSBzbGFzaC4KICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybC5jaGFyQXQoY2ZnLmJhc2VVcmwubGVuZ3RoIC0gMSkgIT09ICcvJykgewogICAgICAgICAgICAgICAgICAgICAgICBjZmcuYmFzZVVybCArPSAnLyc7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vU2F2ZSBvZmYgdGhlIHBhdGhzIHNpbmNlIHRoZXkgcmVxdWlyZSBzcGVjaWFsIHByb2Nlc3NpbmcsCiAgICAgICAgICAgICAgICAvL3RoZXkgYXJlIGFkZGl0aXZlLgogICAgICAgICAgICAgICAgdmFyIHNoaW0gPSBjb25maWcuc2hpbSwKICAgICAgICAgICAgICAgICAgICBvYmpzID0gewogICAgICAgICAgICAgICAgICAgICAgICBwYXRoczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnOiB0cnVlLAogICAgICAgICAgICAgICAgICAgICAgICBtYXA6IHRydWUKICAgICAgICAgICAgICAgICAgICB9OwoKICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZywgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG9ianNbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjb25maWdbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHt9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIG1peGluKGNvbmZpZ1twcm9wXSwgdmFsdWUsIHRydWUsIHRydWUpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHZhbHVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIC8vUmV2ZXJzZSBtYXAgdGhlIGJ1bmRsZXMKICAgICAgICAgICAgICAgIGlmIChjZmcuYnVuZGxlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZy5idW5kbGVzLCBmdW5jdGlvbiAodmFsdWUsIHByb3ApIHsKICAgICAgICAgICAgICAgICAgICAgICAgZWFjaCh2YWx1ZSwgZnVuY3Rpb24gKHYpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2ICE9PSBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlc01hcFt2XSA9IHByb3A7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vTWVyZ2Ugc2hpbQogICAgICAgICAgICAgICAgaWYgKGNmZy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgZWFjaFByb3AoY2ZnLnNoaW0sIGZ1bmN0aW9uICh2YWx1ZSwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9Ob3JtYWxpemUgdGhlIHN0cnVjdHVyZQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlcHM6IHZhbHVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodmFsdWUuZXhwb3J0cyB8fCB2YWx1ZS5pbml0KSAmJiAhdmFsdWUuZXhwb3J0c0ZuKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5leHBvcnRzRm4gPSBjb250ZXh0Lm1ha2VTaGltRXhwb3J0cyh2YWx1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgc2hpbVtpZF0gPSB2YWx1ZTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICBjb25maWcuc2hpbSA9IHNoaW07CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgLy9BZGp1c3QgcGFja2FnZXMgaWYgbmVjZXNzYXJ5LgogICAgICAgICAgICAgICAgaWYgKGNmZy5wYWNrYWdlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2goY2ZnLnBhY2thZ2VzLCBmdW5jdGlvbiAocGtnT2JqKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsb2NhdGlvbiwgbmFtZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHBrZ09iaiA9IHR5cGVvZiBwa2dPYmogPT09ICdzdHJpbmcnID8ge25hbWU6IHBrZ09ian0gOiBwa2dPYmo7CgogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gcGtnT2JqLm5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gcGtnT2JqLmxvY2F0aW9uOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9jYXRpb24pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5wYXRoc1tuYW1lXSA9IHBrZ09iai5sb2NhdGlvbjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TYXZlIHBvaW50ZXIgdG8gbWFpbiBtb2R1bGUgSUQgZm9yIHBrZyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAvL1JlbW92ZSBsZWFkaW5nIGRvdCBpbiBtYWluLCBzbyBtYWluIHBhdGhzIGFyZSBub3JtYWxpemVkLAogICAgICAgICAgICAgICAgICAgICAgICAvL2FuZCByZW1vdmUgYW55IHRyYWlsaW5nIC5qcywgc2luY2UgZGlmZmVyZW50IHBhY2thZ2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9lbnZzIGhhdmUgZGlmZmVyZW50IGNvbnZlbnRpb25zOiBzb21lIHVzZSBhIG1vZHVsZSBuYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NvbWUgdXNlIGEgZmlsZSBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICBjb25maWcucGtnc1tuYW1lXSA9IHBrZ09iai5uYW1lICsgJy8nICsgKHBrZ09iai5tYWluIHx8ICdtYWluJykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKGN1cnJEaXJSZWdFeHAsICcnKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0lmIHRoZXJlIGFyZSBhbnkgIndhaXRpbmcgdG8gZXhlY3V0ZSIgbW9kdWxlcyBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAvL3VwZGF0ZSB0aGUgbWFwcyBmb3IgdGhlbSwgc2luY2UgdGhlaXIgaW5mbywgbGlrZSBVUkxzIHRvIGxvYWQsCiAgICAgICAgICAgICAgICAvL21heSBoYXZlIGNoYW5nZWQuCiAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIG1vZHVsZSBhbHJlYWR5IGhhcyBpbml0IGNhbGxlZCwgc2luY2UgaXQgaXMgdG9vCiAgICAgICAgICAgICAgICAgICAgLy9sYXRlIHRvIG1vZGlmeSB0aGVtLCBhbmQgaWdub3JlIHVubm9ybWFsaXplZCBvbmVzCiAgICAgICAgICAgICAgICAgICAgLy9zaW5jZSB0aGV5IGFyZSB0cmFuc2llbnQuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFtb2QuaW5pdGVkICYmICFtb2QubWFwLnVubm9ybWFsaXplZCkgewogICAgICAgICAgICAgICAgICAgICAgICBtb2QubWFwID0gbWFrZU1vZHVsZU1hcChpZCwgbnVsbCwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9JZiBhIGRlcHMgYXJyYXkgb3IgYSBjb25maWcgY2FsbGJhY2sgaXMgc3BlY2lmaWVkLCB0aGVuIGNhbGwKICAgICAgICAgICAgICAgIC8vcmVxdWlyZSB3aXRoIHRob3NlIGFyZ3MuIFRoaXMgaXMgdXNlZnVsIHdoZW4gcmVxdWlyZSBpcyBkZWZpbmVkIGFzIGEKICAgICAgICAgICAgICAgIC8vY29uZmlnIG9iamVjdCBiZWZvcmUgcmVxdWlyZS5qcyBpcyBsb2FkZWQuCiAgICAgICAgICAgICAgICBpZiAoY2ZnLmRlcHMgfHwgY2ZnLmNhbGxiYWNrKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlKGNmZy5kZXBzIHx8IFtdLCBjZmcuY2FsbGJhY2spOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgbWFrZVNoaW1FeHBvcnRzOiBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgIGZ1bmN0aW9uIGZuKCkgewogICAgICAgICAgICAgICAgICAgIHZhciByZXQ7CiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlLmluaXQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0ID0gdmFsdWUuaW5pdC5hcHBseShnbG9iYWwsIGFyZ3VtZW50cyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIHJldHVybiByZXQgfHwgKHZhbHVlLmV4cG9ydHMgJiYgZ2V0R2xvYmFsKHZhbHVlLmV4cG9ydHMpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBmbjsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG1ha2VSZXF1aXJlOiBmdW5jdGlvbiAocmVsTWFwLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICBmdW5jdGlvbiBsb2NhbFJlcXVpcmUoZGVwcywgY2FsbGJhY2ssIGVycmJhY2spIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQsIG1hcCwgcmVxdWlyZU1vZDsKCiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZW5hYmxlQnVpbGRDYWxsYmFjayAmJiBjYWxsYmFjayAmJiBpc0Z1bmN0aW9uKGNhbGxiYWNrKSkgewogICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjay5fX3JlcXVpcmVKc0J1aWxkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwcyA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzRnVuY3Rpb24oY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0ludmFsaWQgY2FsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdyZXF1aXJlYXJncycsICdJbnZhbGlkIHJlcXVpcmUgY2FsbCcpLCBlcnJiYWNrKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiByZXF1aXJlfGV4cG9ydHN8bW9kdWxlIGFyZSByZXF1ZXN0ZWQsIGdldCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy92YWx1ZSBmb3IgdGhlbSBmcm9tIHRoZSBzcGVjaWFsIGhhbmRsZXJzLiBDYXZlYXQ6CiAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBvbmx5IHdvcmtzIHdoaWxlIG1vZHVsZSBpcyBiZWluZyBkZWZpbmVkLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVsTWFwICYmIGhhc1Byb3AoaGFuZGxlcnMsIGRlcHMpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlcnNbZGVwc10ocmVnaXN0cnlbcmVsTWFwLmlkXSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3luY2hyb25vdXMgYWNjZXNzIHRvIG9uZSBtb2R1bGUuIElmIHJlcXVpcmUuZ2V0IGlzCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYXZhaWxhYmxlIChhcyBpbiB0aGUgTm9kZSBhZGFwdGVyKSwgcHJlZmVyIHRoYXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEuZ2V0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVxLmdldChjb250ZXh0LCBkZXBzLCByZWxNYXAsIGxvY2FsUmVxdWlyZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIG1vZHVsZSBuYW1lLCBpZiBpdCBjb250YWlucyAuIG9yIC4uCiAgICAgICAgICAgICAgICAgICAgICAgIG1hcCA9IG1ha2VNb2R1bGVNYXAoZGVwcywgcmVsTWFwLCBmYWxzZSwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFwLmlkOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGRlZmluZWQsIGlkKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub3Rsb2FkZWQnLCAnTW9kdWxlIG5hbWUgIicgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIgaGFzIG5vdCBiZWVuIGxvYWRlZCB5ZXQgZm9yIGNvbnRleHQ6ICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dE5hbWUgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlbE1hcCA/ICcnIDogJy4gVXNlIHJlcXVpcmUoW10pJykpKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0dyYWIgZGVmaW5lcyB3YWl0aW5nIGluIHRoZSBnbG9iYWwgcXVldWUuCiAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAvL01hcmsgYWxsIHRoZSBkZXBlbmRlbmNpZXMgYXMgbmVlZGluZyB0byBiZSBsb2FkZWQuCiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5uZXh0VGljayhmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vU29tZSBkZWZpbmVzIGNvdWxkIGhhdmUgYmVlbiBhZGRlZCBzaW5jZSB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9yZXF1aXJlIGNhbGwsIGNvbGxlY3QgdGhlbS4KICAgICAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZCA9IGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKG51bGwsIHJlbE1hcCkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TdG9yZSBpZiBtYXAgY29uZmlnIHNob3VsZCBiZSBhcHBsaWVkIHRvIHRoaXMgcmVxdWlyZQogICAgICAgICAgICAgICAgICAgICAgICAvL2NhbGwgZm9yIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5za2lwTWFwID0gb3B0aW9ucy5za2lwTWFwOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5pbml0KGRlcHMsIGNhbGxiYWNrLCBlcnJiYWNrLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tMb2FkZWQoKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsUmVxdWlyZTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBtaXhpbihsb2NhbFJlcXVpcmUsIHsKICAgICAgICAgICAgICAgICAgICBpc0Jyb3dzZXI6IGlzQnJvd3NlciwKCiAgICAgICAgICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAgICAgICAgICogQ29udmVydHMgYSBtb2R1bGUgbmFtZSArIC5leHRlbnNpb24gaW50byBhbiBVUkwgcGF0aC4KICAgICAgICAgICAgICAgICAgICAgKiAqUmVxdWlyZXMqIHRoZSB1c2Ugb2YgYSBtb2R1bGUgbmFtZS4gSXQgZG9lcyBub3Qgc3VwcG9ydCB1c2luZwogICAgICAgICAgICAgICAgICAgICAqIHBsYWluIFVSTHMgbGlrZSBuYW1lVG9VcmwuCiAgICAgICAgICAgICAgICAgICAgICovCiAgICAgICAgICAgICAgICAgICAgdG9Vcmw6IGZ1bmN0aW9uIChtb2R1bGVOYW1lUGx1c0V4dCkgewogICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBtb2R1bGVOYW1lUGx1c0V4dC5sYXN0SW5kZXhPZignLicpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudCA9IG1vZHVsZU5hbWVQbHVzRXh0LnNwbGl0KCcvJylbMF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1JlbGF0aXZlID0gc2VnbWVudCA9PT0gJy4nIHx8IHNlZ21lbnQgPT09ICcuLic7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0hhdmUgYSBmaWxlIGV4dGVuc2lvbiBhbGlhcywgYW5kIGl0IGlzIG5vdCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9kb3RzIGZyb20gYSByZWxhdGl2ZSBwYXRoLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5kZXggIT09IC0xICYmICghaXNSZWxhdGl2ZSB8fCBpbmRleCA+IDEpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHQgPSBtb2R1bGVOYW1lUGx1c0V4dC5zdWJzdHJpbmcoaW5kZXgsIG1vZHVsZU5hbWVQbHVzRXh0Lmxlbmd0aCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lUGx1c0V4dCA9IG1vZHVsZU5hbWVQbHVzRXh0LnN1YnN0cmluZygwLCBpbmRleCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb250ZXh0Lm5hbWVUb1VybChub3JtYWxpemUobW9kdWxlTmFtZVBsdXNFeHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbE1hcCAmJiByZWxNYXAuaWQsIHRydWUpLCBleHQsICB0cnVlKTsKICAgICAgICAgICAgICAgICAgICB9LAoKICAgICAgICAgICAgICAgICAgICBkZWZpbmVkOiBmdW5jdGlvbiAoaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGhhc1Byb3AoZGVmaW5lZCwgbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQpOwogICAgICAgICAgICAgICAgICAgIH0sCgogICAgICAgICAgICAgICAgICAgIHNwZWNpZmllZDogZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQ7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBoYXNQcm9wKGRlZmluZWQsIGlkKSB8fCBoYXNQcm9wKHJlZ2lzdHJ5LCBpZCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9Pbmx5IGFsbG93IHVuZGVmIG9uIHRvcCBsZXZlbCByZXF1aXJlIGNhbGxzCiAgICAgICAgICAgICAgICBpZiAoIXJlbE1hcCkgewogICAgICAgICAgICAgICAgICAgIGxvY2FsUmVxdWlyZS51bmRlZiA9IGZ1bmN0aW9uIChpZCkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgYW55IHdhaXRpbmcgZGVmaW5lKCkgY2FsbHMgdG8gdGhpcyBjb250ZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAvL2ZpeCBmb3IgIzQwOAogICAgICAgICAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtYXAgPSBtYWtlTW9kdWxlTWFwKGlkLCByZWxNYXAsIHRydWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kID0gZ2V0T3duKHJlZ2lzdHJ5LCBpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBtb2QudW5kZWZlZCA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB1cmxGZXRjaGVkW21hcC51cmxdOwogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgdW5kZWZFdmVudHNbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9DbGVhbiBxdWV1ZWQgZGVmaW5lcyB0b28uIEdvIGJhY2t3YXJkcwogICAgICAgICAgICAgICAgICAgICAgICAvL2luIGFycmF5IHNvIHRoYXQgdGhlIHNwbGljZXMgZG8gbm90CiAgICAgICAgICAgICAgICAgICAgICAgIC8vbWVzcyB1cCB0aGUgaXRlcmF0aW9uLgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUmV2ZXJzZShkZWZRdWV1ZSwgZnVuY3Rpb24oYXJncywgaSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmUXVldWUuc3BsaWNlKGksIDEpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIGNvbnRleHQuZGVmUXVldWVNYXBbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9Ib2xkIG9uIHRvIGxpc3RlbmVycyBpbiBjYXNlIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9tb2R1bGUgd2lsbCBiZSBhdHRlbXB0ZWQgdG8gYmUgcmVsb2FkZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdXNpbmcgYSBkaWZmZXJlbnQgY29uZmlnLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5ldmVudHMuZGVmaW5lZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVmRXZlbnRzW2lkXSA9IG1vZC5ldmVudHM7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbFJlcXVpcmU7CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGVkIHRvIGVuYWJsZSBhIG1vZHVsZSBpZiBpdCBpcyBzdGlsbCBpbiB0aGUgcmVnaXN0cnkKICAgICAgICAgICAgICogYXdhaXRpbmcgZW5hYmxlbWVudC4gQSBzZWNvbmQgYXJnLCBwYXJlbnQsIHRoZSBwYXJlbnQgbW9kdWxlLAogICAgICAgICAgICAgKiBpcyBwYXNzZWQgaW4gZm9yIGNvbnRleHQsIHdoZW4gdGhpcyBtZXRob2QgaXMgb3ZlcnJpZGRlbiBieQogICAgICAgICAgICAgKiB0aGUgb3B0aW1pemVyLiBOb3Qgc2hvd24gaGVyZSB0byBrZWVwIGNvZGUgY29tcGFjdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGVuYWJsZTogZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgZGVwTWFwLmlkKTsKICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICBnZXRNb2R1bGUoZGVwTWFwKS5lbmFibGUoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdXNlZCBieSBlbnZpcm9ubWVudCBhZGFwdGVycyB0byBjb21wbGV0ZSBhIGxvYWQgZXZlbnQuCiAgICAgICAgICAgICAqIEEgbG9hZCBldmVudCBjb3VsZCBiZSBhIHNjcmlwdCBsb2FkIG9yIGp1c3QgYSBsb2FkIHBhc3MgZnJvbSBhIHN5bmNocm9ub3VzCiAgICAgICAgICAgICAqIGxvYWQgY2FsbC4KICAgICAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSB0byBwb3RlbnRpYWxseSBjb21wbGV0ZS4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNvbXBsZXRlTG9hZDogZnVuY3Rpb24gKG1vZHVsZU5hbWUpIHsKICAgICAgICAgICAgICAgIHZhciBmb3VuZCwgYXJncywgbW9kLAogICAgICAgICAgICAgICAgICAgIHNoaW0gPSBnZXRPd24oY29uZmlnLnNoaW0sIG1vZHVsZU5hbWUpIHx8IHt9LAogICAgICAgICAgICAgICAgICAgIHNoRXhwb3J0cyA9IHNoaW0uZXhwb3J0czsKCiAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICB3aGlsZSAoZGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgYXJncyA9IGRlZlF1ZXVlLnNoaWZ0KCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgYXJnc1swXSA9IG1vZHVsZU5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vSWYgYWxyZWFkeSBmb3VuZCBhbiBhbm9ueW1vdXMgbW9kdWxlIGFuZCBib3VuZCBpdAogICAgICAgICAgICAgICAgICAgICAgICAvL3RvIHRoaXMgbmFtZSwgdGhlbiB0aGlzIGlzIHNvbWUgb3RoZXIgYW5vbiBtb2R1bGUKICAgICAgICAgICAgICAgICAgICAgICAgLy93YWl0aW5nIGZvciBpdHMgY29tcGxldGVMb2FkIHRvIGZpcmUuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmb3VuZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJnc1swXSA9PT0gbW9kdWxlTmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0ZvdW5kIG1hdGNoaW5nIGRlZmluZSBjYWxsIGZvciB0aGlzIHNjcmlwdCEKICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgY2FsbEdldE1vZHVsZShhcmdzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQuZGVmUXVldWVNYXAgPSB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIHRoaXMgYWZ0ZXIgdGhlIGN5Y2xlIG9mIGNhbGxHZXRNb2R1bGUgaW4gY2FzZSB0aGUgcmVzdWx0CiAgICAgICAgICAgICAgICAvL29mIHRob3NlIGNhbGxzL2luaXQgY2FsbHMgY2hhbmdlcyB0aGUgcmVnaXN0cnkuCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmICghZm91bmQgJiYgIWhhc1Byb3AoZGVmaW5lZCwgbW9kdWxlTmFtZSkgJiYgbW9kICYmICFtb2QuaW5pdGVkKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbmZpZy5lbmZvcmNlRGVmaW5lICYmICghc2hFeHBvcnRzIHx8ICFnZXRHbG9iYWwoc2hFeHBvcnRzKSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc1BhdGhGYWxsYmFjayhtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub2RlZmluZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdObyBkZWZpbmUgY2FsbCBmb3IgJyArIG1vZHVsZU5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFttb2R1bGVOYW1lXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9BIHNjcmlwdCB0aGF0IGRvZXMgbm90IGNhbGwgZGVmaW5lKCksIHNvIGp1c3Qgc2ltdWxhdGUKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGUgY2FsbCBmb3IgaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoW21vZHVsZU5hbWUsIChzaGltLmRlcHMgfHwgW10pLCBzaGltLmV4cG9ydHNGbl0pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBjaGVja0xvYWRlZCgpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIENvbnZlcnRzIGEgbW9kdWxlIG5hbWUgdG8gYSBmaWxlIHBhdGguIFN1cHBvcnRzIGNhc2VzIHdoZXJlCiAgICAgICAgICAgICAqIG1vZHVsZU5hbWUgbWF5IGFjdHVhbGx5IGJlIGp1c3QgYW4gVVJMLgogICAgICAgICAgICAgKiBOb3RlIHRoYXQgaXQgKipkb2VzIG5vdCoqIGNhbGwgbm9ybWFsaXplIG9uIHRoZSBtb2R1bGVOYW1lLAogICAgICAgICAgICAgKiBpdCBpcyBhc3N1bWVkIHRvIGhhdmUgYWxyZWFkeSBiZWVuIG5vcm1hbGl6ZWQuIFRoaXMgaXMgYW4KICAgICAgICAgICAgICogaW50ZXJuYWwgQVBJLCBub3QgYSBwdWJsaWMgb25lLiBVc2UgdG9VcmwgZm9yIHRoZSBwdWJsaWMgQVBJLgogICAgICAgICAgICAgKi8KICAgICAgICAgICAgbmFtZVRvVXJsOiBmdW5jdGlvbiAobW9kdWxlTmFtZSwgZXh0LCBza2lwRXh0KSB7CiAgICAgICAgICAgICAgICB2YXIgcGF0aHMsIHN5bXMsIGksIHBhcmVudE1vZHVsZSwgdXJsLAogICAgICAgICAgICAgICAgICAgIHBhcmVudFBhdGgsIGJ1bmRsZUlkLAogICAgICAgICAgICAgICAgICAgIHBrZ01haW4gPSBnZXRPd24oY29uZmlnLnBrZ3MsIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmIChwa2dNYWluKSB7CiAgICAgICAgICAgICAgICAgICAgbW9kdWxlTmFtZSA9IHBrZ01haW47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgYnVuZGxlSWQgPSBnZXRPd24oYnVuZGxlc01hcCwgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkLCBleHQsIHNraXBFeHQpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vSWYgYSBjb2xvbiBpcyBpbiB0aGUgVVJMLCBpdCBpbmRpY2F0ZXMgYSBwcm90b2NvbCBpcyB1c2VkIGFuZCBpdCBpcyBqdXN0CiAgICAgICAgICAgICAgICAvL2FuIFVSTCB0byBhIGZpbGUsIG9yIGlmIGl0IHN0YXJ0cyB3aXRoIGEgc2xhc2gsIGNvbnRhaW5zIGEgcXVlcnkgYXJnIChpLmUuID8pCiAgICAgICAgICAgICAgICAvL29yIGVuZHMgd2l0aCAuanMsIHRoZW4gYXNzdW1lIHRoZSB1c2VyIG1lYW50IHRvIHVzZSBhbiB1cmwgYW5kIG5vdCBhIG1vZHVsZSBpZC4KICAgICAgICAgICAgICAgIC8vVGhlIHNsYXNoIGlzIGltcG9ydGFudCBmb3IgcHJvdG9jb2wtbGVzcyBVUkxzIGFzIHdlbGwgYXMgZnVsbCBwYXRocy4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIHBsYWluIHBhdGgsIG5vdCBtb2R1bGUgbmFtZSBsb29rdXAsIHNvIGp1c3QgcmV0dXJuIGl0LgogICAgICAgICAgICAgICAgICAgIC8vQWRkIGV4dGVuc2lvbiBpZiBpdCBpcyBpbmNsdWRlZC4gVGhpcyBpcyBhIGJpdCB3b25reSwgb25seSBub24tLmpzIHRoaW5ncyBwYXNzCiAgICAgICAgICAgICAgICAgICAgLy9hbiBleHRlbnNpb24sIHRoaXMgbWV0aG9kIHByb2JhYmx5IG5lZWRzIHRvIGJlIHJld29ya2VkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IG1vZHVsZU5hbWUgKyAoZXh0IHx8ICcnKTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgLy9BIG1vZHVsZSB0aGF0IG5lZWRzIHRvIGJlIGNvbnZlcnRlZCB0byBhIHBhdGguCiAgICAgICAgICAgICAgICAgICAgcGF0aHMgPSBjb25maWcucGF0aHM7CgogICAgICAgICAgICAgICAgICAgIHN5bXMgPSBtb2R1bGVOYW1lLnNwbGl0KCcvJyk7CiAgICAgICAgICAgICAgICAgICAgLy9Gb3IgZWFjaCBtb2R1bGUgbmFtZSBzZWdtZW50LCBzZWUgaWYgdGhlcmUgaXMgYSBwYXRoCiAgICAgICAgICAgICAgICAgICAgLy9yZWdpc3RlcmVkIGZvciBpdC4gU3RhcnQgd2l0aCBtb3N0IHNwZWNpZmljIG5hbWUKICAgICAgICAgICAgICAgICAgICAvL2FuZCB3b3JrIHVwIGZyb20gaXQuCiAgICAgICAgICAgICAgICAgICAgZm9yIChpID0gc3ltcy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50TW9kdWxlID0gc3ltcy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gZ2V0T3duKHBhdGhzLCBwYXJlbnRNb2R1bGUpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAocGFyZW50UGF0aCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiBhbiBhcnJheSwgaXQgbWVhbnMgdGhlcmUgYXJlIGEgZmV3IGNob2ljZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0Nob29zZSB0aGUgb25lIHRoYXQgaXMgZGVzaXJlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzQXJyYXkocGFyZW50UGF0aCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gcGFyZW50UGF0aFswXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXMuc3BsaWNlKDAsIGksIHBhcmVudFBhdGgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIC8vSm9pbiB0aGUgcGF0aCBwYXJ0cyB0b2dldGhlciwgdGhlbiBmaWd1cmUgb3V0IGlmIGJhc2VVcmwgaXMgbmVlZGVkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IHN5bXMuam9pbignLycpOwogICAgICAgICAgICAgICAgICAgIHVybCArPSAoZXh0IHx8ICgvXmRhdGFcOnxcPy8udGVzdCh1cmwpIHx8IHNraXBFeHQgPyAnJyA6ICcuanMnKSk7CiAgICAgICAgICAgICAgICAgICAgdXJsID0gKHVybC5jaGFyQXQoMCkgPT09ICcvJyB8fCB1cmwubWF0Y2goL15bXHdcK1wuXC1dKzovKSA/ICcnIDogY29uZmlnLmJhc2VVcmwpICsgdXJsOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBjb25maWcudXJsQXJncyA/IHVybCArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKHVybC5pbmRleE9mKCc/JykgPT09IC0xID8gJz8nIDogJyYnKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLnVybEFyZ3MpIDogdXJsOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLy9EZWxlZ2F0ZXMgdG8gcmVxLmxvYWQuIEJyb2tlbiBvdXQgYXMgYSBzZXBhcmF0ZSBmdW5jdGlvbiB0bwogICAgICAgICAgICAvL2FsbG93IG92ZXJyaWRpbmcgaW4gdGhlIG9wdGltaXplci4KICAgICAgICAgICAgbG9hZDogZnVuY3Rpb24gKGlkLCB1cmwpIHsKICAgICAgICAgICAgICAgIHJlcS5sb2FkKGNvbnRleHQsIGlkLCB1cmwpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIEV4ZWN1dGVzIGEgbW9kdWxlIGNhbGxiYWNrIGZ1bmN0aW9uLiBCcm9rZW4gb3V0IGFzIGEgc2VwYXJhdGUgZnVuY3Rpb24KICAgICAgICAgICAgICogc29sZWx5IHRvIGFsbG93IHRoZSBidWlsZCBzeXN0ZW0gdG8gc2VxdWVuY2UgdGhlIGZpbGVzIGluIHRoZSBidWlsdAogICAgICAgICAgICAgKiBsYXllciBpbiB0aGUgcmlnaHQgc2VxdWVuY2UuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBleGVjQ2I6IGZ1bmN0aW9uIChuYW1lLCBjYWxsYmFjaywgYXJncywgZXhwb3J0cykgewogICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrLmFwcGx5KGV4cG9ydHMsIGFyZ3MpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIGNhbGxiYWNrIGZvciBzY3JpcHQgbG9hZHMsIHVzZWQgdG8gY2hlY2sgc3RhdHVzIG9mIGxvYWRpbmcuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2dCB0aGUgZXZlbnQgZnJvbSB0aGUgYnJvd3NlciBmb3IgdGhlIHNjcmlwdAogICAgICAgICAgICAgKiB0aGF0IHdhcyBsb2FkZWQuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdExvYWQ6IGZ1bmN0aW9uIChldnQpIHsKICAgICAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgICAgIC8vYWxsIG9sZCBicm93c2VycyB3aWxsIGJlIHN1cHBvcnRlZCwgYnV0IHRoaXMgb25lIHdhcyBlYXN5IGVub3VnaAogICAgICAgICAgICAgICAgLy90byBzdXBwb3J0IGFuZCBzdGlsbCBtYWtlcyBzZW5zZS4KICAgICAgICAgICAgICAgIGlmIChldnQudHlwZSA9PT0gJ2xvYWQnIHx8CiAgICAgICAgICAgICAgICAgICAgICAgIChyZWFkeVJlZ0V4cC50ZXN0KChldnQuY3VycmVudFRhcmdldCB8fCBldnQuc3JjRWxlbWVudCkucmVhZHlTdGF0ZSkpKSB7CiAgICAgICAgICAgICAgICAgICAgLy9SZXNldCBpbnRlcmFjdGl2ZSBzY3JpcHQgc28gYSBzY3JpcHQgbm9kZSBpcyBub3QgaGVsZCBvbnRvIGZvcgogICAgICAgICAgICAgICAgICAgIC8vdG8gbG9uZy4KICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCA9IG51bGw7CgogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvdXQgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSBhbmQgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBnZXRTY3JpcHREYXRhKGV2dCk7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQoZGF0YS5pZCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGJhY2sgZm9yIHNjcmlwdCBlcnJvcnMuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdEVycm9yOiBmdW5jdGlvbiAoZXZ0KSB7CiAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IGdldFNjcmlwdERhdGEoZXZ0KTsKICAgICAgICAgICAgICAgIGlmICghaGFzUGF0aEZhbGxiYWNrKGRhdGEuaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmVudHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24odmFsdWUsIGtleSkgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoa2V5LmluZGV4T2YoJ19AcicpICE9PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHZhbHVlLmRlcE1hcHMsIGZ1bmN0aW9uKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZXBNYXAuaWQgPT09IGRhdGEuaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50cy5wdXNoKGtleSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ3NjcmlwdGVycm9yJywgJ1NjcmlwdCBlcnJvciBmb3IgIicgKyBkYXRhLmlkICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhcmVudHMubGVuZ3RoID8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIsIG5lZWRlZCBieTogJyArIHBhcmVudHMuam9pbignLCAnKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICciJyksIGV2dCwgW2RhdGEuaWRdKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBjb250ZXh0LnJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKCk7CiAgICAgICAgcmV0dXJuIGNvbnRleHQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBNYWluIGVudHJ5IHBvaW50LgogICAgICoKICAgICAqIElmIHRoZSBvbmx5IGFyZ3VtZW50IHRvIHJlcXVpcmUgaXMgYSBzdHJpbmcsIHRoZW4gdGhlIG1vZHVsZSB0aGF0CiAgICAgKiBpcyByZXByZXNlbnRlZCBieSB0aGF0IHN0cmluZyBpcyBmZXRjaGVkIGZvciB0aGUgYXBwcm9wcmlhdGUgY29udGV4dC4KICAgICAqCiAgICAgKiBJZiB0aGUgZmlyc3QgYXJndW1lbnQgaXMgYW4gYXJyYXksIHRoZW4gaXQgd2lsbCBiZSB0cmVhdGVkIGFzIGFuIGFycmF5CiAgICAgKiBvZiBkZXBlbmRlbmN5IHN0cmluZyBuYW1lcyB0byBmZXRjaC4gQW4gb3B0aW9uYWwgZnVuY3Rpb24gY2FsbGJhY2sgY2FuCiAgICAgKiBiZSBzcGVjaWZpZWQgdG8gZXhlY3V0ZSB3aGVuIGFsbCBvZiB0aG9zZSBkZXBlbmRlbmNpZXMgYXJlIGF2YWlsYWJsZS4KICAgICAqCiAgICAgKiBNYWtlIGEgbG9jYWwgcmVxIHZhcmlhYmxlIHRvIGhlbHAgQ2FqYSBjb21wbGlhbmNlIChpdCBhc3N1bWVzIHRoaW5ncwogICAgICogb24gYSByZXF1aXJlIHRoYXQgYXJlIG5vdCBzdGFuZGFyZGl6ZWQpLCBhbmQgdG8gZ2l2ZSBhIHNob3J0CiAgICAgKiBuYW1lIGZvciBtaW5pZmljYXRpb24vbG9jYWwgc2NvcGUgdXNlLgogICAgICovCiAgICByZXEgPSByZXF1aXJlanMgPSBmdW5jdGlvbiAoZGVwcywgY2FsbGJhY2ssIGVycmJhY2ssIG9wdGlvbmFsKSB7CgogICAgICAgIC8vRmluZCB0aGUgcmlnaHQgY29udGV4dCwgdXNlIGRlZmF1bHQKICAgICAgICB2YXIgY29udGV4dCwgY29uZmlnLAogICAgICAgICAgICBjb250ZXh0TmFtZSA9IGRlZkNvbnRleHROYW1lOwoKICAgICAgICAvLyBEZXRlcm1pbmUgaWYgaGF2ZSBjb25maWcgb2JqZWN0IGluIHRoZSBjYWxsLgogICAgICAgIGlmICghaXNBcnJheShkZXBzKSAmJiB0eXBlb2YgZGVwcyAhPT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgLy8gZGVwcyBpcyBhIGNvbmZpZyBvYmplY3QKICAgICAgICAgICAgY29uZmlnID0gZGVwczsKICAgICAgICAgICAgaWYgKGlzQXJyYXkoY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAvLyBBZGp1c3QgYXJncyBpZiB0aGVyZSBhcmUgZGVwZW5kZW5jaWVzCiAgICAgICAgICAgICAgICBkZXBzID0gY2FsbGJhY2s7CiAgICAgICAgICAgICAgICBjYWxsYmFjayA9IGVycmJhY2s7CiAgICAgICAgICAgICAgICBlcnJiYWNrID0gb3B0aW9uYWw7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBkZXBzID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmIChjb25maWcgJiYgY29uZmlnLmNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dE5hbWUgPSBjb25maWcuY29udGV4dDsKICAgICAgICB9CgogICAgICAgIGNvbnRleHQgPSBnZXRPd24oY29udGV4dHMsIGNvbnRleHROYW1lKTsKICAgICAgICBpZiAoIWNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dCA9IGNvbnRleHRzW2NvbnRleHROYW1lXSA9IHJlcS5zLm5ld0NvbnRleHQoY29udGV4dE5hbWUpOwogICAgICAgIH0KCiAgICAgICAgaWYgKGNvbmZpZykgewogICAgICAgICAgICBjb250ZXh0LmNvbmZpZ3VyZShjb25maWcpOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIGNvbnRleHQucmVxdWlyZShkZXBzLCBjYWxsYmFjaywgZXJyYmFjayk7CiAgICB9OwoKICAgIC8qKgogICAgICogU3VwcG9ydCByZXF1aXJlLmNvbmZpZygpIHRvIG1ha2UgaXQgZWFzaWVyIHRvIGNvb3BlcmF0ZSB3aXRoIG90aGVyCiAgICAgKiBBTUQgbG9hZGVycyBvbiBnbG9iYWxseSBhZ3JlZWQgbmFtZXMuCiAgICAgKi8KICAgIHJlcS5jb25maWcgPSBmdW5jdGlvbiAoY29uZmlnKSB7CiAgICAgICAgcmV0dXJuIHJlcShjb25maWcpOwogICAgfTsKCiAgICAvKioKICAgICAqIEV4ZWN1dGUgc29tZXRoaW5nIGFmdGVyIHRoZSBjdXJyZW50IHRpY2sKICAgICAqIG9mIHRoZSBldmVudCBsb29wLiBPdmVycmlkZSBmb3Igb3RoZXIgZW52cwogICAgICogdGhhdCBoYXZlIGEgYmV0dGVyIHNvbHV0aW9uIHRoYW4gc2V0VGltZW91dC4KICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBmbiBmdW5jdGlvbiB0byBleGVjdXRlIGxhdGVyLgogICAgICovCiAgICByZXEubmV4dFRpY2sgPSB0eXBlb2Ygc2V0VGltZW91dCAhPT0gJ3VuZGVmaW5lZCcgPyBmdW5jdGlvbiAoZm4pIHsKICAgICAgICBzZXRUaW1lb3V0KGZuLCA0KTsKICAgIH0gOiBmdW5jdGlvbiAoZm4pIHsgZm4oKTsgfTsKCiAgICAvKioKICAgICAqIEV4cG9ydCByZXF1aXJlIGFzIGEgZ2xvYmFsLCBidXQgb25seSBpZiBpdCBkb2VzIG5vdCBhbHJlYWR5IGV4aXN0LgogICAgICovCiAgICBpZiAoIXJlcXVpcmUpIHsKICAgICAgICByZXF1aXJlID0gcmVxOwogICAgfQoKICAgIHJlcS52ZXJzaW9uID0gdmVyc2lvbjsKCiAgICAvL1VzZWQgdG8gZmlsdGVyIG91dCBkZXBlbmRlbmNpZXMgdGhhdCBhcmUgYWxyZWFkeSBwYXRocy4KICAgIHJlcS5qc0V4dFJlZ0V4cCA9IC9eXC98OnxcP3xcLmpzJC87CiAgICByZXEuaXNCcm93c2VyID0gaXNCcm93c2VyOwogICAgcyA9IHJlcS5zID0gewogICAgICAgIGNvbnRleHRzOiBjb250ZXh0cywKICAgICAgICBuZXdDb250ZXh0OiBuZXdDb250ZXh0CiAgICB9OwoKICAgIC8vQ3JlYXRlIGRlZmF1bHQgY29udGV4dC4KICAgIHJlcSh7fSk7CgogICAgLy9FeHBvcnRzIHNvbWUgY29udGV4dC1zZW5zaXRpdmUgbWV0aG9kcyBvbiBnbG9iYWwgcmVxdWlyZS4KICAgIGVhY2goWwogICAgICAgICd0b1VybCcsCiAgICAgICAgJ3VuZGVmJywKICAgICAgICAnZGVmaW5lZCcsCiAgICAgICAgJ3NwZWNpZmllZCcKICAgIF0sIGZ1bmN0aW9uIChwcm9wKSB7CiAgICAgICAgLy9SZWZlcmVuY2UgZnJvbSBjb250ZXh0cyBpbnN0ZWFkIG9mIGVhcmx5IGJpbmRpbmcgdG8gZGVmYXVsdCBjb250ZXh0LAogICAgICAgIC8vc28gdGhhdCBkdXJpbmcgYnVpbGRzLCB0aGUgbGF0ZXN0IGluc3RhbmNlIG9mIHRoZSBkZWZhdWx0IGNvbnRleHQKICAgICAgICAvL3dpdGggaXRzIGNvbmZpZyBnZXRzIHVzZWQuCiAgICAgICAgcmVxW3Byb3BdID0gZnVuY3Rpb24gKCkgewogICAgICAgICAgICB2YXIgY3R4ID0gY29udGV4dHNbZGVmQ29udGV4dE5hbWVdOwogICAgICAgICAgICByZXR1cm4gY3R4LnJlcXVpcmVbcHJvcF0uYXBwbHkoY3R4LCBhcmd1bWVudHMpOwogICAgICAgIH07CiAgICB9KTsKCiAgICBpZiAoaXNCcm93c2VyKSB7CiAgICAgICAgaGVhZCA9IHMuaGVhZCA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdoZWFkJylbMF07CiAgICAgICAgLy9JZiBCQVNFIHRhZyBpcyBpbiBwbGF5LCB1c2luZyBhcHBlbmRDaGlsZCBpcyBhIHByb2JsZW0gZm9yIElFNi4KICAgICAgICAvL1doZW4gdGhhdCBicm93c2VyIGRpZXMsIHRoaXMgY2FuIGJlIHJlbW92ZWQuIERldGFpbHMgaW4gdGhpcyBqUXVlcnkgYnVnOgogICAgICAgIC8vaHR0cDovL2Rldi5qcXVlcnkuY29tL3RpY2tldC8yNzA5CiAgICAgICAgYmFzZUVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnYmFzZScpWzBdOwogICAgICAgIGlmIChiYXNlRWxlbWVudCkgewogICAgICAgICAgICBoZWFkID0gcy5oZWFkID0gYmFzZUVsZW1lbnQucGFyZW50Tm9kZTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBBbnkgZXJyb3JzIHRoYXQgcmVxdWlyZSBleHBsaWNpdGx5IGdlbmVyYXRlcyB3aWxsIGJlIHBhc3NlZCB0byB0aGlzCiAgICAgKiBmdW5jdGlvbi4gSW50ZXJjZXB0L292ZXJyaWRlIGl0IGlmIHlvdSB3YW50IGN1c3RvbSBlcnJvciBoYW5kbGluZy4KICAgICAqIEBwYXJhbSB7RXJyb3J9IGVyciB0aGUgZXJyb3Igb2JqZWN0LgogICAgICovCiAgICByZXEub25FcnJvciA9IGRlZmF1bHRPbkVycm9yOwoKICAgIC8qKgogICAgICogQ3JlYXRlcyB0aGUgbm9kZSBmb3IgdGhlIGxvYWQgY29tbWFuZC4gT25seSB1c2VkIGluIGJyb3dzZXIgZW52cy4KICAgICAqLwogICAgcmVxLmNyZWF0ZU5vZGUgPSBmdW5jdGlvbiAoY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgbm9kZSA9IGNvbmZpZy54aHRtbCA/CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCAnaHRtbDpzY3JpcHQnKSA6CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsKICAgICAgICBub2RlLnR5cGUgPSBjb25maWcuc2NyaXB0VHlwZSB8fCAndGV4dC9qYXZhc2NyaXB0JzsKICAgICAgICBub2RlLmNoYXJzZXQgPSAndXRmLTgnOwogICAgICAgIG5vZGUuYXN5bmMgPSB0cnVlOwogICAgICAgIHJldHVybiBub2RlOwogICAgfTsKCiAgICAvKioKICAgICAqIERvZXMgdGhlIHJlcXVlc3QgdG8gbG9hZCBhIG1vZHVsZSBmb3IgdGhlIGJyb3dzZXIgY2FzZS4KICAgICAqIE1ha2UgdGhpcyBhIHNlcGFyYXRlIGZ1bmN0aW9uIHRvIGFsbG93IG90aGVyIGVudmlyb25tZW50cwogICAgICogdG8gb3ZlcnJpZGUgaXQuCiAgICAgKgogICAgICogQHBhcmFtIHtPYmplY3R9IGNvbnRleHQgdGhlIHJlcXVpcmUgY29udGV4dCB0byBmaW5kIHN0YXRlLgogICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZS4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSB1cmwgdGhlIFVSTCB0byB0aGUgbW9kdWxlLgogICAgICovCiAgICByZXEubG9hZCA9IGZ1bmN0aW9uIChjb250ZXh0LCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgY29uZmlnID0gKGNvbnRleHQgJiYgY29udGV4dC5jb25maWcpIHx8IHt9LAogICAgICAgICAgICBub2RlOwogICAgICAgIGlmIChpc0Jyb3dzZXIpIHsKICAgICAgICAgICAgLy9JbiB0aGUgYnJvd3NlciBzbyB1c2UgYSBzY3JpcHQgdGFnCiAgICAgICAgICAgIG5vZGUgPSByZXEuY3JlYXRlTm9kZShjb25maWcsIG1vZHVsZU5hbWUsIHVybCk7CiAgICAgICAgICAgIGlmIChjb25maWcub25Ob2RlQ3JlYXRlZCkgewogICAgICAgICAgICAgICAgY29uZmlnLm9uTm9kZUNyZWF0ZWQobm9kZSwgY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcsIGNvbnRleHQuY29udGV4dE5hbWUpOwogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJywgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAvL1NldCB1cCBsb2FkIGxpc3RlbmVyLiBUZXN0IGF0dGFjaEV2ZW50IGZpcnN0IGJlY2F1c2UgSUU5IGhhcwogICAgICAgICAgICAvL2Egc3VidGxlIGlzc3VlIGluIGl0cyBhZGRFdmVudExpc3RlbmVyIGFuZCBzY3JpcHQgb25sb2FkIGZpcmluZ3MKICAgICAgICAgICAgLy90aGF0IGRvIG5vdCBtYXRjaCB0aGUgYmVoYXZpb3Igb2YgYWxsIG90aGVyIGJyb3dzZXJzIHdpdGgKICAgICAgICAgICAgLy9hZGRFdmVudExpc3RlbmVyIHN1cHBvcnQsIHdoaWNoIGZpcmUgdGhlIG9ubG9hZCBldmVudCBmb3IgYQogICAgICAgICAgICAvL3NjcmlwdCByaWdodCBhZnRlciB0aGUgc2NyaXB0IGV4ZWN1dGlvbi4gU2VlOgogICAgICAgICAgICAvL2h0dHBzOi8vY29ubmVjdC5taWNyb3NvZnQuY29tL0lFL2ZlZWRiYWNrL2RldGFpbHMvNjQ4MDU3L3NjcmlwdC1vbmxvYWQtZXZlbnQtaXMtbm90LWZpcmVkLWltbWVkaWF0ZWx5LWFmdGVyLXNjcmlwdC1leGVjdXRpb24KICAgICAgICAgICAgLy9VTkZPUlRVTkFURUxZIE9wZXJhIGltcGxlbWVudHMgYXR0YWNoRXZlbnQgYnV0IGRvZXMgbm90IGZvbGxvdyB0aGUgc2NyaXB0CiAgICAgICAgICAgIC8vc2NyaXB0IGV4ZWN1dGlvbiBtb2RlLgogICAgICAgICAgICBpZiAobm9kZS5hdHRhY2hFdmVudCAmJgogICAgICAgICAgICAgICAgICAgIC8vQ2hlY2sgaWYgbm9kZS5hdHRhY2hFdmVudCBpcyBhcnRpZmljaWFsbHkgYWRkZWQgYnkgY3VzdG9tIHNjcmlwdCBvcgogICAgICAgICAgICAgICAgICAgIC8vbmF0aXZlbHkgc3VwcG9ydGVkIGJ5IGJyb3dzZXIKICAgICAgICAgICAgICAgICAgICAvL3JlYWQgaHR0cHM6Ly9naXRodWIuY29tL2pyYnVya2UvcmVxdWlyZWpzL2lzc3Vlcy8xODcKICAgICAgICAgICAgICAgICAgICAvL2lmIHdlIGNhbiBOT1QgZmluZCBbbmF0aXZlIGNvZGVdIHRoZW4gaXQgbXVzdCBOT1QgbmF0aXZlbHkgc3VwcG9ydGVkLgogICAgICAgICAgICAgICAgICAgIC8vaW4gSUU4LCBub2RlLmF0dGFjaEV2ZW50IGRvZXMgbm90IGhhdmUgdG9TdHJpbmcoKQogICAgICAgICAgICAgICAgICAgIC8vTm90ZSB0aGUgdGVzdCBmb3IgIltuYXRpdmUgY29kZSIgd2l0aCBubyBjbG9zaW5nIGJyYWNlLCBzZWU6CiAgICAgICAgICAgICAgICAgICAgLy9odHRwczovL2dpdGh1Yi5jb20vanJidXJrZS9yZXF1aXJlanMvaXNzdWVzLzI3MwogICAgICAgICAgICAgICAgICAgICEobm9kZS5hdHRhY2hFdmVudC50b1N0cmluZyAmJiBub2RlLmF0dGFjaEV2ZW50LnRvU3RyaW5nKCkuaW5kZXhPZignW25hdGl2ZSBjb2RlJykgPCAwKSAmJgogICAgICAgICAgICAgICAgICAgICFpc09wZXJhKSB7CiAgICAgICAgICAgICAgICAvL1Byb2JhYmx5IElFLiBJRSAoYXQgbGVhc3QgNi04KSBkbyBub3QgZmlyZQogICAgICAgICAgICAgICAgLy9zY3JpcHQgb25sb2FkIHJpZ2h0IGFmdGVyIGV4ZWN1dGluZyB0aGUgc2NyaXB0LCBzbwogICAgICAgICAgICAgICAgLy93ZSBjYW5ub3QgdGllIHRoZSBhbm9ueW1vdXMgZGVmaW5lIGNhbGwgdG8gYSBuYW1lLgogICAgICAgICAgICAgICAgLy9Ib3dldmVyLCBJRSByZXBvcnRzIHRoZSBzY3JpcHQgYXMgYmVpbmcgaW4gJ2ludGVyYWN0aXZlJwogICAgICAgICAgICAgICAgLy9yZWFkeVN0YXRlIGF0IHRoZSB0aW1lIG9mIHRoZSBkZWZpbmUgY2FsbC4KICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKCiAgICAgICAgICAgICAgICBub2RlLmF0dGFjaEV2ZW50KCdvbnJlYWR5c3RhdGVjaGFuZ2UnLCBjb250ZXh0Lm9uU2NyaXB0TG9hZCk7CiAgICAgICAgICAgICAgICAvL0l0IHdvdWxkIGJlIGdyZWF0IHRvIGFkZCBhbiBlcnJvciBoYW5kbGVyIGhlcmUgdG8gY2F0Y2gKICAgICAgICAgICAgICAgIC8vNDA0cyBpbiBJRTkrLiBIb3dldmVyLCBvbnJlYWR5c3RhdGVjaGFuZ2Ugd2lsbCBmaXJlIGJlZm9yZQogICAgICAgICAgICAgICAgLy90aGUgZXJyb3IgaGFuZGxlciwgc28gdGhhdCBkb2VzIG5vdCBoZWxwLiBJZiBhZGRFdmVudExpc3RlbmVyCiAgICAgICAgICAgICAgICAvL2lzIHVzZWQsIHRoZW4gSUUgd2lsbCBmaXJlIGVycm9yIGJlZm9yZSBsb2FkLCBidXQgd2UgY2Fubm90CiAgICAgICAgICAgICAgICAvL3VzZSB0aGF0IHBhdGh3YXkgZ2l2ZW4gdGhlIGNvbm5lY3QubWljcm9zb2Z0LmNvbSBpc3N1ZQogICAgICAgICAgICAgICAgLy9tZW50aW9uZWQgYWJvdmUgYWJvdXQgbm90IGRvaW5nIHRoZSAnc2NyaXB0IGV4ZWN1dGUsCiAgICAgICAgICAgICAgICAvL3RoZW4gZmlyZSB0aGUgc2NyaXB0IGxvYWQgZXZlbnQgbGlzdGVuZXIgYmVmb3JlIGV4ZWN1dGUKICAgICAgICAgICAgICAgIC8vbmV4dCBzY3JpcHQnIHRoYXQgb3RoZXIgYnJvd3NlcnMgZG8uCiAgICAgICAgICAgICAgICAvL0Jlc3QgaG9wZTogSUUxMCBmaXhlcyB0aGUgaXNzdWVzLAogICAgICAgICAgICAgICAgLy9hbmQgdGhlbiBkZXN0cm95cyBhbGwgaW5zdGFsbHMgb2YgSUUgNi05LgogICAgICAgICAgICAgICAgLy9ub2RlLmF0dGFjaEV2ZW50KCdvbmVycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIGNvbnRleHQub25TY3JpcHRMb2FkLCBmYWxzZSk7CiAgICAgICAgICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbm9kZS5zcmMgPSB1cmw7CgogICAgICAgICAgICAvL0ZvciBzb21lIGNhY2hlIGNhc2VzIGluIElFIDYtOCwgdGhlIHNjcmlwdCBleGVjdXRlcyBiZWZvcmUgdGhlIGVuZAogICAgICAgICAgICAvL29mIHRoZSBhcHBlbmRDaGlsZCBleGVjdXRpb24sIHNvIHRvIHRpZSBhbiBhbm9ueW1vdXMgZGVmaW5lCiAgICAgICAgICAgIC8vY2FsbCB0byB0aGUgbW9kdWxlIG5hbWUgKHdoaWNoIGlzIHN0b3JlZCBvbiB0aGUgbm9kZSksIGhvbGQgb24KICAgICAgICAgICAgLy90byBhIHJlZmVyZW5jZSB0byB0aGlzIG5vZGUsIGJ1dCBjbGVhciBhZnRlciB0aGUgRE9NIGluc2VydGlvbi4KICAgICAgICAgICAgY3VycmVudGx5QWRkaW5nU2NyaXB0ID0gbm9kZTsKICAgICAgICAgICAgaWYgKGJhc2VFbGVtZW50KSB7CiAgICAgICAgICAgICAgICBoZWFkLmluc2VydEJlZm9yZShub2RlLCBiYXNlRWxlbWVudCk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBoZWFkLmFwcGVuZENoaWxkKG5vZGUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGN1cnJlbnRseUFkZGluZ1NjcmlwdCA9IG51bGw7CgogICAgICAgICAgICByZXR1cm4gbm9kZTsKICAgICAgICB9IGVsc2UgaWYgKGlzV2ViV29ya2VyKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAvL0luIGEgd2ViIHdvcmtlciwgdXNlIGltcG9ydFNjcmlwdHMuIFRoaXMgaXMgbm90IGEgdmVyeQogICAgICAgICAgICAgICAgLy9lZmZpY2llbnQgdXNlIG9mIGltcG9ydFNjcmlwdHMsIGltcG9ydFNjcmlwdHMgd2lsbCBibG9jayB1bnRpbAogICAgICAgICAgICAgICAgLy9pdHMgc2NyaXB0IGlzIGRvd25sb2FkZWQgYW5kIGV2YWx1YXRlZC4gSG93ZXZlciwgaWYgd2ViIHdvcmtlcnMKICAgICAgICAgICAgICAgIC8vYXJlIGluIHBsYXksIHRoZSBleHBlY3RhdGlvbiBpcyB0aGF0IGEgYnVpbGQgaGFzIGJlZW4gZG9uZSBzbwogICAgICAgICAgICAgICAgLy90aGF0IG9ubHkgb25lIHNjcmlwdCBuZWVkcyB0byBiZSBsb2FkZWQgYW55d2F5LiBUaGlzIG1heSBuZWVkCiAgICAgICAgICAgICAgICAvL3RvIGJlIHJlZXZhbHVhdGVkIGlmIG90aGVyIHVzZSBjYXNlcyBiZWNvbWUgY29tbW9uLgogICAgICAgICAgICAgICAgaW1wb3J0U2NyaXB0cyh1cmwpOwoKICAgICAgICAgICAgICAgIC8vQWNjb3VudCBmb3IgYW5vbnltb3VzIG1vZHVsZXMKICAgICAgICAgICAgICAgIGNvbnRleHQuY29tcGxldGVMb2FkKG1vZHVsZU5hbWUpOwogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICBjb250ZXh0Lm9uRXJyb3IobWFrZUVycm9yKCdpbXBvcnRzY3JpcHRzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaW1wb3J0U2NyaXB0cyBmYWlsZWQgZm9yICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lICsgJyBhdCAnICsgdXJsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW21vZHVsZU5hbWVdKSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9OwoKICAgIGZ1bmN0aW9uIGdldEludGVyYWN0aXZlU2NyaXB0KCkgewogICAgICAgIGlmIChpbnRlcmFjdGl2ZVNjcmlwdCAmJiBpbnRlcmFjdGl2ZVNjcmlwdC5yZWFkeVN0YXRlID09PSAnaW50ZXJhY3RpdmUnKSB7CiAgICAgICAgICAgIHJldHVybiBpbnRlcmFjdGl2ZVNjcmlwdDsKICAgICAgICB9CgogICAgICAgIGVhY2hSZXZlcnNlKHNjcmlwdHMoKSwgZnVuY3Rpb24gKHNjcmlwdCkgewogICAgICAgICAgICBpZiAoc2NyaXB0LnJlYWR5U3RhdGUgPT09ICdpbnRlcmFjdGl2ZScpIHsKICAgICAgICAgICAgICAgIHJldHVybiAoaW50ZXJhY3RpdmVTY3JpcHQgPSBzY3JpcHQpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgcmV0dXJuIGludGVyYWN0aXZlU2NyaXB0OwogICAgfQoKICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gc2NyaXB0IGF0dHJpYnV0ZSwgd2hpY2ggY291bGQgYWxzbyBhZGp1c3QgdGhlIGJhc2VVcmwuCiAgICBpZiAoaXNCcm93c2VyICYmICFjZmcuc2tpcERhdGFNYWluKSB7CiAgICAgICAgLy9GaWd1cmUgb3V0IGJhc2VVcmwuIEdldCBpdCBmcm9tIHRoZSBzY3JpcHQgdGFnIHdpdGggcmVxdWlyZS5qcyBpbiBpdC4KICAgICAgICBlYWNoUmV2ZXJzZShzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHQpIHsKICAgICAgICAgICAgLy9TZXQgdGhlICdoZWFkJyB3aGVyZSB3ZSBjYW4gYXBwZW5kIGNoaWxkcmVuIGJ5CiAgICAgICAgICAgIC8vdXNpbmcgdGhlIHNjcmlwdCdzIHBhcmVudC4KICAgICAgICAgICAgaWYgKCFoZWFkKSB7CiAgICAgICAgICAgICAgICBoZWFkID0gc2NyaXB0LnBhcmVudE5vZGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gYXR0cmlidXRlIHRvIHNldCBtYWluIHNjcmlwdCBmb3IgdGhlIHBhZ2UKICAgICAgICAgICAgLy90byBsb2FkLiBJZiBpdCBpcyB0aGVyZSwgdGhlIHBhdGggdG8gZGF0YSBtYWluIGJlY29tZXMgdGhlCiAgICAgICAgICAgIC8vYmFzZVVybCwgaWYgaXQgaXMgbm90IGFscmVhZHkgc2V0LgogICAgICAgICAgICBkYXRhTWFpbiA9IHNjcmlwdC5nZXRBdHRyaWJ1dGUoJ2RhdGEtbWFpbicpOwogICAgICAgICAgICBpZiAoZGF0YU1haW4pIHsKICAgICAgICAgICAgICAgIC8vUHJlc2VydmUgZGF0YU1haW4gaW4gY2FzZSBpdCBpcyBhIHBhdGggKGkuZS4gY29udGFpbnMgJz8nKQogICAgICAgICAgICAgICAgbWFpblNjcmlwdCA9IGRhdGFNYWluOwoKICAgICAgICAgICAgICAgIC8vU2V0IGZpbmFsIGJhc2VVcmwgaWYgdGhlcmUgaXMgbm90IGFscmVhZHkgYW4gZXhwbGljaXQgb25lLgogICAgICAgICAgICAgICAgaWYgKCFjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvZmYgdGhlIGRpcmVjdG9yeSBvZiBkYXRhLW1haW4gZm9yIHVzZSBhcyB0aGUKICAgICAgICAgICAgICAgICAgICAvL2Jhc2VVcmwuCiAgICAgICAgICAgICAgICAgICAgc3JjID0gbWFpblNjcmlwdC5zcGxpdCgnLycpOwogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBzcmMucG9wKCk7CiAgICAgICAgICAgICAgICAgICAgc3ViUGF0aCA9IHNyYy5sZW5ndGggPyBzcmMuam9pbignLycpICArICcvJyA6ICcuLyc7CgogICAgICAgICAgICAgICAgICAgIGNmZy5iYXNlVXJsID0gc3ViUGF0aDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1N0cmlwIG9mZiBhbnkgdHJhaWxpbmcgLmpzIHNpbmNlIG1haW5TY3JpcHQgaXMgbm93CiAgICAgICAgICAgICAgICAvL2xpa2UgYSBtb2R1bGUgbmFtZS4KICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBtYWluU2NyaXB0LnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKCiAgICAgICAgICAgICAgICAvL0lmIG1haW5TY3JpcHQgaXMgc3RpbGwgYSBwYXRoLCBmYWxsIGJhY2sgdG8gZGF0YU1haW4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtYWluU2NyaXB0KSkgewogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBkYXRhTWFpbjsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1B1dCB0aGUgZGF0YS1tYWluIHNjcmlwdCBpbiB0aGUgZmlsZXMgdG8gbG9hZC4KICAgICAgICAgICAgICAgIGNmZy5kZXBzID0gY2ZnLmRlcHMgPyBjZmcuZGVwcy5jb25jYXQobWFpblNjcmlwdCkgOiBbbWFpblNjcmlwdF07CgogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKICAgIH0KCiAgICAvKioKICAgICAqIFRoZSBmdW5jdGlvbiB0aGF0IGhhbmRsZXMgZGVmaW5pdGlvbnMgb2YgbW9kdWxlcy4gRGlmZmVycyBmcm9tCiAgICAgKiByZXF1aXJlKCkgaW4gdGhhdCBhIHN0cmluZyBmb3IgdGhlIG1vZHVsZSBzaG91bGQgYmUgdGhlIGZpcnN0IGFyZ3VtZW50LAogICAgICogYW5kIHRoZSBmdW5jdGlvbiB0byBleGVjdXRlIGFmdGVyIGRlcGVuZGVuY2llcyBhcmUgbG9hZGVkIHNob3VsZAogICAgICogcmV0dXJuIGEgdmFsdWUgdG8gZGVmaW5lIHRoZSBtb2R1bGUgY29ycmVzcG9uZGluZyB0byB0aGUgZmlyc3QgYXJndW1lbnQncwogICAgICogbmFtZS4KICAgICAqLwogICAgZGVmaW5lID0gZnVuY3Rpb24gKG5hbWUsIGRlcHMsIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIG5vZGUsIGNvbnRleHQ7CgogICAgICAgIC8vQWxsb3cgZm9yIGFub255bW91cyBtb2R1bGVzCiAgICAgICAgaWYgKHR5cGVvZiBuYW1lICE9PSAnc3RyaW5nJykgewogICAgICAgICAgICAvL0FkanVzdCBhcmdzIGFwcHJvcHJpYXRlbHkKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbmFtZTsKICAgICAgICAgICAgbmFtZSA9IG51bGw7CiAgICAgICAgfQoKICAgICAgICAvL1RoaXMgbW9kdWxlIG1heSBub3QgaGF2ZSBkZXBlbmRlbmNpZXMKICAgICAgICBpZiAoIWlzQXJyYXkoZGVwcykpIHsKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbnVsbDsKICAgICAgICB9CgogICAgICAgIC8vSWYgbm8gbmFtZSwgYW5kIGNhbGxiYWNrIGlzIGEgZnVuY3Rpb24sIHRoZW4gZmlndXJlIG91dCBpZiBpdCBhCiAgICAgICAgLy9Db21tb25KUyB0aGluZyB3aXRoIGRlcGVuZGVuY2llcy4KICAgICAgICBpZiAoIWRlcHMgJiYgaXNGdW5jdGlvbihjYWxsYmFjaykpIHsKICAgICAgICAgICAgZGVwcyA9IFtdOwogICAgICAgICAgICAvL1JlbW92ZSBjb21tZW50cyBmcm9tIHRoZSBjYWxsYmFjayBzdHJpbmcsCiAgICAgICAgICAgIC8vbG9vayBmb3IgcmVxdWlyZSBjYWxscywgYW5kIHB1bGwgdGhlbSBpbnRvIHRoZSBkZXBlbmRlbmNpZXMsCiAgICAgICAgICAgIC8vYnV0IG9ubHkgaWYgdGhlcmUgYXJlIGZ1bmN0aW9uIGFyZ3MuCiAgICAgICAgICAgIGlmIChjYWxsYmFjay5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGNhbGxiYWNrCiAgICAgICAgICAgICAgICAgICAgLnRvU3RyaW5nKCkKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjb21tZW50UmVnRXhwLCAnJykKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjanNSZXF1aXJlUmVnRXhwLCBmdW5jdGlvbiAobWF0Y2gsIGRlcCkgewogICAgICAgICAgICAgICAgICAgICAgICBkZXBzLnB1c2goZGVwKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAvL01heSBiZSBhIENvbW1vbkpTIHRoaW5nIGV2ZW4gd2l0aG91dCByZXF1aXJlIGNhbGxzLCBidXQgc3RpbGwKICAgICAgICAgICAgICAgIC8vY291bGQgdXNlIGV4cG9ydHMsIGFuZCBtb2R1bGUuIEF2b2lkIGRvaW5nIGV4cG9ydHMgYW5kIG1vZHVsZQogICAgICAgICAgICAgICAgLy93b3JrIHRob3VnaCBpZiBpdCBqdXN0IG5lZWRzIHJlcXVpcmUuCiAgICAgICAgICAgICAgICAvL1JFUVVJUkVTIHRoZSBmdW5jdGlvbiB0byBleHBlY3QgdGhlIENvbW1vbkpTIHZhcmlhYmxlcyBpbiB0aGUKICAgICAgICAgICAgICAgIC8vb3JkZXIgbGlzdGVkIGJlbG93LgogICAgICAgICAgICAgICAgZGVwcyA9IChjYWxsYmFjay5sZW5ndGggPT09IDEgPyBbJ3JlcXVpcmUnXSA6IFsncmVxdWlyZScsICdleHBvcnRzJywgJ21vZHVsZSddKS5jb25jYXQoZGVwcyk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8vSWYgaW4gSUUgNi04IGFuZCBoaXQgYW4gYW5vbnltb3VzIGRlZmluZSgpIGNhbGwsIGRvIHRoZSBpbnRlcmFjdGl2ZQogICAgICAgIC8vd29yay4KICAgICAgICBpZiAodXNlSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgbm9kZSA9IGN1cnJlbnRseUFkZGluZ1NjcmlwdCB8fCBnZXRJbnRlcmFjdGl2ZVNjcmlwdCgpOwogICAgICAgICAgICBpZiAobm9kZSkgewogICAgICAgICAgICAgICAgaWYgKCFuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQgPSBjb250ZXh0c1tub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy9BbHdheXMgc2F2ZSBvZmYgZXZhbHVhdGluZyB0aGUgZGVmIGNhbGwgdW50aWwgdGhlIHNjcmlwdCBvbmxvYWQgaGFuZGxlci4KICAgICAgICAvL1RoaXMgYWxsb3dzIG11bHRpcGxlIG1vZHVsZXMgdG8gYmUgaW4gYSBmaWxlIHdpdGhvdXQgcHJlbWF0dXJlbHkKICAgICAgICAvL3RyYWNpbmcgZGVwZW5kZW5jaWVzLCBhbmQgYWxsb3dzIGZvciBhbm9ueW1vdXMgbW9kdWxlIHN1cHBvcnQsCiAgICAgICAgLy93aGVyZSB0aGUgbW9kdWxlIG5hbWUgaXMgbm90IGtub3duIHVudGlsIHRoZSBzY3JpcHQgb25sb2FkIGV2ZW50CiAgICAgICAgLy9vY2N1cnMuIElmIG5vIGNvbnRleHQsIHVzZSB0aGUgZ2xvYmFsIHF1ZXVlLCBhbmQgZ2V0IGl0IHByb2Nlc3NlZAogICAgICAgIC8vaW4gdGhlIG9uc2NyaXB0IGxvYWQgY2FsbGJhY2suCiAgICAgICAgaWYgKGNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgICAgICBjb250ZXh0LmRlZlF1ZXVlTWFwW25hbWVdID0gdHJ1ZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBnbG9iYWxEZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgIH0KICAgIH07CgogICAgZGVmaW5lLmFtZCA9IHsKICAgICAgICBqUXVlcnk6IHRydWUKICAgIH07CgogICAgLyoqCiAgICAgKiBFeGVjdXRlcyB0aGUgdGV4dC4gTm9ybWFsbHkganVzdCB1c2VzIGV2YWwsIGJ1dCBjYW4gYmUgbW9kaWZpZWQKICAgICAqIHRvIHVzZSBhIGJldHRlciwgZW52aXJvbm1lbnQtc3BlY2lmaWMgY2FsbC4gT25seSB1c2VkIGZvciB0cmFuc3BpbGluZwogICAgICogbG9hZGVyIHBsdWdpbnMsIG5vdCBmb3IgcGxhaW4gSlMgbW9kdWxlcy4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IHRoZSB0ZXh0IHRvIGV4ZWN1dGUvZXZhbHVhdGUuCiAgICAgKi8KICAgIHJlcS5leGVjID0gZnVuY3Rpb24gKHRleHQpIHsKICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgcmV0dXJuIGV2YWwodGV4dCk7CiAgICB9OwoKICAgIC8vU2V0IHVwIHdpdGggY29uZmlnIGluZm8uCiAgICByZXEoY2ZnKTsKfSh0aGlzKSk7Cg==",
"ok": true,
"headers": [
[
"content-type",
"application/javascript"
]
],
"status": 200,
"status_text": ""
}
},
"base_uri": "https://localhost:8080/",
"height": 1000
}
},
"source": [
"# use all predictors at each timestep\n",
"# without selection criteria you would expect performance to be lower, and indeed it is\n",
"configure_plotly_browser_state()\n",
"backtestmodel = BacktestModel(X, Y, \n",
" create_model=LinearRegression, \n",
" coef_dict_param=\"all\", \n",
" startindex=FIRST_TRAIN_MONTHS,\n",
" fit_missing='mean',\n",
" scaler=None)\n",
"backtestmodel.gen_predictions(verbose=False)\n",
"backtestmodel.gen_returns(calc_returns, verbose=False)\n",
"backtestmodel.report_returns(start_date=start_date_str, freq='M')\n",
"backtestmodel.evaluate_predictions()\n",
"backtestmodel.evaluate_quantiles(chart=True, verbose=False)\n",
"perf_all_preds = backtestmodel.cumulative_return\n",
"mychart([perf_all_preds],[\"All preds\"], title=\"OLS all predictors\")\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/html": [
"\n",
" <script src=\"/static/components/requirejs/require.js\"></script>\n",
" <script>\n",
" requirejs.config({\n",
" paths: {\n",
" base: '/static/base',\n",
" plotly: 'https://cdn.plot.ly/plotly-latest.min.js?noext',\n",
" },\n",
" });\n",
" </script>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
},
{
"output_type": "stream",
"text": [
"................................................................................\n",
"15:34:13 Still training step 80 of 563\n",
"................................................................................\n",
"15:34:16 Still training step 160 of 563\n",
"................................................................................\n",
"15:34:20 Still training step 240 of 563\n",
"................................................................................\n",
"15:34:24 Still training step 320 of 563\n",
"................................................................................\n",
"15:34:28 Still training step 400 of 563\n",
"................................................................................\n",
"15:34:32 Still training step 480 of 563\n",
"................................................................................\n",
"15:34:36 Still training step 560 of 563\n",
"...\n",
"Mean return: 2.781%\n",
"Monthly Sharpe ratio: 0.506\n",
"OOS MSE across all predictions: 43.8692\n",
"In-sample MSE: 34.7467\n",
"Variance: 39.4097\n",
"R-squared: -0.1132\n",
"Avg rank correlation (Kendall's tau): 0.0246 (Expected: 0)\n",
"5-quintile accuracy: 0.2161 (Expected: 0.2)\n",
"Long/short/flat accuracy: 0.4657 (Expected: 0.44)\n",
"Excess true positive in quintiles 1 + 5: 225.800000\n"
],
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAJQCAYAAACKOb67AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzs3Xd4VFX+x/H3N5WEXqVLB6UIgoAF\nGyJYsKyr4u4PXQuogAoWFHtDURE7KKxi18XesICIFWnSVqRKSwIhBEgICWlzfn9kjNE1Ie4yJfd+\nXs9zH2bO3DvznTxD5uRzzrnXnHOIiIiIeFlMpAsQERERCTV1eERERMTz1OERERERz1OHR0RERDxP\nHR4RERHxPHV4RERExPPU4RERERHPU4dHREREPE8dHhEREfG8uEgXUJ6CtB91CugQm9PjnkiX4Hmn\n7/o60iX4QoPkWpEuwfP+UqdrpEvwhckbZ1g4X69wx89h+66Nb9AmrO/t95TwiIiIiOepwyMiIiKe\nF7VDWiIiIhJigeJIVxA2SnhERETE85TwiIiI+JULRLqCsFHCIyIiIp6nhEdERMSvAkp4RERERDxD\nCY+IiIhPOc3hEREREfEOJTwiIiJ+pTk8IiIiIt6hhEdERMSvNIdHRERExDvU4RERERHP05CWiIiI\nX+nioSIiIiLeoYRHRETErzRpWURERMQ7lPCIiIj4lU48KCIiIuIdSnhERER8ShcPFREREfEQJTwi\nIiJ+pTk8IiIiIt6hhEdERMSvNIdHREREJDzMrKOZLS2zZZvZaDPrbmbfB9sWmVnv4P5mZo+b2Toz\nW25mh+/vNZTwiIiI+FWUXEvLObca6A5gZrFAKvAOMA24yzn3sZmdCjwIHA+cArQPbn2AKcF/y6WE\nR0RERKJJf2C9c24T4IBawfbaQFrw9pnAi67E90AdM2tS0ZMq4REREfGr6JzDMwR4LXh7NPCpmU2k\nJKQ5KtjeDNhS5piUYNvW8p5UCY+IiIiEnJkND87D+WUb/gf7JABnAG8Em64ExjjnWgBjgGf/29dX\nwiMiIiIh55ybCkzdz26nAD8459KD9y8CrgnefgP4Z/B2KtCizHHNg23lUsIjIiLiV4FA+LbKuYBf\nh7OgZM7OccHbJwJrg7ffBy4MrtbqC2Q558odzgIlPCIiIhIFzKw6MAC4vEzzMOAxM4sD9gG/DIPN\nBE4F1gG5wMX7e351eERERPwqiiYtO+f2AvV/1/YN0PMP9nXAyD/z/BrSEhEREc9TwiMiIuJXunio\niIiIiHco4REREfEp56Lj0hLhoIRHREREPE8Jj4iIiF9F0SqtUFPCIyIiIp6nhEdERMSvtEpLRERE\nxDuU8IiIiPiV5vCIiIiIeIcSHhEREb8K6Dw8IiIiIp6hDo+IiIh4noa0KmnD5lRuuPvh0vspW9MZ\nefEQjujehXsmPU1+QSGxsbHcOno4XQ9pz/TX3+Wj2V8BUFxczM+bU/nqnenUrlUzUm+hSoirlUyX\nSZdTo1NzcPDvMU9TnJtP54cuI7Z6NfK2ZLDsyicpzsmjdo+2dJ44rORAM9Y99CbbP14Y2TdQRdSu\nXYupz0ykc+eOOOcYNuw6mjVvwu23Xcshndpz5FGnsfiH5QAc0as7U6Y8CICZcfc9D/Pee59Esvwq\noVbtmkx6/B46HtIe5xxjRt3KaYNPYsCgEygsLGTjhi2MHnkz2Vl7So9p1rwJX33/ARMnPMWUJ6dH\nsPqqIalWMn+fcAVNO7YA53hp7BQ2/LCW4y8axLEXDiRQHODHOT/wzoRXqF6nBsOmXEvLbu34/s25\nzLjjuUiXHx18NGnZnHORruEPFaT9GJ2FUdKB6X/uMF6dPIE7H57C0L8Opl+fw/nq+8VMf/1dpj96\nz2/2n/vdQl568wOenXR3hCr+Y3N63LP/ncKs6+NXsmv+KlJe+QKLjyU2KZEjZtzCqrteZte8n2h2\nwfEktWzEugdmEJOUgCsowhUHSGxUh6O+eIC53a7EFUfPf+DTd30d6RL+0HPPPso338znuemvER8f\nT3JyEk2aNCIQcEx5agJjb7yntMOTlFSNgoJCiouLady4ET8smkWLgw+nuDh6xv4bJNeKdAn/4fEp\n9/P9d4t59aU3iY+PJym5Gj0O78o3X82nuLiYW++8DoB77/z1D6l/vvAozjl+WLQ86jo8f6nTNdIl\n/IcLHx7JugU/8d2/5hAbH0tCUiItOrdm0MizmXzJBIoKiqhRvxY5mdnBx1rRtGNLmnRoEbUdnskb\nZ1g4X2/fgjfC9l1brfe5YX1vvxeyIS0z62RmN5rZ48HtRjM7JFSvF07zf1hBi6YH0bRxIwxj795c\nAHL25tKwfr3/2H/m599wyon9wl1mlRNXM4m6Rx5CyitfAOAKiynKziW5bRN2zfsJgMwvV9D4tN4A\nBPIKSjs3MdXiIUo779GmVq2a9DumD89Nfw2AwsJCsrKyWbVqHWvWrP+P/fPy9pV2bqpVSyRa/0iK\nJjVr1aDvUb149aU3gZKfcXbWHr784rvSn+XiRcto0vSg0mMGndafzZtSWL1qXURqrmqq1UyiXe9D\n+O5fcwAoLiwmLzuXfn8/mU+nvEdRQREAOZnZABTk5bN+0WoK8wsiVnNUCgTCt0VYSDo8ZnYj8Dpg\nwILgZsBrZnZTKF4znD6e8w2n9C/pwNw46hIefuZFTjpvGA8//QKjh/39N/vm7cvn24VLGHBs30iU\nWqUktWxEQWY2XR+7kqNm30/nScOJTU4kZ3UKjU7pBUDjwX2o1qx+6TG1D2/H0V8+xNFzH+LHG56N\nqnQnWrVu3ZIdOzJ59p+PsHDBpzzz9EMkJydVeEzvI3qwbOkclv7wOSNG3RRV6U40anlwczJ37OSx\nyfcx66u3ePjxe/7jZ3zB//2FObNLEsDk6smMuuYyJj4wORLlVkkNWjQiJzOboRNHMO6jB/j7hMtJ\nSEqkUZsmtOvdiRveHc+Yf93Jwd3aRrpUiRKhSnguBY5wzk1wzr0c3CYAvYOPVVmFhYXM/W4hJx93\nFAD/eu8Txo64mNkzpnHDiIu5/aHf/sL68ruF9OjSSXN3KsHiYqnVtTWbX5jFdyeNozg3n9ZXncm/\nRz9Ny3+czJGf3UdsjSQCwb/cALJ+WMe3x93AvIE30+aaM4lJjI/gO6ga4mJj6dGjK8888yJH9B7I\n3r253Dh2VIXHLFi4hMO6n0jfo07lprGjSExMDFO1VVNcbCxdDzuU5599nQHHnkNubi6jxgwrffya\n6y6nqKiYt2Z8AMANN41k6uQXyA2mxbJ/MbGxtOjSmq9f/oz7T7uRgrx8Tr7yLGJjY6heuwYPnXUL\nb9/3Epc+NSbSpUY3FwjfFmGh6vAEgKZ/0N4k+NgfMrPhZrbIzBb98+U3QlTa/+br+Us4pEMbGtSr\nA8D7n83lpGB6M/D4o/j3qrW/2f/jL77hlBOPCXudVdG+tEzy03aS9UNJpJ/+wXxqdW3F3nVpLDr/\nPuadfDNb3/mO3E3p/3Hs3rVpFO/dR41OLcJddpWTkrqVlJStLFi4BIC33/6IHt0rNz9j1ap15OTk\n0qVzx1CWWOWlpaWzNS2dJYtL5kF9+N5ndOt2KADn/+0sBgw8npHDbijdv0fPbtx29/UsXD6bYVde\nyNXXDeeSYX+LSO1Vxe5tmezelsnGpSW/L36Y+T0tu7Rm17adLP10AQCblq3HBQLUqKc/OCV0q7RG\nA5+b2VpgS7CtJdAOKPdPSefcVGAqRO+k5Y/nfP2bDkzD+nVZtOxHjujehfk/rKBlsyalj+3J2cui\nZSu5/+bRkSi1yinIyCIvLZPqbZuwd/1W6vfrwt41qSQ0qEXBjmwwo+2Ys9nywmwAklo2ZF9qJq44\nQLXmDajeril5WzIi/C6iX3p6BikpaXTo0JY1a9Zz4onH8NNPa8rdv1WrFmzZkkZxcTEtWzajY8e2\nbNy0pdz9BTK27yA1ZStt27Vi/bqN9DuuL2tWr+OE/scw8upLOfu0C8nL21e6/1mnDi29ff1NI9mb\nk8tz016NROlVRnZGFrvSMmnUpgnbf95Kp6O7snVtCjs2p9Ohb2fWzPuRRq2bEBcfR87OPft/Qr+K\ngrk14RKSDo9z7hMz60DJEFazYHMqsNA5V2UH/3Pz9jFv8TJuv/aK0rY7rx/BhCeepbi4mMSEBO64\n7srSxz7/Zj5H9TqM5KRqkSi3Svrp5ul0mzyKmIQ4cjdtZ8U1T9PsvGNpefHJAKTPXEDqa3MBqNu7\nE62vOgNXVIwLOFbe9ByF+sVWKdeMuY0XX3iChIR4NmzYzKWXXcuZZw7isUfupWHDerz/3ossW/Yj\np57+d44+ujdjbxhJYWERgUCAUVffTGbmrki/hah3y43jmTztIeIT4tm0cQujR9zCJ1/MICEhgX+9\n+ywAixcu48Zr74pwpVXXjDuf4+JHryYuPo4dW7bz4vWTKcjbx9AHR3DrpxMpKiziheueKt3/nm+e\npFqNZGLj4zjs5CN4Yui9bFuXGsF3IOGkZek+Fo3L0r0mWpele000Lkv3mmhclu5FYV+W/vVL4VuW\n3m+oN5eli4iIiEQLnWlZRETEp6rwLJM/TQmPiIiIeJ4SHhEREb/y0SotJTwiIiLieUp4RERE/CoK\nzoAcLkp4RERExPPU4RERERHP05CWiIiIX2nSsoiIiIh3KOERERHxK01aFhEREfEOJTwiIiJ+pTk8\nIiIiIt6hhEdERMSvNIdHRERExDuU8IiIiPiV5vCIiIiIeIcSHhEREb9SwiMiIiLiHUp4RERE/Eqr\ntERERES8QwmPiIiIX2kOj4iIiIh3qMMjIiIinqchLREREb/SpGURERER71DCIyIi4leatCwiIiLi\nHUp4RERE/EpzeERERES8QwmPiIiIX2kOj4iIiIh3KOERERHxKyU8IiIiIt6hhEdERMSvnIt0BWGj\nhEdEREQ8TwmPiIiIX2kOj4iIiIh3KOERERHxKyU8IiIiIt6hhEdERMSvdC0tEREREe9Qh0dEREQ8\nT0NaIiIifqVJyyIiIiLeoYRHRETEr3RpCRERERHvUMIjIiLiVz6awxO1HZ4jDh8W6RI877aY1pEu\nwfOWNu8R6RJ8Ydm+OpEuwfMWURTpEkT+J1Hb4REREZEQ81HCozk8IiIi4nlKeERERPxKl5YQERER\n8Q4lPCIiIj7lAjoPj4iIiIhnKOERERHxK63SEhEREfEOJTwiIiJ+pVVaIiIiIt6hDo+IiIh4njo8\nIiIifhVw4dsqYGYdzWxpmS3bzEab2Z1mllqm/dQyx4wzs3VmttrMBu7vrWoOj4iIiESUc2410B3A\nzGKBVOAd4GLgEefcxLL7m9mhwBCgM9AUmG1mHZxzxeW9hjo8IiIifhWdy9L7A+udc5vMrLx9zgRe\nd87lAxvMbB3QG5hX3gEa0hIREZGQM7PhZraozDa8nF2HAK+VuT/KzJab2XNmVjfY1gzYUmaflGBb\nudThERER8atAIGybc26qc65XmW3q78sxswTgDOCNYNMUoC0lw11bgYf/27eqDo+IiIhEi1OAH5xz\n6QDOuXTnXLFzLgBMo2TYCkrm+LQoc1zzYFu51OERERHxK+fCt1XOBZQZzjKzJmUeOxv4d/D2+8AQ\nM0s0s9ZAe2BBRU+sScsiIiIScWZWHRgAXF6m+UEz6w44YOMvjznnfjSzGcBKoAgYWdEKLVCHR0RE\nxL+iaJWWc24vUP93bUMr2H88ML6yz68hLREREfE8JTwiIiJ+tZ8zIHuJEh4RERHxPCU8IiIifuWi\nZw5PqCnhEREREc9TwiMiIuJXmsMjIiIi4h3q8IiIiIjnaUhLRETEp1wUnXgw1JTwiIiIiOcp4RER\nEfErTVoWERER8Q4lPCIiIn6lEw+KiIiIeIcSHhEREb/SHB4RERER71DCIyIi4lc6D4+IiIiIdyjh\nERER8SvN4RERERHxDiU8IiIifqXz8IiIiIh4hxIeERERv9IcHhERERHvUIdHREREPE9DWiIiIj7l\ndOJBEREREe9QwiMiIuJXmrQsIiIi4h1KeERERPzKRwmPOjx/Qs1aNbhj0jjadWyDc447xtxHv/5H\ncvygfgQCAXbt2M1t19xLRvoOeh3Vg0eff4DUzWkAzJn5Jc9Mmh7hdxD94msl0/PhYdTq1BycY9GY\nqRTvK+TwBy4hNjGeQHExS26azq6lPxNXM4neT44guVl9LC6WNVM+YtO/vor0W4h6Ca2b0eKJG3+9\n36Ix2x99md1vz6HFEzcS3/wgClPS2TxqAoHsvQBU79OVxrcNw+JiKd6VzYYLxkWq/CojvlYyfSde\nRu3gZ/n7a6dRvK+A3hMuIaZaPK6omIXjnidz6c80OvIQjps+hpwtGQBsmbmQfz/yboTfQfSrViuZ\nIRMup3HH5uDgtbFPs+mHtfS7aCBHX3gyrjjAyjlL+GDCq6XH1Glan5tmPcwnj77J3GkfRrB6CTd1\neP6EsfeO5ts533P9ZbcQFx9HUlI11q/+macenAbA3y49l8uvvZh7b3wIgCXzl3HV0BsiWXKVc9g9\nQ9n2xTK+H/YYFh9LXFIifadezU+T3mbbnGU0PvEwut12AV+eM552Fw9gz5pUvrvoYRLq12TQ1xPZ\n/Pa3uMLiSL+NqFawIZX1p19dcicmho7zXiD703k0uOJccr5bxo6n36TBFX+l4ZXnkv7A88TUrE6T\nu69k08V3UJiWQWz92pF9A1VEr7uHkjZ3OV8Pf5yY+FhikxLp98xVrJj0NmlfLKfpiYfR49YLmP3X\n8QBkzF/N3IsejnDVVctf7riIn75cyvMjHiE2Ppb4pETaHXkoXQb04qFTbqS4oIga9Wv95pizbr2Q\nn+YujVDFUUiXlpDfq1GzOj37duedVz8AoKiwiD3ZOezNyS3dp1pyNRz+iQcPtLiaSTTs24mNr84F\nwBUWU5idi3OOuBpJQMlfzXnbdpc87iCuRrWSY5OrUbA7B1fkn/+8B0KNow6jYNNWCtMyqDWgD7vf\n+hyA3W99Tq0BfQGoc+ZxZH/6HYVpJelDcWZWxOqtKuJrJtGob0fWvzoXgECZz3J8zTKf5fRdkSuy\niqtWM4k2vQ9h/r++AKC4sJh92bkc/fcBfD7lPYoLigDIycwuPabLyb3I3LKdbWtTIlKzRFbYEx4z\nu9g5V+XGdpq1bMquzN3c/dgtdDy0PSuXr+LB2x4lL3cfo266nMHnDiJnz14uO2dU6THdenZhxucv\nkJG+g0l3Pcn61Rsi+A6iX/WWjcjP3EOvRy+n9qEt2b18A0tve4llt79Ev9dupNvtf8NijC/OuAuA\n9c99xlEvXMdpS58kvkYS31/+REkvSCqt9uBjyfqgZBgwrkEdijJKvoCLMnYR16AOUDIEZnGxtH71\nfmKqJ5H5/PvsfmdOxGquCmq0bMi+zD30fWQ4dTu3ZOfyjSy67SUW3/4yJ742lh63/w0z47PgZxmg\nQc92nDprPHnpu/nh7lfJWpMawXcQ/eq1aEROZjYXTLySpoe0JGXFBt656wUatmlCm96dOPWGIRTm\nF/D++JfZsvxnEpIT6X/FGUz5v/GcMHxwpMuPHj6awxOJhOeu8h4ws+FmtsjMFmXmpoezpv2KjYul\nU9cOvPH8O5w/4B/k5e7jklFDAXhywjMM7Hk2H731KUMuOQeAn5avZlCvv3Be/4t47dk3eWT6hEiW\nXyXExMVQp2srfn5hNp+ffAtFefl0umowbS48iWV3vMzMXlez7I6X6fnwMAAOOr4bWT9u4qPuo5h1\n0s30uO+i0iRI9s/i46jZvzdZH3/zxzsEfw9abCxJXdqx8dI72fiP22l41RASWjcNX6FVkMXGUq9r\nK9a++Dkfn3wrRbn5dB41mPYX9WfxHa/wbq9rWHznK/SZVPJZ3rliI+/2Hs3MAbew+rnPOPa5MRF+\nB9EvNjaW5l1a8+3Ls3j4tHEU5OXT/8oziYmNJbl2DR4961Y+uO8VLnpqNACDRp/Ll8/OpCA3P8KV\nS6SEpMNjZsvL2VYAB5V3nHNuqnOul3OuV/3kcneLiPS07aRvzWDFkpUAzPrwCzp16/ibfWa+/Rkn\nnXYCAHtzcsnLzQPgm8/nERcfR516mvtQkdy0neRt3cnOJesBSP1wAXW6tqLVef1I/WghACkfzKde\nj7YAtBpyLKkzS9r3bkxn7+YMarZrEpniq6Aax/Vk34/rKd5RMkRYtGM3cQ3rAhDXsC5FmSXthdt2\nkPP1D7i8fIp3ZZO74N9U69Q6YnVXBblbd5K7dSeZwc/y5g8XUK9rK9qc248twc/s5g/m06B7yWe5\nKCePouAXcdqcZcTEx5JYr0Zkiq8idm/LJGvbTjYvXQfAspnzad6lFbu3ZbL80wUAbF62HhdwVK9X\nk4O7t2PwuL9z2zdPcNwlp3DSyLM45sKBkXwLUcEFXNi2SAtVwnMQcCEw+A+2zBC9ZkhlZuwkPTWd\ng9u2BKBPv178vGYDLVs3L93nhEH92LBuEwD1G9Yrbe/S4xBizNi9U3MfKpKfkUVeWiY12pZ0Whod\n05nsNankpe+i4ZGHlLblbNgGQG5qJo2O6QxAYoNa1GzbhL2bt0em+Cqo9uDj2P3Br6vasmfPp845\n/QGoc05/smfNB2DPrO9J7tUZYmOwaokkHdaR/PWaA1GRfRlZ5KbtpGbws9y4X2ey1pZ8lhsFP8sH\nHdOZ7OBnuVrDX/8Yqt+9DRZj5O/MCX/hVciejCx2p2XSsE3Jz7j90V3YtjaVf3+2iHZ9S34vNGzd\nhNj4OPbu3MMT593JPcdcxT3HXMWXz33M7Kfe5ZsXP43kW5AwC9Ucng+BGs65/5gKb2ZzQ/SaITfh\nlke4f/IdxMfHk7IpjdtHj+fOh2+iVbuDCQQCbE3Zxr1jHwRgwOATOO+isykqKiZ/Xz43XnF7hKuv\nGpbc8iK9nxpBTHwcezdvZ9HoZ0j7dDHd77kQi40hkF/I4hv+CcBPj7zDEY9dwYA5E8BgxfjXKdCX\nRKVYUiI1julO2q1PlrbtePpNWjx5E3XPO5nC1O1sGVUyDJu/PoWcLxfTbuaTEHDsmvEp+Ws2Rar0\nKmPRrS9w9JNXEhMfR87m7Xw/Ziopny6m591DiYmNoTi/kAU3PAtAy9N70/7C/riiYor3FfLNlU9F\nuPqq4a07pzP00VHExseRuWU7r13/NAV5+xjy4BWM/fQhiguLePW6yZEuM7pFQfISLuaidJLnYY2P\nis7CPOQ207BEqHVKUqoXDsv21Yl0CZ63KKEo0iX4wiMbX7dwvt6eq08P23dtzcc/DOt7+z2dh0dE\nRMSvdLV0EREREe9Qh0dEREQ8T0NaIiIifuWjSctKeERERMTzlPCIiIj4lRIeEREREe9QwiMiIuJT\n0XouvlBQwiMiIiKep4RHRETErzSHR0RERMQ7lPCIiIj4lRIeEREREe9QwiMiIuJTTgmPiIiIiHco\n4REREfErJTwiIiIi3qGER0RExK8CkS4gfJTwiIiIiOepwyMiIiKepyEtERERn9KydBEREREPUcIj\nIiLiV0p4RERERLxDCY+IiIhfaVm6iIiIiHco4REREfEprdISERER8RAlPCIiIn6lOTwiIiIi3qGE\nR0RExKc0h0dERETEQ5TwiIiI+JXm8IiIiIh4hxIeERERn3JKeERERES8Qx0eERER8TwNaYmIiPiV\nhrREREREvEMJj4iIiE9p0rKIiIiIhyjhERER8SslPCIiIiLeoYRHRETEpzSHR0RERCRMzKyjmS0t\ns2Wb2Wgze8jMVpnZcjN7x8zqlDlmnJmtM7PVZjZwf6+hDo+IiIhPuUD4tgrrcG61c667c6470BPI\nBd4BZgFdnHPdgDXAOAAzOxQYAnQGBgGTzSy2otdQh0dERESiSX9gvXNuk3PuM+dcUbD9e6B58PaZ\nwOvOuXzn3AZgHdC7oidVh0dERMSnwpnwmNlwM1tUZhteTllDgNf+oP0S4OPg7WbAljKPpQTbyqVJ\nyyIiIhJyzrmpwNSK9jGzBOAMgkNXZdpvAYqAV/7b14/aDk+nxEaRLsHz2rEn0iV4Xvre6pEuwRd6\n1c2MdAmed9mmlZEuwRceCfcLOgv3K+7PKcAPzrn0XxrM7B/A6UB/55wLNqcCLcoc1zzYVi4NaYmI\niEi0uIAyw1lmNggYC5zhnMsts9/7wBAzSzSz1kB7YEFFTxy1CY+IiIiEVjSdh8fMqgMDgMvLND8J\nJAKzzAzge+fcFc65H81sBrCSkqGukc654oqeXx0eERERiTjn3F6g/u/a2lWw/3hgfGWfX0NaIiIi\n4nlKeERERHzKBaJu0nLIKOERERERz1PCIyIi4lPRNGk51JTwiIiIiOcp4REREfEpF30nHgwZJTwi\nIiLieUp4REREfEpzeEREREQ8RAmPiIiIT+k8PCIiIiIeooRHRETEp5yLdAXho4RHREREPE8Jj4iI\niE9pDo+IiIiIh1Qq4TGzg4H2zrnZZpYExDnn9oS2NBEREQklJTxlmNkw4E3gmWBTc+DdUBYlIiIi\nciBVZkhrJHA0kA3gnFsLNAplUSIiIiIHUmWGtPKdcwVmJbGXmcUBPlrIJiIi4k1alv5bX5rZzUCS\nmQ0A3gA+CG1ZIiIiIgdOZRKem4BLgRXA5cBM4J+hLEpERERCz0+Tlvfb4XHOBYBpwU1ERESkyim3\nw2NmK6hgro5zrltIKhIREZGwcE4JD8DpYatCREREJITK7fA45zaFsxAREREJLxeIdAXhU9GQ1jfO\nuWPMbA+/HdoywDnnaoW8OhEREZEDoKKE55jgvzXDV46IiIiES8BHc3gqc2mJlyrTJiIiIhKtKnMe\nns5l7wTPtNwzNOWIiIhIuPhplVa5CY+ZjQvO3+lmZtnBbQ+QDrwXtgpFRERE/kcVzeG5H7jfzO53\nzo0LY00iIiISBjrTchnOuXFm1gw4uOz+zrmvQlmYiIiIyIGy3w6PmU0AhgArgeJgswPU4REREanC\n/HS19MpMWj4b6Oicyw91MSIiIiKhsN9l6cDPQHyoCxEREREJlcokPLnAUjP7HChNeZxzV4esKhER\nEQk5TVr+rfeDm4iIiEiVVJlVWi+EoxAREREJLz9dWqKii4fOcM6dZ2Yr+O3FQwFwznULaWUiIiIi\nB0hFCc81wX9PD0chIiIiEl6JDZP3AAAgAElEQVR+urRERWda3hr8d1P4yhERERE58Cpz4sE9/Dqk\nlUDJEvW9zrlaoSxMREREQksnHizDOVfzl9tmZsCZQN9QFiUiIiJyIFXmxIOlXIl3gYEhqkdERETC\nJOAsbFukVWZI6y9l7sYAvYB9IatIRERE5ACrzIkHB5e5XQRspGRYS0RERKowrdIqwzl3cTgKqQqS\na1Xn8gdG0qJDS8Ax5YYnOezYHvS/YADZmdkAvPbQyyz9YjFtD2vP8PtHAGAGbzz6Ogs/nR/B6qNf\nYptmtHryhtL7CS0bs23Sq+x8aw6tnhpLQvNGFKRsZ+OIByjO3lu6X1K3dnR45yE2XvUQWTO/i0Tp\nVU5crWQOmXQ51Tu1AAcrx0whkFtAp4cuI7Z6NfK2ZPDjlU9QnJNHtRYN6fv1JHLXpwGQtXgtq8f+\nM8LvILrFt25G00njfr3fogmZj79E1nuzaTppHPHNDqIwNZ20MfcTyM4hplYNGo8fQ0LLJgTyC9h2\nyyMUrNUC2f2pXbsWU6Y8wKGHdsA5uOKKG2jWrDG33DKGTp3a0a/fGfzwwwoAhgw5i9Gjh5ce27Xr\nIRx55GksX74yUuVLmJmrYIq2mZ0JjAUOCTYtAu52zn1jZrWdc1mhKuz8g8+KurnjIx6+mlULVzLn\n9dnExseRmJTIqZcMZl9uHh9Ofe83+yZUS6CosIhAcYA6jery4MePcEXvSwgUByJU/X8aR/TU8h9i\nYug8fzprzrqeBheeRvHuPWyf8haNrjyH2No12DrhhdL92r5yNy6/gMwZs6Ouw5O5LynSJfyhQx8f\nwe75q0h7ZQ4WH0tsUiI9ZtzK2rteYve8n2hywfEktWzEzw/MoFqLhhz28o3MP+76SJddruZ1syNd\nQvliYmj75UtsOn8Mdf92OsVZe9g57Q3qDTuXmFo12fHwczS84VICuXlkPvUqCa2b0+j2kaRcPG7/\nzx1G3TdFX8dg2rSH+fbbhTz//OvEx8eTnJxE48aNCAQCPPnkfYwbN760w1NW584dmTFjGp07HxuB\nqiuWl7cprJHLDy3ODNt37eFb3otonFTupGUzuxK4Lbi1Cm4TgAfN7HzgqzDUFzWSaiZzSJ/OzHl9\nNgDFhUXklkkZfq9gX0Fp5yY+Md5XS/8OhJpHdyN/8zYKUzOoPaA3O9+aA8DOt+ZQ++Q+pfs1/Mfp\nZH38HUU7Qtb39pzYmknUOfIQ0l4p+Zm6wmKKsnNJbtuE3fN+AmDnlytodFqfip5GKin5yO4UbtlK\nUdp2avQ/kqx3S36HZL07m5onHQlAQtuW5H6/DICCDSnENzuI2Pp1IlZzVVCrVk2OOaYPzz//OgCF\nhYVkZWWzevU61q79ucJjzzvvDN5444NwlClRpKJVWlcDJzvn5jjnsoPbHErm9DwPTKnoic2sk5n1\nN7Mav2sf9L8WHQmNWhxEdmYWV068mgkzJ3H5AyNJTEoEYOCFp/HgJ49yxUOjqF6reukx7bq3Z+Ks\nx5n46WP885YpUZXuRLs6ZxzL7vdL+tTxDepQtH0XAEXbdxHfoOSLIP6getQe2JcdL30csTqroqSW\njSjIzOaQx66k9+wJdJp0OTHJieSs3kKDU3oB0GhwXxKb1S9zTEN6z57A4e/cQZ0+nSJVepVU69Tj\nyP7oSwBi69ehOKPks1ycsau0U5O/+mdqDDgagGpdOxDftBFxjRtEpuAqolWrFuzYkcnUqROZN28m\nkyc/QHJy5RLVv/51MDNmvLf/HX3AT6u0KlyW7pzb+QdtmcAm59zT5R1nZlcD7wFXAf8ODo394r7/\nstaIio2NoXWXtsx6+WNuOvVa9uXu48wR5zDr5Y+5+tgruPGUMezavouht/065Wnd0rVcP+Bqbj7j\nBs4acQ7xifERfAdVh8XHUfuk3uz+6Ns/fPyXsKzZHcNIm/CCv86cdQBYXCw1u7Ym9YVZLDjpJgK5\n+2h11Zn8NPppmv/jZI747H7iaiThCooAyE/fxTeHj2TBSTex9o4X6TzlKmJrROdQXdSJj6P6iX3Y\n88nXf/x48LO7c+obxNaqzsHvPEmd/zuDfT+tB/2BVKG4uFi6d+/CtGkvc+SRp5Kbm8v114/Y73FH\nHNGd3Nw8Vq5cE4YqJZpU1OHJNrPDft8YbNvf+MEwoKdz7izgeOA2M/vl2lzldvPMbLiZLTKzRetz\nNu7nJcIrc1smmVszWbd0LQDzZ86jdZc2ZO3IwgUCOOeY89os2h3W/j+OTV2Xwr7cfcHJzrI/NY/v\nSe6/11O0YzcAhTt2E9eoLgBxjeqWtid1a0erJ67n0G+mUfvUo2h+zxW/Ge6SP5aflkl+WibZP6wD\nYPsH86nZtTW569JYev59LDx5HNve+ZbcTekAuIIiinblALBn+QbyNqaT3LZJxOqvSmr060X+yvUU\nZ5Z8ZoszdxPbsOSzHNuwLsU7S36VBvbmsu3mR9h09ii23TiRuHq1KdyyLWJ1VwWpqdtITd3KwoVL\nAXjnnZl0795lv8ede+5gZsx4P9TlVRnOWdi2SKuow3Md8L6Z3Wlmg4PbXZQkN9ft73mdczkAzrmN\nlHR6TjGzSVTQ4XHOTXXO9XLO9Wpbo9WfeBuhl5Wxm8ytO2jSpikAXY7uRsraLdQJfhEDHDGwD1tW\nbwagYYtGxMSW/HgbNGtI07bNyUjZHv7Cq6C6Z/QrHc4CyJ69gHrnnAhAvXNOJGvWAgB+OmYYK4Nb\n1szvSLntabI+00q4/SnIyCI/LbO001K3Xxf2rkkhvkHwajFmtB7zF1JfmAVAfP2aEFPy37bawY1I\natOEvGBnSCpW87Tjyf5obun9nDnfU/uskwCofdZJ5Hw+D4CYmtUhvmTRbO1zB5G7cAWBvblhr7cq\nSU/PICVlK+3btwHg+OOPZtWqtRUeY2acc87pvPGGOjx+VNHFQ78xs97ASOAfweaVQF/n3P7+9Eg3\ns+7OuaXB58oxs9OB54Cu/3vZkTH9jmlc9di1xMXHsX1zOlOuf5x/3DWMVoe2xjlHRsp2pt1cMrWp\nU69DOXPEXyguLMa5AM/e+gx7du2J8DuIfjFJidTs150tN08ubUuf/BatJo+l/vkDKEjdzsYRD0aw\nQm9YffN0Ok++CkuIY9+m7ay8ZgpNzjuW5hefDMD2mQvY+tpcAOr0PYQ2Y8/DFRXjAo7VY6dRtLv8\nCftSwpISqX50D9LveLy0LXPaDJo+cjO1zxlIYdp20saUjPAntG1BkwnXgYP8tZvYduujkSq7Srn2\n2juYPv0xEhLi2bhxM8OHX88ZZwxk0qS7aNCgHm+/PZ3ly1dyxhkXAnDMMX1ISUlj48YtEa5cIqHC\nZen/9ZOaNQeK/qhjZGZHO+f+eHJGGdG4LN1ronpZukdE67J0r4nqZekeEY3L0r0o3MvS5zf9S9i+\na/ukvR3Rca3KnGn5T3POpVTw2H47OyIiIiIHUkg6PCIiIhL9/DSU8qeuli4iIiJSFZWb8JjZB1TQ\n+XPOnRGSikRERCQsouGEgOFS0ZDWxLBVISIiIhJCFS1L/zKchYiIiEh4RcMJAcNlv5OWzaw9cD9w\nKFDtl3bnXJsQ1iUiIiJywFRmldZ04A7gEeAE4GI02VlERKTK89PZ2CrTcUlyzn1OyUkKNznn7gRO\nC21ZIiIiIgdOZRKefDOLAdaa2SggFagR2rJEREQk1Fz5l7f0nMokPNcAycDVQE9gKHBRKIsSERER\nOZD2m/A45xYGb+ZQMn9HREREPCDgo1MtV2aV1hf8wQkInXMnhqQiERERkQOsMnN4ri9zuxpwDlAU\nmnJEREQkXAI+msNTmSGtxb9r+tbMFoSoHhEREZEDrjJDWvXK3I2hZOJy7ZBVJCIiInKAVWZIazEl\nc3iMkqGsDcCloSxKREREQs9Py9Ir0+E5xDm3r2yDmSWGqB4RERGRA64y5+H57g/a5h3oQkRERCS8\nAmHcIq3chMfMGgPNgCQz6wGluVctSk5EKCIiIlIlVDSkNRD4B9AceJhfOzzZwM2hLUtERERCTXN4\nAOfcC8ALZnaOc+6tMNYkIiIickBVZg5PTzOr88sdM6trZveGsCYREREJAz/N4alMh+cU59zuX+44\n53YBp4auJBEREZEDqzLL0mPNLNE5lw9gZkmAlqWLiIhUcdGQvIRLZTo8rwCfm9n04P2LgRdDV5KI\niIjIgVWZa2k9YGbLgJOCTfc45z4NbVkiIiISalql9TvOuU+ATwDM7Bgze8o5NzKklYmIiIgcIJWZ\ntIyZ9TCzB81sI3APsCqkVYmIiEjIBSx82/6YWR0ze9PMVpnZT2Z2pJkdZmbzzGyFmX1gZrXK7D/O\nzNaZ2WozG7i/56/oTMsdgAuC2w7gX4A5506oxM9QRERE5M94DPjEOfdXM0ug5KoOs4DrnXNfmtkl\nwA3AbWZ2KDAE6Aw0BWabWQfnXHF5T15RwrMKOBE43Tl3jHPuCaDcJxIREZGqJYCFbauImdUGjgWe\nBXDOFQRPidMB+Cq42yzgnODtM4HXnXP5zrkNwDqgd0WvUVGH5y/AVuALM5tmZv3BR7ObRERE5IAx\ns+FmtqjMNrzMw62BDGC6mS0xs3+aWXXgR0o6NwDnAi2Ct5sBW8ocnxJsK1e5HR7n3LvOuSFAJ+AL\nYDTQyMymmNnJf+I9ioiIiM8556Y653qV2aaWeTgOOByY4pzrAewFbgIuAUaY2WKgJlDw377+fict\nO+f2Oudedc4NpuRCokuAG//bFxQREZHo4MK47UcKkOKcmx+8/yZwuHNulXPuZOdcT+A1YH3w8VR+\nTXugpH+SWtELVGqV1i+cc7uCPbT+f+Y4ERERkfI457YBW8ysY7CpP7DSzBoBmFkMcCvwdPDx94Eh\nZpZoZq2B9sCCil6jUufhEREREe+JsktLXAW8Elyh9TMlV3a40Mx+Oe/f28B0AOfcj2Y2A1gJFAEj\nK1qhBerwiIiISBRwzi0Fev2u+bHg9kf7jwfGV/b51eERERHxqYD5Z/H1n5rDIyIiIlIVKeERERHx\nqUqsnvIMJTwiIiLieUp4REREfCrKVmmFlBIeERER8TwlPCIiIj4V8M8iLSU8IiIi4n1KeERERHwq\ngH8iHiU8IiIi4nlKeERERHxK5+ERERER8RB1eERERMTzonZIa1X+9kiX4HmzE9pEugTPu+Lv2ZEu\nwRc+f7VupEvwvF712kW6BAkBLUsXERER8ZCoTXhEREQktHRpCREREREPUcIjIiLiU1qWLiIiIuIh\nSnhERER8Squ0RERERDxECY+IiIhPaZWWiIiIiIco4REREfEpJTwiIiIiHqKER0RExKecVmmJiIiI\neIcSHhEREZ/SHB4RERERD1GHR0RERDxPQ1oiIiI+pSEtEREREQ9RwiMiIuJTLtIFhJESHhEREfE8\nJTwiIiI+FdCJB0VERES8QwmPiIiIT2mVloiIiIiHKOERERHxKSU8IiIiIh6ihEdERMSndB4eERER\nEQ9RwiMiIuJTOg+PiIiIiIco4REREfEprdISERER8RB1eERERMTzNKQlIiLiU1qWLiIiIuIhSnhE\nRER8KuCjjEcJj4iIiHieEh4RERGf0rJ0EREREQ9RwiMiIuJT/pnBo4RHREREfEAJj4iIiE9pDo+I\niIiIhyjhERER8amARbqC8FHCIyIiIp6nhEdERMSndKZlEREREQ9RwiMiIuJT/sl3lPCIiIiIDyjh\n+RNq1qrBHZPG0a5jG5xz3DHmPvr1P5LjB/UjEAiwa8dubrvmXjLSd9DrqB48+vwDpG5OA2DOzC95\nZtL0CL+D6JdYK5mBD15G/Q7NwTk+uWEaPS8dRL02TUofz8/O5cVTbqFW8wZcPOdBdq3fCkDaknXM\nvlk/4/2xhs2oduENpfdj6jem4JNXseSaxHbpAy6Ay8ki/7XHcNk7iT/hbOIOPy64cywxBzVn7+1D\nITcnQu+gaoirlUyPScOo2bEFOMeSMVMpzsvnsAcvJa56IrlbdrB4xFMU5eQB0P6qM2j5t+OhOMDy\nW18kY+7yyL6BKqBGrercOPF6WndshXOOCddN5MfFKwE4//JzGXX7FZze5WyydmXTsm0Lxj0ylg5d\n2jHtged4/Zk3Ily9hJs6PH/C2HtH8+2c77n+sluIi48jKaka61f/zFMPTgPgb5eey+XXXsy9Nz4E\nwJL5y7hq6A0VPaX8zol3DmXD3OW8f8XjxMTHEp+UyIcjnyx9/Phb/0b+ntzS+1mb0nnxlFsiUWqV\n5TJSyXt4dMkdiyH5jukUrZiHy82BT14BIL7f6SScfD75b06h8It3KPziHQBiDz2C+OPOVGenErre\neyHpc5ax8LLHsPhYYpMSOWrGOH686xUy562i5QXH0W7E6ax68A1qdmhGs7OO5IvjxlKtcV2OmnEz\ns4+6FgJ+GnD4866+exTzv1jIbcPvIi4+jmpJiQA0atqQ3sf2ZFtKeum+2bv38NhtT9Jv0NGRKjcq\n6cSDB4CZ9TazI4K3DzWza83s1FC9XqjVqFmdnn27886rHwBQVFjEnuwc9ub8+uVbLbkazlcjogdW\nQs0kmvfuyIrX5wIQKCwmPzv3N/t0OL0PP703LwLVeVNs+264zG24XRmQn/frAwnV/nBwP+7wYyla\n8lX4Cqyi4momUb9vJza/OhcAV1hMUXYuNdo0IXPeKgC2f7mCpqcfAUDjgT1JfXcegYIicjdnsHdD\nOnV7tItQ9VVD9ZrVOaxPVz58bSZQ8js5J3svAFfdOYLJ46fi3K8f4t2Zu1m1bDVFhUURqVciLyQJ\nj5ndAZwCxJnZLKAP8AVwk5n1cM6ND8XrhlKzlk3Zlbmbux+7hY6Htmfl8lU8eNuj5OXuY9RNlzP4\n3EHk7NnLZeeMKj2mW88uzPj8BTLSdzDpridZv3pDBN9B9KvdoiG5O/cw6OHhNDykJekrNvLFnS9R\nmJcPQPPeHcndkcXujem/OWbozHspyMnjm4lvkrpgdaTKr5Lievy2A5Nwyv8R1+sE3L5c8ib/LjmL\nTyCu0+Hkv/1MmKusepJbNqIgcw89HrucWoceTNbyDay47UX2rE6h8aBebPtkEc0G9yWpaX0AqjWp\nx67Fa0uPz9uaSbUmdSNVfpXQpGVjdmdmcfMjY2l7aBvWLF/LY7c/Ra9+h5OxdQfrV/4c6RKrBC1L\n/9/9FTgaOBYYCZzlnLsHGAicH6LXDKnYuFg6de3AG8+/w/kD/kFe7j4uGTUUgCcnPMPAnmfz0Vuf\nMuSScwD4aflqBvX6C+f1v4jXnn2TR6ZPiGT5VUJMXCwHdWnF0pc+56VTb6UwL5/eIwaXPt7pzCNZ\nVSbd2bt9N8/0Hc1Lp97K3Hte4bTHR5BQIykSpVdNsXHEde5N0dJvS5sKPn6Z3HsupeiHL0k45rTf\n7B7XuTfFG37ScFYlxMTFULtrKzY+P5svB9xMUW4+7UedwZIxU2n9j5M47tPxxNWoRqBAacN/KzY2\nlg5d2/Pui+9z6cArSn4nX3chQ6/6G89OfD7S5UkUClWHp8g5V+ycywXWO+eyAZxzeVQwZGhmw81s\nkZktysxNL2+3iEhP20761gxWLCmZEDfrwy/o1K3jb/aZ+fZnnHTaCQDszcklL7dkiOCbz+cRFx9H\nnXq1w1t0FbNn6072bN3JtqXrAVgzcwEHdWkFgMXG0H7QEaz6YH7p/sUFRezbXfLlm75iI1mbtlO3\nTeOw111VxXbqSXHqelzO7v94rGjxXGK7HfWbtrge/TScVUl5aTvZt3Unu5aUfJbTPpxP7W6tyFmX\nxrwhE/hy4C2kvPMdezdtB2Df1p2laQ9AUpP67Nu6KyK1VxUZWzPI2JrByiUlQ4RzP/qKDl3b06Rl\nY6bPmsqM71+hYZOGPPvp09RrqLSsPC6MW6SFqsNTYGbJwds9f2k0s9pU0OFxzk11zvVyzvWqn3xQ\niEr772Rm7CQ9NZ2D27YEoE+/Xvy8ZgMtWzcv3eeEQf3YsG4TAPUb1itt79LjEGLM2L0zK7xFVzG5\nGVns2bqTusEVWQcf3ZnMtaklt4/pws71aeRs21m6f1K9mlhMyYVgardsSJ3WB5EV/AKR/Ys7vB9F\nP/zagbEGTX59rEsf3PaUX3eulkxs2y4U/Xs+sn/5GVnkpWZSo23Jz7Rhvy7sWZNKQoNaJTuY0XHM\n2Wx8cTYA2z5bTLOzjiQmIY7klg2p3qYxu5asi1T5VcLOjF1sT8ugRduS38E9j+nBmhVrOeOwv3Je\n379zXt+/k7E1g0sHXsHODHUeJXSrtI51zuUDOOfKdnDigYtC9JohN+GWR7h/8h3Ex8eTsimN20eP\n586Hb6JVu4MJBAJsTdnGvWMfBGDA4BM476KzKSoqJn9fPjdecXuEq68aPr/9BU57/Epi4+PYvXk7\nn1w/FYBOZ/Rl1fu/nazcvE8njr7uHAKFxbiAY9bN09mXtTcSZVc9CYnEdehO/huTS5sST78Ia9gM\nnMPt2k7+m78+Fte1L0Wrl0BBfiSqrZKW3/ICPSePxOLjyN20nSWjn6HFuf1offEAALbOXMjm174E\nYM/qVNLe/54Tv3oIV1TM8nHTtUKrEh697Qluf+Jm4uPjSdu8lfuufbDcfes1rMu0j6dQvUYygYDj\n3GHnMPT4S8jNyS33GD/w0yotKzuLPZoc1vio6CzMQ4YmtIl0CZ53xV+zI12CL3z+ao1Il+B5E2Oj\na5qBV32d+nlYr19+fasLwvZdO3HjaxG9NrvOwyMiIuJTWqUlIiIi4iFKeERERHzKP/mOEh4RERHx\nASU8IiIiPuWnVVpKeERERMTzlPCIiIj4lJ8ueK2ER0RERDxPHR4RERHxPA1piYiI+JQmLYuIiIh4\niDo8IiIiPhXAhW3bHzOrY2ZvmtkqM/vJzI4Mtl8VbPvRzB4ss/84M1tnZqvNbOD+nl9DWiIiIhIN\nHgM+cc791cwSgGQzOwE4EzjMOZdvZo0AzOxQYAjQGWgKzDazDs654vKeXAmPiIiIT7kwbhUxs9rA\nscCzAM65AufcbuBKYIJzLj/Yvj14yJnA6865fOfcBmAd0Lui11CHR0RERELOzIab2aIy2/AyD7cG\nMoDpZrbEzP5pZtWBDkA/M5tvZl+a2RHB/ZsBW8ocnxJsK5eGtERERHyqMnNrDhTn3FRgajkPxwGH\nA1c55+ab2WPATcH2ekBf4Ahghpm1+W9eXwmPiIiIRFoKkOKcmx+8/yYlHaAU4G1XYgElK+kbAKlA\nizLHNw+2lUsdHhEREZ8KhHGriHNuG7DFzDoGm/oDK4F3gRMAzKwDkADsAN4HhphZopm1BtoDCyp6\nDQ1piYiISDS4CngluELrZ+BiYC/wnJn9GygALnLOOeBHM5tBSaeoCBhZ0QotUIdHRETEt6Lp4qHO\nuaVArz946P/K2X88ML6yz68hLREREfE8JTwiIiI+pWtpiYiIiHiIEh4RERGfiqY5PKGmhEdEREQ8\nTx0eERER8TwNaYmIiPiUJi2LiIiIeIgSHhEREZ8KOE1aFhEREfEMJTwiIiI+5Z98RwmPiIiI+IAS\nHhEREZ8K+CjjUcIjIiIinqeER0RExKd0aQkRERERD1HCIyIi4lM607KI/H97dx5n53wvcPzzzcxE\nJos1CElkEUQEKRFLbLFVglAtqorWdUNUKGJJw7W0Smorrl6Uam1Fb+jNDUquJWgFaayxR2SVTBZZ\nJ5HMzO/+cY7pWBIiZs7Mcz5vr/N6nfOc3/M83/NIzvnm+1seSVKGWOGRJKlIOUtLkiQpQ6zwSJJU\npJylJUmSlCEmPJIkKfPs0pIkqUg5LV2SJClDrPBIklSkUnLQsiRJUmZY4ZEkqUi58KAkSVKGWOGR\nJKlIFdMsrUab8By9TpdCh5B5l8z5e6FDyLw77tmk0CEUhf7lrQodQuY9Of73hQ5BWiuNNuGRJEn1\ny1tLSJIkZYgVHkmSipSztCRJkjLECo8kSUXKlZYlSZIyxAqPJElFqpjW4bHCI0mSMs8KjyRJRcp1\neCRJkjLEhEeSJGWeXVqSJBUpFx6UJEnKECs8kiQVKRcelCRJyhArPJIkFSnH8EiSJGWIFR5JkoqU\nCw9KkiRliBUeSZKKVI2ztCRJkrLDCo8kSUWqeOo7VngkSVIRsMIjSVKRch0eSZKkDLHCI0lSkbLC\nI0mSlCEmPJIkKfPs0pIkqUglFx6UJEnKDis8kiQVKQctS5IkZYgVHkmSilSywiNJkpQdVngkSSpS\nztKSJEnKECs8kiQVKWdpSZIkZYgVHkmSipRjeCRJkjLECo8kSUXKMTySJEkZYoVHkqQi5UrLkiRJ\nGWLCI0mSMs8uLUmSilSN09IlSZKywwqPJElFykHLkiRJGWKFZw2ss25LDhnx72y8dQcgMfrcW+lz\nUn826rpZ7fufLKrktgG/oMuePel3wQ8pKSulemUVT/z6Xqb8483CfoAmYL312nDT70bQo8fWpJQY\nfOp5tG+/Gb8YfibbdO/GPnsfwcsTXgegtLSUm353Jb16bUdpaSn33vsg11z9XwX+BE1Dm3Vbc9m1\nw+nWvSspJS4661fsvX9f+h28F6kmMW/uxww/4zLmzJ5Lv4P3Zsj5g0g1iaqqakZcdB0TXny10B+h\n0WuxbkuOvnIQ7bbpQErwwHm3MGXCe/Q98bv0PeFAaqoTbz35Mg9feS8bdGjLef93DRUfzARg6svv\nM3L47QX+BI3b5CnTGfofV9S+nj7zI04/+Xh22WlHfnnVjVQuW87mm23CiIvPo3WrVgD8/s77eXD0\nY5Q0a8awswbTd9edCxV+o1FMY3hMeNbAQRcfzwdjX+XBwdfTrKyEsvJ1eOj0G2vf3//C4/hkUSUA\nlR8v5oGTrmZJxQI23roDx951PjfsOqRQoTcZv7nqYsaMGcuPjzuNsrIyWrZswcKFi/jRsYO54cbL\nP9P2e0cOYJ11mrNrn/6Ul7dg/IQx/OWBUUydOqNA0Tcdw351Ns899TxnnTyMsrJSWpS34P23J3Pj\niFsAOO7koxl8zr9x2dKtNtoAABC/SURBVHkjeOGZl3jqb88AsHWPblxz6+UctucxhQy/STji4hN5\ne+yr3HnabynJf19suXsPtjtwZ67pfwHVK6povdG6te3nTZnNdQOGFTDipqVLpw6M/NNNAFRXV7Pf\nEcez/z57cNbwyxl6+sns8p0deHD0Y9xxz0iGDDqBSZOn8OgTY/mfu2+mYu58Tj5zGA/fdxslJSUF\n/iRqKA3WpRURdzbUuerDOm3K2WLX7rxy39MA1Kysrk1uPtXjkF2ZOOofAMyeOIUlFQsAmPPudEpb\nNKekufnl6qy7bhv67tmHP/3xfgBWrlzJwoWLeeedSbz33gdf3CElWrZqSUlJCeXlLVixYiWLFy9p\n4KibntZtWrHz7t9h5D2jAFi5sorFi5awdMnS2jblLctrbypYWbmszvYWRXWzwW+qRZtyuvbpzov3\nPwVA9cpqli+qZI/jDuSp/xpF9YoqAJbMW1TIMDNj3PhX6Nh+MzZvtylTps2gd6/tAdh9l50YM/Y5\nAJ58dhz999+H5s2b02HzdmzRYXNef+vdQobdKKQG/K/Q6uUXOCJGfX4T0C8i1gdIKQ2sj/PWp/U7\nbkLlvMUcevUpbNpjC2a9PpnHL7mLlcs+AaBjn+4snbuQjz+c/YV9uw/ow6w3Pqz9ktOX69S5A3Pn\nzufmW65i+x225eWX3+C8oZd+5ge3roceepRDDj2QSR+8QHnLci44/1d8/PHCBo666emwxeZ8PO9j\nLr/+IrbZbismvvY2V154Lcsql3PGsFMZeNQAlixewk+PPK12n/3778PPh5/GRm03YPCPzy5g9E3D\nhh03Ycm8RRxz9alsvm0npr/+Af9z6Z207dqOLn260//cY1j5yUpGX3430177IL/Pxpz18BUsX7KM\nv119P5NfeqfAn6LpePSJsQw4YB8AtuzSiSeffZ79996Dx596llmz5wJQMWceO/TsXrvPppu0pWLO\n3ILEqy+XzxFuA3oCCTgJGAAcDtQAFcBPUkozIyKA6/PvV+a3T1jd8eurwtMBWARcC1yTfyyu8/xL\nRcSgiBgfEeNfWvJ+PYX2zTQraUa7np2ZcPf/cfuA4ayo/IQ9Tjus9v3tBu7OxFHPf2G/tlu1Z78L\nfsgjw+yP/yqlpaX06rUdt912D313P5TKpZWcM3TwKtv37r0j1dXVdNtyN3r22JshZ5xM584dGzDi\npqmktIRtt9+G+/70ID844ASWVS7n5CEnAnDDFTdzwE4DGT3yMX500lG1+zzx6FgO2/MYhvzkPIac\nf0qhQm8ympWU0L5nF56/ewzXHTKMFcs+od/ggZSUlNByvdbccMRFjP71PRx/05kALKpYwK/2GMJ1\nhwxj1C/v4rjrh7BO6/ICf4qmYeXKlTz93AsctN9eAPzyF2dx34OjOfqkISytXEZZmZX11alJqcEe\nX8P1wN9SSt2BHYG3gKtSSjuklHoBo4H/yLftD2yVfwwCvnIAZ30lPL2BfwLDgYUppaeBZSmlsSml\nsavaKaV0a0qpd0qp9y6tu9VTaN/MolnzWfTRfGa+MgmAtx95kXY9OwMQJc3Y5uBdePN/x31mnzbt\nNuQHt57FqLNvZsHUioYOucmZMeMjZsyYxfiXXgHgrw89yo69tltl+6OPOZwxY56hqqqKOXPmMW7c\neHbaaYeGCrfJmj2zgtkzK3h9wkQAHv/fJ9l2+20+0+bhkX/jwEP7fWHff457hQ6d2rP+hus1SKxN\n1cJZ81g4az5T898Xrz3yAh16dmHBrPm8/tiLAEx7dRI1NYlWG7ahekUVlQty3bEz3pjMvKmz2bjL\nZgWLvyl5dtx4tt16S9puuAEAXTt15Pe//TUP/OFGBhywDx3b567jJhtvxKzZc2r3m10xl002bluQ\nmPVFEbEesDdwO0BKaUVKaUFKqW6/byuo7Rs7HLgz5YwD1o+I1f6lqZeEJ6VUk1K6DvgpMDwi/pMm\nPkB66ZyFLPpoHhvmZ2R17rsdc97LDY7tsmdP5k2ayeJZ82vbr7NuS465YyhPjbiP6ePtJ/46KmbP\nZcb0j9hqq64A7NtvD95+a9WVvmnTZrDPvrsD0LJlOX12+Q7vvDupQWJtyubOmc+smRV03nILAHbb\nqzeT3p3MFl3+VR3rd/DeTH5vCgBbdO5Qu33b7behefMyFsy363B1Fs9ZyIKZ89g4/32xVd+ezH5v\nOhMfH0+33XoA0LZLO0rLSlk6fzGtNmxDNAsg1x3WtnM75k39Yve4vuiRMU8z4MB9a1/P+zg3drKm\npoZb/nQfRx8xAIB+e+7Go0+MZcWKFUyfOYup02ey/bZbFyLkRqURjeHpAswB7oiIlyPitohoBRAR\nl0fENOA4/lXhaQ9Mq7P/9Py2VarXJCSlNB04KiIOIdfF1aQ9fvGdHHH9aTQrK2XB1ApGD83NaOlx\n2O68+bnurN4nHsQGnTdlrzOOZK8zjgTg3uOvpNJBiqt1zjkXc/sd19G8rDmTP5zK4FPO5bCBB3H1\nNZfQtu2GjBz5B1577U2OOPxEbr3lLm6+5SpeGv8YEcFdd/03E994u9AfoUn49S+uZsTvLqOseSnT\np8zkwjN/yWXXDqdzty2oqanho+mzuPTcEQAceGg/Bh41gKqqKpYv/4Shgy4scPRNw18v+SM/+u3p\nlJSVMn/abO4fegsrli3n6N+cytDHfkPVyiruOydXhe/aZ1u+e/ZRVFdVkWoSI4ffzrKFS7/iDKpc\ntpznX3qZi887o3bbI2Oe5r4HRwNwwD578L1DDgKgW9dOfHe/vRh43CmUlpQw/OzTnKHVwCJiELnu\np0/dmlK6Nf+8FNgJGJJSeiEirgcuAC5KKQ0nVzwZBpwOXPyNzt9YZ1xc3um4xhlYhlwx5x+FDiHz\nOrXZpNAhFIX+5V0LHULmXTH+8q9upLVW1rZrNOT5tmy7U4P91k6aO2GVny0i2gHjUkqd86/3Ai5I\nKR1Sp80WwCMppZ4RcQvwdErpz/n33gH2TSl9tKpzuNKyJEkqqJTSLGBaRHw6oHB/4M2I2KpOs8OB\nT8v4o4ATImc3cuOFV5nsQBMfVyNJkr65xrA+Th1DgHsiojnwAblxwLflk6AaYApwar7tI+SmpL9P\nblr6T7/q4CY8kiSp4FJKr5Cb5V3X91fRNgE/W5Pj26UlSZIyzwqPJElFKqWaQofQYKzwSJKkzLPC\nI0lSkappXIOW65UVHkmSlHlWeCRJKlKNdfHh+mCFR5IkZZ4VHkmSipRjeCRJkjLECo8kSUXKMTyS\nJEkZYoVHkqQiVWOFR5IkKTus8EiSVKSSs7QkSZKywwqPJElFyllakiRJGWLCI0mSMs8uLUmSipS3\nlpAkScoQKzySJBUpBy1LkiRliBUeSZKKlLeWkCRJyhArPJIkFSnH8EiSJGWIFR5JkoqU6/BIkiRl\niBUeSZKKlGN4JEmSMsQKjyRJRcp1eCRJkjLECo8kSUUqOUtLkiQpO0x4JElS5tmlJUlSkXLQsiRJ\nUoZY4ZEkqUi58KAkSVKGWOGRJKlIOS1dkiQpQ6zwSJJUpBzDI0mSlCFWeCRJKlJWeCRJkjLECo8k\nSUWqeOo7VngkSVIRiGLqv6tvETEopXRroePIMq9x/fMaNwyvc/3zGqsuKzzfrkGFDqAIeI3rn9e4\nYXid65/XWLVMeCRJUuaZ8EiSpMwz4fl22Vdc/7zG9c9r3DC8zvXPa6xaDlqWJEmZZ4VHkiRlngnP\ntyAiDo6IdyLi/Yi4oNDxZFFE/CEiKiLijULHklUR0TEinoqINyNiYkScWeiYsiYiWkTEixHxav4a\nX1romLIqIkoi4uWIGF3oWNQ4mPCspYgoAW4C+gM9gGMjokdho8qkPwIHFzqIjKsCzkkp9QB2A37m\nn+Vv3SfAfimlHYFewMERsVuBY8qqM4G3Ch2EGg8TnrXXB3g/pfRBSmkFcB9weIFjypyU0jPA/ELH\nkWUppY9SShPyzxeT+7FoX9iosiXlLMm/LMs/HEj5LYuIDsAhwG2FjkWNhwnP2msPTKvzejr+SKiJ\ni4jOwHeAFwobSfbku1peASqAMSklr/G377fAeUBNoQNR42HCI+kzIqI1MBL4eUppUaHjyZqUUnVK\nqRfQAegTET0LHVOWRMShQEVK6Z+FjkWNiwnP2psBdKzzukN+m9TkREQZuWTnnpTSg4WOJ8tSSguA\np3Bs2retLzAwIj4kN8Rgv4i4u7AhqTEw4Vl7LwFbRUSXiGgO/BAYVeCYpDUWEQHcDryVUrq20PFk\nUURsHBHr55+XAwcCbxc2qmxJKQ1LKXVIKXUm9338ZErpxwUOS42ACc9aSilVAacDj5Eb5PlASmli\nYaPKnoj4M/A8sE1ETI+Ifyt0TBnUFzie3L+IX8k/BhQ6qIzZDHgqIl4j94+lMSklp01LDcCVliVJ\nUuZZ4ZEkSZlnwiNJkjLPhEeSJGWeCY8kSco8Ex5JkpR5JjxSA4iI6vw07zci4i8R0XItjrXvp3eA\njoiBEXHBatquHxGnfYNzXBIRQ1fx3qCIeDv/GB8R+36N4602znybzhHxozqve0fEDfnnP4mI/1zD\njyFJtUx4pIaxLKXUK6XUE1gBnFr3zchZ47+PKaVRKaUrV9NkfWCNE55VyS/bfwqwZ0qpOzAIuDsi\nVnv/uK8RJ0BnoDbhSSmNTymdsZYhSxJgwiMVwrNAt3xF452IuBN4A+gYEQdFxPMRMSFfCWoNEBEH\n5ysqE4AjPz1Q3cpHRGwaEQ9FxKv5xx7AlcCW+erSVfl250bESxHxWkRcWudYwyPi3Yh4DthmFbGf\nD5ybUpoLkL+7+h3Az/LH+DAi2uaf946Ip78kzj9GxA0R8Y+I+CAifpA/9pXAXvlYz6pbyaorv1rx\nyPxneCki+q75/wJJxcaER2pAEVEK9Adez2/aCvhdSmk7YClwIXBASmknYDxwdkS0AH4PHAbsDLRb\nxeFvAMamlHYEdgImAhcAk/LVpXMj4qD8OfsAvYCdI2LviNiZ3DL8vYABwC6rOMd2wOdvyjge6LEG\nlwFyKw7vCRxKLtEhH+uz+VivW82+1wPXpZR2Ab4P3LaG55ZUhEoLHYBUJMoj4pX882fJ3bNqc2BK\nSmlcfvtu5BKHv+dua0VzcrfT6A5MTim9B5C/EeKgLznHfsAJkLsjN7AwIjb4XJuD8o+X869bk0uA\n2gAPpZQq8+eo7/vB/TWlVAO8GRGbruG+BwA98tcIYN2IaJ1SWvKtRigpU0x4pIaxLKXUq+6G/A/2\n0rqbyN1b6djPtfvMfmspgCtSSrd87hw//5r7v0muyvRknW07k6vyAFTxr8pxi9Uc55PPxbQmmgG7\npZSWr+F+koqYXVpS4zEO6BsR3QAiolVEbE3ubtqdI2LLfLtjV7H/E8Dg/L4lEbEesJhc9eZTjwEn\n1Rkb1D4iNgGeAY6IiPKIaEOu++zL/AYYEREb5ffvBXwP+DSB+pBcAgS57qY18flYV+VxYMinL77l\nhFBSRpnwSI1ESmkO8BPgz/m7aT8PdM9XMgYBD+cHLVes4hBnAv0i4nVy42x6pJTmkesieyMirkop\nPQ7cCzyfb/ffQJv84OP7gVeBR8ndyfvLYhxFrjvu7xHxPvAccEQ+doBLgesjYjxQvYaX4DWgOj/g\n+qzVtDsD6J0fdP0mn5vxJklfxrulS/pG8gOw7yD3D6cfJ79MJDViJjySJCnz7NKSJEmZZ8IjSZIy\nz4RHkiRlngmPJEnKPBMeSZKUeSY8kiQp80x4JElS5v0/Ps+A/+HJomMAAAAASUVORK5CYII=\n",
"text/plain": [
"<Figure size 720x720 with 2 Axes>"
]
},
"metadata": {
"tags": []
}
},
{
"output_type": "display_data",
"data": {
"text/html": [
"<div id=\"3ddb1981-37d6-4b0e-8ba7-3ac1bace0f7b\" style=\"height: 600px; width: 900px;\" class=\"plotly-graph-div\"></div><script type=\"text/javascript\">require([\"plotly\"], function(Plotly) { window.PLOTLYENV=window.PLOTLYENV || {};window.PLOTLYENV.BASE_URL=\"https://plot.ly\";Plotly.newPlot(\"3ddb1981-37d6-4b0e-8ba7-3ac1bace0f7b\", [{\"type\": \"scatter\", \"x\": [1970.0, 1970.081850533808, 1970.1637010676156, 1970.2455516014236, 1970.3274021352313, 1970.4092526690392, 1970.491103202847, 1970.5729537366549, 1970.6548042704626, 1970.7366548042705, 1970.8185053380782, 1970.9003558718862, 1970.982206405694, 1971.0640569395018, 1971.1459074733095, 1971.2277580071175, 1971.3096085409252, 1971.3914590747331, 1971.4733096085408, 1971.5551601423488, 1971.6370106761565, 1971.7188612099644, 1971.8007117437724, 1971.88256227758, 1971.964412811388, 1972.0462633451957, 1972.1281138790036, 1972.2099644128114, 1972.2918149466193, 1972.373665480427, 1972.455516014235, 1972.5373665480427, 1972.6192170818506, 1972.7010676156583, 1972.7829181494662, 1972.864768683274, 1972.946619217082, 1973.0284697508896, 1973.1103202846975, 1973.1921708185052, 1973.2740213523132, 1973.355871886121, 1973.4377224199288, 1973.5195729537365, 1973.6014234875445, 1973.6832740213524, 1973.7651245551601, 1973.846975088968, 1973.9288256227758, 1974.0106761565837, 1974.0925266903914, 1974.1743772241994, 1974.256227758007, 1974.338078291815, 1974.4199288256227, 1974.5017793594307, 1974.5836298932384, 1974.6654804270463, 1974.747330960854, 1974.829181494662, 1974.9110320284697, 1974.9928825622776, 1975.0747330960853, 1975.1565836298932, 1975.238434163701, 1975.320284697509, 1975.4021352313168, 1975.4839857651245, 1975.5658362989325, 1975.6476868327402, 1975.7295373665481, 1975.8113879003558, 1975.8932384341638, 1975.9750889679715, 1976.0569395017794, 1976.1387900355871, 1976.220640569395, 1976.3024911032028, 1976.3843416370107, 1976.4661921708184, 1976.5480427046264, 1976.629893238434, 1976.711743772242, 1976.7935943060497, 1976.8754448398577, 1976.9572953736654, 1977.0391459074733, 1977.1209964412812, 1977.202846975089, 1977.284697508897, 1977.3665480427046, 1977.4483985765125, 1977.5302491103203, 1977.6120996441282, 1977.693950177936, 1977.7758007117438, 1977.8576512455516, 1977.9395017793595, 1978.0213523131672, 1978.1032028469751, 1978.1850533807828, 1978.2669039145908, 1978.3487544483985, 1978.4306049822064, 1978.5124555160141, 1978.594306049822, 1978.6761565836298, 1978.7580071174377, 1978.8398576512454, 1978.9217081850534, 1979.0035587188613, 1979.085409252669, 1979.167259786477, 1979.2491103202847, 1979.3309608540926, 1979.4128113879003, 1979.4946619217083, 1979.576512455516, 1979.658362989324, 1979.7402135231316, 1979.8220640569396, 1979.9039145907473, 1979.9857651245552, 1980.067615658363, 1980.1494661921708, 1980.2313167259786, 1980.3131672597865, 1980.3950177935942, 1980.4768683274021, 1980.5587188612099, 1980.6405693950178, 1980.7224199288257, 1980.8042704626334, 1980.8861209964414, 1980.967971530249, 1981.049822064057, 1981.1316725978647, 1981.2135231316727, 1981.2953736654804, 1981.3772241992883, 1981.459074733096, 1981.540925266904, 1981.6227758007117, 1981.7046263345196, 1981.7864768683273, 1981.8683274021353, 1981.950177935943, 1982.032028469751, 1982.1138790035586, 1982.1957295373666, 1982.2775800711743, 1982.3594306049822, 1982.4412811387901, 1982.5231316725979, 1982.6049822064058, 1982.6868327402135, 1982.7686832740214, 1982.8505338078292, 1982.932384341637, 1983.0142348754448, 1983.0960854092527, 1983.1779359430604, 1983.2597864768684, 1983.341637010676, 1983.423487544484, 1983.5053380782917, 1983.5871886120997, 1983.6690391459074, 1983.7508896797153, 1983.832740213523, 1983.914590747331, 1983.9964412811387, 1984.0782918149466, 1984.1601423487546, 1984.2419928825623, 1984.3238434163702, 1984.405693950178, 1984.4875444839859, 1984.5693950177936, 1984.6512455516015, 1984.7330960854092, 1984.8149466192172, 1984.8967971530249, 1984.9786476868328, 1985.0604982206405, 1985.1423487544484, 1985.2241992882562, 1985.306049822064, 1985.3879003558718, 1985.4697508896797, 1985.5516014234875, 1985.6334519572954, 1985.715302491103, 1985.797153024911, 1985.8790035587188, 1985.9608540925267, 1986.0427046263346, 1986.1245551601423, 1986.2064056939503, 1986.288256227758, 1986.370106761566, 1986.4519572953736, 1986.5338078291816, 1986.6156583629893, 1986.6975088967972, 1986.779359430605, 1986.8612099644129, 1986.9430604982206, 1987.0249110320285, 1987.1067615658362, 1987.1886120996442, 1987.2704626334519, 1987.3523131672598, 1987.4341637010675, 1987.5160142348755, 1987.5978647686832, 1987.679715302491, 1987.761565836299, 1987.8434163701068, 1987.9252669039147, 1988.0071174377224, 1988.0889679715303, 1988.170818505338, 1988.252669039146, 1988.3345195729537, 1988.4163701067616, 1988.4982206405693, 1988.5800711743773, 1988.661921708185, 1988.743772241993, 1988.8256227758006, 1988.9074733096086, 1988.9893238434163, 1989.0711743772242, 1989.153024911032, 1989.2348754448399, 1989.3167259786476, 1989.3985765124555, 1989.4804270462632, 1989.5622775800712, 1989.644128113879, 1989.7259786476868, 1989.8078291814948, 1989.8896797153025, 1989.9715302491104, 1990.053380782918, 1990.135231316726, 1990.2170818505338, 1990.2989323843417, 1990.3807829181494, 1990.4626334519573, 1990.544483985765, 1990.626334519573, 1990.7081850533807, 1990.7900355871886, 1990.8718861209964, 1990.9537366548043, 1991.035587188612, 1991.11743772242, 1991.1992882562276, 1991.2811387900356, 1991.3629893238435, 1991.4448398576512, 1991.5266903914592, 1991.6085409252669, 1991.6903914590748, 1991.7722419928825, 1991.8540925266905, 1991.9359430604982, 1992.017793594306, 1992.0996441281138, 1992.1814946619218, 1992.2633451957295, 1992.3451957295374, 1992.4270462633451, 1992.508896797153, 1992.5907473309608, 1992.6725978647687, 1992.7544483985764, 1992.8362989323844, 1992.918149466192, 1993.0, 1993.081850533808, 1993.1637010676156, 1993.2455516014236, 1993.3274021352313, 1993.4092526690392, 1993.491103202847, 1993.5729537366549, 1993.6548042704626, 1993.7366548042705, 1993.8185053380782, 1993.9003558718862, 1993.982206405694, 1994.0640569395018, 1994.1459074733095, 1994.2277580071175, 1994.3096085409252, 1994.3914590747331, 1994.4733096085408, 1994.5551601423488, 1994.6370106761565, 1994.7188612099644, 1994.8007117437724, 1994.88256227758, 1994.964412811388, 1995.0462633451957, 1995.1281138790036, 1995.2099644128114, 1995.2918149466193, 1995.373665480427, 1995.455516014235, 1995.5373665480427, 1995.6192170818506, 1995.7010676156583, 1995.7829181494662, 1995.864768683274, 1995.946619217082, 1996.0284697508896, 1996.1103202846975, 1996.1921708185052, 1996.2740213523132, 1996.355871886121, 1996.4377224199288, 1996.5195729537368, 1996.6014234875445, 1996.6832740213524, 1996.7651245551601, 1996.846975088968, 1996.9288256227758, 1997.0106761565837, 1997.0925266903914, 1997.1743772241994, 1997.256227758007, 1997.338078291815, 1997.4199288256227, 1997.5017793594307, 1997.5836298932384, 1997.6654804270463, 1997.747330960854, 1997.829181494662, 1997.9110320284697, 1997.9928825622776, 1998.0747330960853, 1998.1565836298932, 1998.238434163701, 1998.320284697509, 1998.4021352313168, 1998.4839857651245, 1998.5658362989325, 1998.6476868327402, 1998.7295373665481, 1998.8113879003558, 1998.8932384341638, 1998.9750889679715, 1999.0569395017794, 1999.1387900355871, 1999.220640569395, 1999.3024911032028, 1999.3843416370107, 1999.4661921708184, 1999.5480427046264, 1999.629893238434, 1999.711743772242, 1999.7935943060497, 1999.8754448398577, 1999.9572953736654, 2000.0391459074733, 2000.1209964412812, 2000.202846975089, 2000.284697508897, 2000.3665480427046, 2000.4483985765125, 2000.5302491103203, 2000.6120996441282, 2000.693950177936, 2000.7758007117438, 2000.8576512455516, 2000.9395017793595, 2001.0213523131672, 2001.1032028469751, 2001.1850533807828, 2001.2669039145908, 2001.3487544483985, 2001.4306049822064, 2001.5124555160141, 2001.594306049822, 2001.6761565836298, 2001.7580071174377, 2001.8398576512454, 2001.9217081850534, 2002.0035587188613, 2002.085409252669, 2002.167259786477, 2002.2491103202847, 2002.3309608540926, 2002.4128113879003, 2002.4946619217083, 2002.576512455516, 2002.658362989324, 2002.7402135231316, 2002.8220640569396, 2002.9039145907473, 2002.9857651245552, 2003.067615658363, 2003.1494661921708, 2003.2313167259786, 2003.3131672597865, 2003.3950177935942, 2003.4768683274021, 2003.5587188612099, 2003.6405693950178, 2003.7224199288257, 2003.8042704626334, 2003.8861209964414, 2003.967971530249, 2004.049822064057, 2004.1316725978647, 2004.2135231316727, 2004.2953736654804, 2004.3772241992883, 2004.459074733096, 2004.540925266904, 2004.6227758007117, 2004.7046263345196, 2004.7864768683273, 2004.8683274021353, 2004.950177935943, 2005.032028469751, 2005.1138790035586, 2005.1957295373666, 2005.2775800711743, 2005.3594306049822, 2005.4412811387901, 2005.5231316725979, 2005.6049822064058, 2005.6868327402135, 2005.7686832740214, 2005.8505338078292, 2005.932384341637, 2006.0142348754448, 2006.0960854092527, 2006.1779359430604, 2006.2597864768684, 2006.341637010676, 2006.423487544484, 2006.5053380782917, 2006.5871886120997, 2006.6690391459074, 2006.7508896797153, 2006.832740213523, 2006.914590747331, 2006.9964412811387, 2007.0782918149466, 2007.1601423487546, 2007.2419928825623, 2007.3238434163702, 2007.405693950178, 2007.4875444839859, 2007.5693950177936, 2007.6512455516015, 2007.7330960854092, 2007.8149466192172, 2007.8967971530249, 2007.9786476868328, 2008.0604982206405, 2008.1423487544484, 2008.2241992882562, 2008.306049822064, 2008.3879003558718, 2008.4697508896797, 2008.5516014234875, 2008.6334519572954, 2008.715302491103, 2008.797153024911, 2008.879003558719, 2008.9608540925267, 2009.0427046263346, 2009.1245551601423, 2009.2064056939503, 2009.288256227758, 2009.370106761566, 2009.4519572953736, 2009.5338078291816, 2009.6156583629893, 2009.6975088967972, 2009.779359430605, 2009.8612099644129, 2009.9430604982206, 2010.0249110320285, 2010.1067615658362, 2010.1886120996442, 2010.2704626334519, 2010.3523131672598, 2010.4341637010675, 2010.5160142348755, 2010.5978647686832, 2010.679715302491, 2010.761565836299, 2010.8434163701068, 2010.9252669039147, 2011.0071174377224, 2011.0889679715303, 2011.170818505338, 2011.252669039146, 2011.3345195729537, 2011.4163701067616, 2011.4982206405693, 2011.5800711743773, 2011.661921708185, 2011.743772241993, 2011.8256227758006, 2011.9074733096086, 2011.9893238434163, 2012.0711743772242, 2012.153024911032, 2012.2348754448399, 2012.3167259786476, 2012.3985765124555, 2012.4804270462632, 2012.5622775800712, 2012.644128113879, 2012.7259786476868, 2012.8078291814948, 2012.8896797153025, 2012.9715302491104, 2013.053380782918, 2013.135231316726, 2013.2170818505338, 2013.2989323843417, 2013.3807829181494, 2013.4626334519573, 2013.544483985765, 2013.626334519573, 2013.7081850533807, 2013.7900355871886, 2013.8718861209964, 2013.9537366548043, 2014.035587188612, 2014.11743772242, 2014.1992882562276, 2014.2811387900356, 2014.3629893238435, 2014.4448398576512, 2014.5266903914592, 2014.6085409252669, 2014.6903914590748, 2014.7722419928825, 2014.8540925266905, 2014.9359430604982, 2015.017793594306, 2015.0996441281138, 2015.1814946619218, 2015.2633451957295, 2015.3451957295374, 2015.4270462633451, 2015.508896797153, 2015.5907473309608, 2015.6725978647687, 2015.7544483985764, 2015.8362989323844, 2015.918149466192, 2016.0], \"y\": [100.0, 99.9175, 100.68853004166667, 100.11376634934548, 102.03344781909418, 103.47381999080704, 101.23878547900563, 103.05095973907983, 103.62461008162738, 101.40358927221116, 102.70831545418027, 102.87521646679332, 104.78440902572288, 105.2332355777164, 107.0984946783314, 105.29388504300152, 105.71155078700542, 106.05158960870362, 107.2234596738798, 105.07452283624914, 105.20586598979445, 105.8590190744811, 106.67677999683147, 106.47676103433741, 107.10852314980781, 108.01269759939744, 107.71476257518577, 108.42747525422492, 110.54723239544502, 111.259340817459, 111.92133389532289, 112.13678246307137, 111.47984781247521, 111.8570212975741, 111.94464263092385, 110.17218578926756, 108.82808512263848, 111.15428544213488, 113.01797229471467, 112.86351439924522, 113.98556583823105, 118.16028718705624, 114.05421720730604, 113.69969868215333, 115.794615630372, 119.41223241369086, 121.84127624137268, 123.29931018039444, 120.8518188733136, 121.67663253712398, 119.98735528873357, 120.86826245547834, 121.78988295670136, 123.07882588465979, 123.51678137343272, 126.21768165946511, 122.42063306954287, 127.27563134269249, 129.35340602436193, 129.03972401475286, 119.36712136881367, 121.24715353037247, 119.59111949173679, 117.14747428345564, 118.51614727466735, 116.6880357029556, 117.81893724897674, 118.84199835408869, 120.27899618418687, 118.77250175697993, 119.34557907795738, 116.84628374276649, 117.03908011094204, 118.57619336306573, 117.43687377183561, 116.055033223787, 119.52024309079393, 121.97738008833548, 121.01680822013982, 121.6329854686607, 122.88985965183686, 122.65944116498966, 122.17084772434912, 121.2891814399384, 121.60251182532494, 121.00564616311564, 121.65000122893423, 122.03421248281563, 124.46371026299437, 126.76940049561631, 128.4966335773691, 131.32677193191066, 131.7426400430284, 131.9830703611069, 129.72286028117296, 130.4168775836772, 129.694150720401, 128.52906493309607, 131.3834812501519, 133.1900041173415, 135.0435650079745, 135.5015877659599, 134.09462961299002, 134.28347954969496, 132.4874380107178, 135.45626068414128, 135.5149583971044, 136.86897868975547, 138.33575791138068, 140.26784733020963, 140.9539908833999, 140.73551219753062, 139.51228603734708, 142.865231311778, 144.53556397453153, 144.4693185077099, 146.6435817512509, 145.51198211207043, 147.40727567908013, 151.17475996664461, 154.27258275629444, 155.37177490843303, 154.08089441190214, 155.53053882682744, 154.71270741016303, 153.98168986765, 156.8034043344747, 158.5204016119372, 161.9378372700212, 162.4735816149895, 159.88754377428424, 157.81300289381292, 158.69938592673316, 161.54274992458713, 160.58157056253583, 157.88246199733055, 157.7719442739324, 156.24155641447527, 156.0280262873755, 156.59882881687682, 154.62698856402432, 155.68231776097377, 154.1527389889722, 154.1296160781239, 153.74172321099394, 157.48149062810134, 160.57600191894352, 163.25628301764056, 166.16496579340486, 167.40012537246918, 172.26588901662893, 172.5443855372058, 170.3286280529322, 174.63368412697008, 179.3604358440067, 177.87772290769627, 181.79251512602315, 174.79653316892336, 175.6588627325567, 178.7855904891962, 179.0150319969907, 181.03939365048998, 180.05122029348104, 180.16075145249292, 181.57801603058584, 179.35671163447836, 173.6950181038833, 174.40572021962504, 172.4451092481561, 174.47421336697607, 172.80798462932145, 173.26880592166629, 175.13866511890427, 173.96085759597966, 175.04231426070135, 171.9032220916261, 169.54958047582159, 170.0031256035944, 168.5609324213906, 167.7139137359731, 169.30160545267367, 169.27903190528, 170.93091312495568, 169.90247879765386, 168.56166506914238, 168.30741789099645, 164.1810810290355, 164.2782215019777, 166.0976028051121, 166.93501155258787, 168.34561240020722, 170.80906986166357, 173.03243458769623, 176.0244537691085, 175.07685545965145, 173.7010431704977, 178.04791177583942, 180.3551159659347, 179.57958896728118, 181.64625073697965, 185.52742562772647, 182.1771095332658, 183.00297909648324, 182.83980144012222, 182.6569616386821, 186.44709359268475, 186.93651721336556, 191.17374493686853, 191.7647904316317, 193.47309510639346, 190.2114611780582, 187.569106963193, 183.8739955560181, 178.71020084748656, 177.41008413632107, 175.27081420511064, 181.7237013480955, 182.20526915666795, 181.37927193649105, 184.4219092232257, 186.20004379798632, 188.7571910661453, 187.02377086152123, 188.7677675248049, 190.3172362832377, 190.74386408790596, 190.99501017562167, 189.44317571794477, 189.9799313824789, 190.90608354796848, 188.43066799796316, 187.1933066114432, 187.9202406187843, 188.34306116017657, 188.23005532348049, 186.80264407061074, 187.15134233954254, 188.589288486518, 190.06971440113716, 192.31570485964392, 195.2709561909871, 197.38964606565932, 197.4011604616798, 196.4602149301458, 193.51494887465137, 194.9211575031405, 195.26064518579184, 199.97944411111516, 208.9168587675144, 213.07604523081102, 208.9832095286692, 212.18065263445786, 210.0853686896926, 212.2667551012539, 214.63529831025872, 212.81626415707927, 207.86473907769124, 206.6158184370661, 206.76905850240695, 206.79662771020725, 205.23875978145702, 205.7296224819343, 206.58854365579643, 208.2739618577883, 213.82619855764716, 218.65867064504997, 219.92871309037997, 218.00433685083914, 218.06247134066604, 219.41991022476165, 219.71064160580943, 218.94165436018912, 214.8748131304486, 216.36461183481964, 219.4856713605369, 219.42348375365142, 223.06774211299333, 225.07535179201022, 227.5680613131067, 226.7488162923795, 227.8787812269032, 225.81647825679974, 228.94968189261283, 227.8564471615756, 227.6380847330458, 228.28685327453496, 230.29577758335085, 232.285916927967, 235.92699867581294, 237.6748245243362, 239.15831155407562, 237.77916529078044, 234.98327860556972, 232.90955117187556, 234.07021710188206, 229.10792849932218, 232.57509515061196, 229.5981339326841, 232.60012953385396, 231.18126874369747, 235.09208520661167, 234.3672179438913, 236.50386574747975, 232.70797870223268, 233.0201952403248, 232.73474550115537, 230.96402197913412, 228.89304458205456, 229.41759114255507, 233.32724925827608, 234.4141653610709, 232.07783751297222, 230.83041913634, 233.6003841659761, 238.86028614944667, 237.92475002869463, 238.2380176162324, 240.70775173218735, 242.6775435005291, 241.1163179706757, 242.9688950137504, 244.1553931177342, 246.09642849302017, 245.58167679675563, 243.887163226858, 248.80148956587917, 248.12557885255853, 245.46649973252195, 248.69642975816907, 246.69235102836785, 246.81775297347394, 251.13706365050973, 250.90476186663304, 259.0173491669875, 270.86307593555773, 275.0117953819707, 281.78166907829024, 277.4422313744846, 279.15081311603245, 279.1391818321526, 281.39323072544727, 279.18663880784186, 281.42478502895136, 291.2793429180485, 290.58755447861813, 279.0633363805869, 275.6936465937913, 274.07394642005283, 274.4119709539709, 270.09912947714434, 271.6116846022163, 271.5822600030511, 271.30615137204796, 271.26997721853166, 270.3973921251454, 271.17703793910624, 273.0278212230407, 285.6030276222052, 281.0262391045594, 274.90923463338345, 294.3911357277359, 298.0342260323666, 295.42891017313366, 300.11145839937785, 301.491971108015, 291.39450250898904, 287.2348459856732, 289.48006503179454, 284.16328117071055, 279.6735013282133, 281.6125709374222, 292.6189289182265, 274.710650468431, 261.0643989064117, 265.7243984268911, 265.1907352600505, 263.24158335588913, 264.60824590947846, 270.0746112562252, 268.9222929148653, 278.02083049181823, 283.21286950125295, 276.55972717521934, 277.37096904159995, 276.6590502210598, 286.57958266356997, 289.04655523766553, 277.47987558557156, 280.8235080863777, 282.68162363154926, 275.7488568119855, 278.32710862317754, 278.90463737357067, 284.59196777068, 285.035456920456, 278.5033943660289, 275.70675611427004, 280.97964782495546, 277.2941314443181, 278.62976484410825, 269.9434819250932, 271.8083414793923, 265.9078353997772, 270.4814501686534, 265.82466120158307, 264.130028986423, 265.7698362497137, 258.062510998472, 260.08830170980997, 255.64946136062923, 256.8637963020922, 253.19706560987987, 254.40608159816702, 256.5473327849516, 259.21756294035504, 263.5356955096698, 262.83732591656917, 262.47811490448316, 258.5693783100306, 255.81561443102876, 252.91850259759735, 257.6291097084776, 256.1284201444257, 263.3853920485178, 262.45915341981384, 263.73864179273545, 267.7035127076862, 267.6700497685977, 275.75145468786127, 272.2631987860598, 272.9120927431666, 272.41175390647084, 277.8032365358697, 277.4305171935174, 274.138341722821, 274.86023935602446, 274.53956907677576, 275.09322387441387, 286.92452494454596, 293.05992770294347, 301.52203311536596, 298.35856445126393, 296.8394220939329, 302.5263706888825, 301.82047582394176, 298.38726791144444, 299.22772538272835, 299.58181152443126, 302.52270630756277, 304.29750618456717, 304.49529956358714, 305.9670268448111, 302.2240302164096, 297.89215244997445, 288.61529433576146, 294.79406676199955, 286.76092844273506, 286.53151969998083, 286.13037557240085, 271.7260955821269, 274.63356480485567, 287.6946794243666, 282.7079716476776, 282.6302269554745, 279.37055833792135, 277.78513041935366, 284.82235372331064, 281.46382346899, 277.80713929575535, 284.8101942655025, 288.4438976606732, 321.86973800125094, 319.1338452282403, 325.22132332596897, 316.9119185149905, 320.01765531643736, 324.9405935807219, 324.9324700658824, 328.1493015195347, 335.13888164190075, 335.38744297911853, 328.7719256663554, 326.1773672196384, 331.63811997584054, 330.97208008488906, 342.07067717040235, 337.99718552309815, 334.57496401967677, 327.6659910126704, 331.6798994025757, 333.2111549381509, 338.12601947348867, 344.2714598774193, 344.03620771316974, 342.9037551961139, 340.68059584992574, 352.2864481485466, 356.6518643851873, 355.3738618711404, 363.3756966609389, 383.7489607203956, 362.2558210120474, 360.41435392190283, 367.42140965273444, 372.58674230343576, 373.5616776124631, 378.84757535067945, 375.7915382428506, 374.47000466669664, 368.75309592878506, 364.3680070296986, 360.569470556414, 362.38133214596, 373.6664907978721, 368.26701000584285, 360.15592911046417, 360.35101357206565, 365.28782245800295, 368.6636907505523, 375.9232932609153, 370.73241911980415, 357.868004176347, 351.0267608298425, 355.8036500001353, 355.65243344888523, 355.2226867584678, 352.7953317322849, 350.32576441015897, 353.50789010355123, 353.74945382845533, 346.9309331059119, 347.14198275688466, 346.70805527843856, 344.89650568960866, 345.70126420288443, 347.1359244493264, 348.8195336829056, 357.2580595685846, 359.44031088244935, 358.8711970568855, 358.6379307787985, 358.4197593709081, 354.6503782348573, 352.94805641933, 350.46859632298424, 360.03054785932966, 377.06599328220693, 372.83656972422483, 362.50899674286387, 368.3604961319549, 362.9855025592295, 357.12631157208585, 370.11380510292406, 365.4935511025559, 367.4489416009546, 382.4592308653536, 385.6017708789639, 378.8762333252167, 371.6081242492613, 376.86947594175706, 375.6352284080478, 372.52058630583105, 362.1924530505019], \"mode\": \"line\", \"name\": \"All preds\"}], {\"title\": \"OLS all predictors\", \"autosize\": false, \"width\": 900, \"height\": 600, \"yaxis\": {\"type\": \"log\", \"autorange\": true}}, {\"showLink\": true, \"linkText\": \"Export to plot.ly\"})});</script>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "Ki8T0jBZfkZl",
"outputId": "097fc363-2568-4ae1-a9b1-419dc06547e8",
"colab": {
"resources": {
"http://localhost:8080/static/components/requirejs/require.js": {
"data": "LyoqIHZpbTogZXQ6dHM9NDpzdz00OnN0cz00CiAqIEBsaWNlbnNlIFJlcXVpcmVKUyAyLjEuMjIgQ29weXJpZ2h0IChjKSAyMDEwLTIwMTUsIFRoZSBEb2pvIEZvdW5kYXRpb24gQWxsIFJpZ2h0cyBSZXNlcnZlZC4KICogQXZhaWxhYmxlIHZpYSB0aGUgTUlUIG9yIG5ldyBCU0QgbGljZW5zZS4KICogc2VlOiBodHRwOi8vZ2l0aHViLmNvbS9qcmJ1cmtlL3JlcXVpcmVqcyBmb3IgZGV0YWlscwogKi8KLy9Ob3QgdXNpbmcgc3RyaWN0OiB1bmV2ZW4gc3RyaWN0IHN1cHBvcnQgaW4gYnJvd3NlcnMsICMzOTIsIGFuZCBjYXVzZXMKLy9wcm9ibGVtcyB3aXRoIHJlcXVpcmVqcy5leGVjKCkvdHJhbnNwaWxlciBwbHVnaW5zIHRoYXQgbWF5IG5vdCBiZSBzdHJpY3QuCi8qanNsaW50IHJlZ2V4cDogdHJ1ZSwgbm9tZW46IHRydWUsIHNsb3BweTogdHJ1ZSAqLwovKmdsb2JhbCB3aW5kb3csIG5hdmlnYXRvciwgZG9jdW1lbnQsIGltcG9ydFNjcmlwdHMsIHNldFRpbWVvdXQsIG9wZXJhICovCgp2YXIgcmVxdWlyZWpzLCByZXF1aXJlLCBkZWZpbmU7CihmdW5jdGlvbiAoZ2xvYmFsKSB7CiAgICB2YXIgcmVxLCBzLCBoZWFkLCBiYXNlRWxlbWVudCwgZGF0YU1haW4sIHNyYywKICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCwgY3VycmVudGx5QWRkaW5nU2NyaXB0LCBtYWluU2NyaXB0LCBzdWJQYXRoLAogICAgICAgIHZlcnNpb24gPSAnMi4xLjIyJywKICAgICAgICBjb21tZW50UmVnRXhwID0gLyhcL1wqKFtcc1xTXSo/KVwqXC98KFteOl18XilcL1wvKC4qKSQpL21nLAogICAgICAgIGNqc1JlcXVpcmVSZWdFeHAgPSAvW14uXVxzKnJlcXVpcmVccypcKFxzKlsiJ10oW14nIlxzXSspWyInXVxzKlwpL2csCiAgICAgICAganNTdWZmaXhSZWdFeHAgPSAvXC5qcyQvLAogICAgICAgIGN1cnJEaXJSZWdFeHAgPSAvXlwuXC8vLAogICAgICAgIG9wID0gT2JqZWN0LnByb3RvdHlwZSwKICAgICAgICBvc3RyaW5nID0gb3AudG9TdHJpbmcsCiAgICAgICAgaGFzT3duID0gb3AuaGFzT3duUHJvcGVydHksCiAgICAgICAgYXAgPSBBcnJheS5wcm90b3R5cGUsCiAgICAgICAgaXNCcm93c2VyID0gISEodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmRvY3VtZW50KSwKICAgICAgICBpc1dlYldvcmtlciA9ICFpc0Jyb3dzZXIgJiYgdHlwZW9mIGltcG9ydFNjcmlwdHMgIT09ICd1bmRlZmluZWQnLAogICAgICAgIC8vUFMzIGluZGljYXRlcyBsb2FkZWQgYW5kIGNvbXBsZXRlLCBidXQgbmVlZCB0byB3YWl0IGZvciBjb21wbGV0ZQogICAgICAgIC8vc3BlY2lmaWNhbGx5LiBTZXF1ZW5jZSBpcyAnbG9hZGluZycsICdsb2FkZWQnLCBleGVjdXRpb24sCiAgICAgICAgLy8gdGhlbiAnY29tcGxldGUnLiBUaGUgVUEgY2hlY2sgaXMgdW5mb3J0dW5hdGUsIGJ1dCBub3Qgc3VyZSBob3cKICAgICAgICAvL3RvIGZlYXR1cmUgdGVzdCB3L28gY2F1c2luZyBwZXJmIGlzc3Vlcy4KICAgICAgICByZWFkeVJlZ0V4cCA9IGlzQnJvd3NlciAmJiBuYXZpZ2F0b3IucGxhdGZvcm0gPT09ICdQTEFZU1RBVElPTiAzJyA/CiAgICAgICAgICAgICAgICAgICAgICAvXmNvbXBsZXRlJC8gOiAvXihjb21wbGV0ZXxsb2FkZWQpJC8sCiAgICAgICAgZGVmQ29udGV4dE5hbWUgPSAnXycsCiAgICAgICAgLy9PaCB0aGUgdHJhZ2VkeSwgZGV0ZWN0aW5nIG9wZXJhLiBTZWUgdGhlIHVzYWdlIG9mIGlzT3BlcmEgZm9yIHJlYXNvbi4KICAgICAgICBpc09wZXJhID0gdHlwZW9mIG9wZXJhICE9PSAndW5kZWZpbmVkJyAmJiBvcGVyYS50b1N0cmluZygpID09PSAnW29iamVjdCBPcGVyYV0nLAogICAgICAgIGNvbnRleHRzID0ge30sCiAgICAgICAgY2ZnID0ge30sCiAgICAgICAgZ2xvYmFsRGVmUXVldWUgPSBbXSwKICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwoKICAgIGZ1bmN0aW9uIGlzRnVuY3Rpb24oaXQpIHsKICAgICAgICByZXR1cm4gb3N0cmluZy5jYWxsKGl0KSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJzsKICAgIH0KCiAgICBmdW5jdGlvbiBpc0FycmF5KGl0KSB7CiAgICAgICAgcmV0dXJuIG9zdHJpbmcuY2FsbChpdCkgPT09ICdbb2JqZWN0IEFycmF5XSc7CiAgICB9CgogICAgLyoqCiAgICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIGl0ZXJhdGluZyBvdmVyIGFuIGFycmF5LiBJZiB0aGUgZnVuYyByZXR1cm5zCiAgICAgKiBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoKGFyeSwgZnVuYykgewogICAgICAgIGlmIChhcnkpIHsKICAgICAgICAgICAgdmFyIGk7CiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBhcnkubGVuZ3RoOyBpICs9IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhlbHBlciBmdW5jdGlvbiBmb3IgaXRlcmF0aW5nIG92ZXIgYW4gYXJyYXkgYmFja3dhcmRzLiBJZiB0aGUgZnVuYwogICAgICogcmV0dXJucyBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoUmV2ZXJzZShhcnksIGZ1bmMpIHsKICAgICAgICBpZiAoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpOwogICAgICAgICAgICBmb3IgKGkgPSBhcnkubGVuZ3RoIC0gMTsgaSA+IC0xOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBoYXNQcm9wKG9iaiwgcHJvcCkgewogICAgICAgIHJldHVybiBoYXNPd24uY2FsbChvYmosIHByb3ApOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldE93bihvYmosIHByb3ApIHsKICAgICAgICByZXR1cm4gaGFzUHJvcChvYmosIHByb3ApICYmIG9ialtwcm9wXTsKICAgIH0KCiAgICAvKioKICAgICAqIEN5Y2xlcyBvdmVyIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGFuZCBjYWxscyBhIGZ1bmN0aW9uIGZvciBlYWNoCiAgICAgKiBwcm9wZXJ0eSB2YWx1ZS4gSWYgdGhlIGZ1bmN0aW9uIHJldHVybnMgYSB0cnV0aHkgdmFsdWUsIHRoZW4gdGhlCiAgICAgKiBpdGVyYXRpb24gaXMgc3RvcHBlZC4KICAgICAqLwogICAgZnVuY3Rpb24gZWFjaFByb3Aob2JqLCBmdW5jKSB7CiAgICAgICAgdmFyIHByb3A7CiAgICAgICAgZm9yIChwcm9wIGluIG9iaikgewogICAgICAgICAgICBpZiAoaGFzUHJvcChvYmosIHByb3ApKSB7CiAgICAgICAgICAgICAgICBpZiAoZnVuYyhvYmpbcHJvcF0sIHByb3ApKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBTaW1wbGUgZnVuY3Rpb24gdG8gbWl4IGluIHByb3BlcnRpZXMgZnJvbSBzb3VyY2UgaW50byB0YXJnZXQsCiAgICAgKiBidXQgb25seSBpZiB0YXJnZXQgZG9lcyBub3QgYWxyZWFkeSBoYXZlIGEgcHJvcGVydHkgb2YgdGhlIHNhbWUgbmFtZS4KICAgICAqLwogICAgZnVuY3Rpb24gbWl4aW4odGFyZ2V0LCBzb3VyY2UsIGZvcmNlLCBkZWVwU3RyaW5nTWl4aW4pIHsKICAgICAgICBpZiAoc291cmNlKSB7CiAgICAgICAgICAgIGVhY2hQcm9wKHNvdXJjZSwgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICBpZiAoZm9yY2UgfHwgIWhhc1Byb3AodGFyZ2V0LCBwcm9wKSkgewogICAgICAgICAgICAgICAgICAgIGlmIChkZWVwU3RyaW5nTWl4aW4gJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAhaXNBcnJheSh2YWx1ZSkgJiYgIWlzRnVuY3Rpb24odmFsdWUpICYmCiAgICAgICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApKSB7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRhcmdldFtwcm9wXSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0ge307CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgbWl4aW4odGFyZ2V0W3Byb3BdLCB2YWx1ZSwgZm9yY2UsIGRlZXBTdHJpbmdNaXhpbik7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0gdmFsdWU7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRhcmdldDsKICAgIH0KCiAgICAvL1NpbWlsYXIgdG8gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQsIGJ1dCB0aGUgJ3RoaXMnIG9iamVjdCBpcyBzcGVjaWZpZWQKICAgIC8vZmlyc3QsIHNpbmNlIGl0IGlzIGVhc2llciB0byByZWFkL2ZpZ3VyZSBvdXQgd2hhdCAndGhpcycgd2lsbCBiZS4KICAgIGZ1bmN0aW9uIGJpbmQob2JqLCBmbikgewogICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHJldHVybiBmbi5hcHBseShvYmosIGFyZ3VtZW50cyk7CiAgICAgICAgfTsKICAgIH0KCiAgICBmdW5jdGlvbiBzY3JpcHRzKCkgewogICAgICAgIHJldHVybiBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7CiAgICB9CgogICAgZnVuY3Rpb24gZGVmYXVsdE9uRXJyb3IoZXJyKSB7CiAgICAgICAgdGhyb3cgZXJyOwogICAgfQoKICAgIC8vQWxsb3cgZ2V0dGluZyBhIGdsb2JhbCB0aGF0IGlzIGV4cHJlc3NlZCBpbgogICAgLy9kb3Qgbm90YXRpb24sIGxpa2UgJ2EuYi5jJy4KICAgIGZ1bmN0aW9uIGdldEdsb2JhbCh2YWx1ZSkgewogICAgICAgIGlmICghdmFsdWUpIHsKICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgIH0KICAgICAgICB2YXIgZyA9IGdsb2JhbDsKICAgICAgICBlYWNoKHZhbHVlLnNwbGl0KCcuJyksIGZ1bmN0aW9uIChwYXJ0KSB7CiAgICAgICAgICAgIGcgPSBnW3BhcnRdOwogICAgICAgIH0pOwogICAgICAgIHJldHVybiBnOwogICAgfQoKICAgIC8qKgogICAgICogQ29uc3RydWN0cyBhbiBlcnJvciB3aXRoIGEgcG9pbnRlciB0byBhbiBVUkwgd2l0aCBtb3JlIGluZm9ybWF0aW9uLgogICAgICogQHBhcmFtIHtTdHJpbmd9IGlkIHRoZSBlcnJvciBJRCB0aGF0IG1hcHMgdG8gYW4gSUQgb24gYSB3ZWIgcGFnZS4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGh1bWFuIHJlYWRhYmxlIGVycm9yLgogICAgICogQHBhcmFtIHtFcnJvcn0gW2Vycl0gdGhlIG9yaWdpbmFsIGVycm9yLCBpZiB0aGVyZSBpcyBvbmUuCiAgICAgKgogICAgICogQHJldHVybnMge0Vycm9yfQogICAgICovCiAgICBmdW5jdGlvbiBtYWtlRXJyb3IoaWQsIG1zZywgZXJyLCByZXF1aXJlTW9kdWxlcykgewogICAgICAgIHZhciBlID0gbmV3IEVycm9yKG1zZyArICdcbmh0dHA6Ly9yZXF1aXJlanMub3JnL2RvY3MvZXJyb3JzLmh0bWwjJyArIGlkKTsKICAgICAgICBlLnJlcXVpcmVUeXBlID0gaWQ7CiAgICAgICAgZS5yZXF1aXJlTW9kdWxlcyA9IHJlcXVpcmVNb2R1bGVzOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgZS5vcmlnaW5hbEVycm9yID0gZXJyOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZTsKICAgIH0KCiAgICBpZiAodHlwZW9mIGRlZmluZSAhPT0gJ3VuZGVmaW5lZCcpIHsKICAgICAgICAvL0lmIGEgZGVmaW5lIGlzIGFscmVhZHkgaW4gcGxheSB2aWEgYW5vdGhlciBBTUQgbG9hZGVyLAogICAgICAgIC8vZG8gbm90IG92ZXJ3cml0ZS4KICAgICAgICByZXR1cm47CiAgICB9CgogICAgaWYgKHR5cGVvZiByZXF1aXJlanMgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgaWYgKGlzRnVuY3Rpb24ocmVxdWlyZWpzKSkgewogICAgICAgICAgICAvL0RvIG5vdCBvdmVyd3JpdGUgYW4gZXhpc3RpbmcgcmVxdWlyZWpzIGluc3RhbmNlLgogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNmZyA9IHJlcXVpcmVqczsKICAgICAgICByZXF1aXJlanMgPSB1bmRlZmluZWQ7CiAgICB9CgogICAgLy9BbGxvdyBmb3IgYSByZXF1aXJlIGNvbmZpZyBvYmplY3QKICAgIGlmICh0eXBlb2YgcmVxdWlyZSAhPT0gJ3VuZGVmaW5lZCcgJiYgIWlzRnVuY3Rpb24ocmVxdWlyZSkpIHsKICAgICAgICAvL2Fzc3VtZSBpdCBpcyBhIGNvbmZpZyBvYmplY3QuCiAgICAgICAgY2ZnID0gcmVxdWlyZTsKICAgICAgICByZXF1aXJlID0gdW5kZWZpbmVkOwogICAgfQoKICAgIGZ1bmN0aW9uIG5ld0NvbnRleHQoY29udGV4dE5hbWUpIHsKICAgICAgICB2YXIgaW5DaGVja0xvYWRlZCwgTW9kdWxlLCBjb250ZXh0LCBoYW5kbGVycywKICAgICAgICAgICAgY2hlY2tMb2FkZWRUaW1lb3V0SWQsCiAgICAgICAgICAgIGNvbmZpZyA9IHsKICAgICAgICAgICAgICAgIC8vRGVmYXVsdHMuIERvIG5vdCBzZXQgYSBkZWZhdWx0IGZvciBtYXAKICAgICAgICAgICAgICAgIC8vY29uZmlnIHRvIHNwZWVkIHVwIG5vcm1hbGl6ZSgpLCB3aGljaAogICAgICAgICAgICAgICAgLy93aWxsIHJ1biBmYXN0ZXIgaWYgdGhlcmUgaXMgbm8gZGVmYXVsdC4KICAgICAgICAgICAgICAgIHdhaXRTZWNvbmRzOiA3LAogICAgICAgICAgICAgICAgYmFzZVVybDogJy4vJywKICAgICAgICAgICAgICAgIHBhdGhzOiB7fSwKICAgICAgICAgICAgICAgIGJ1bmRsZXM6IHt9LAogICAgICAgICAgICAgICAgcGtnczoge30sCiAgICAgICAgICAgICAgICBzaGltOiB7fSwKICAgICAgICAgICAgICAgIGNvbmZpZzoge30KICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgLy9yZWdpc3RyeSBvZiBqdXN0IGVuYWJsZWQgbW9kdWxlcywgdG8gc3BlZWQKICAgICAgICAgICAgLy9jeWNsZSBicmVha2luZyBjb2RlIHdoZW4gbG90cyBvZiBtb2R1bGVzCiAgICAgICAgICAgIC8vYXJlIHJlZ2lzdGVyZWQsIGJ1dCBub3QgYWN0aXZhdGVkLgogICAgICAgICAgICBlbmFibGVkUmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgdW5kZWZFdmVudHMgPSB7fSwKICAgICAgICAgICAgZGVmUXVldWUgPSBbXSwKICAgICAgICAgICAgZGVmaW5lZCA9IHt9LAogICAgICAgICAgICB1cmxGZXRjaGVkID0ge30sCiAgICAgICAgICAgIGJ1bmRsZXNNYXAgPSB7fSwKICAgICAgICAgICAgcmVxdWlyZUNvdW50ZXIgPSAxLAogICAgICAgICAgICB1bm5vcm1hbGl6ZWRDb3VudGVyID0gMTsKCiAgICAgICAgLyoqCiAgICAgICAgICogVHJpbXMgdGhlIC4gYW5kIC4uIGZyb20gYW4gYXJyYXkgb2YgcGF0aCBzZWdtZW50cy4KICAgICAgICAgKiBJdCB3aWxsIGtlZXAgYSBsZWFkaW5nIHBhdGggc2VnbWVudCBpZiBhIC4uIHdpbGwgYmVjb21lCiAgICAgICAgICogdGhlIGZpcnN0IHBhdGggc2VnbWVudCwgdG8gaGVscCB3aXRoIG1vZHVsZSBuYW1lIGxvb2t1cHMsCiAgICAgICAgICogd2hpY2ggYWN0IGxpa2UgcGF0aHMsIGJ1dCBjYW4gYmUgcmVtYXBwZWQuIEJ1dCB0aGUgZW5kIHJlc3VsdCwKICAgICAgICAgKiBhbGwgcGF0aHMgdGhhdCB1c2UgdGhpcyBmdW5jdGlvbiBzaG91bGQgbG9vayBub3JtYWxpemVkLgogICAgICAgICAqIE5PVEU6IHRoaXMgbWV0aG9kIE1PRElGSUVTIHRoZSBpbnB1dCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnkgdGhlIGFycmF5IG9mIHBhdGggc2VnbWVudHMuCiAgICAgICAgICovCiAgICAgICAgZnVuY3Rpb24gdHJpbURvdHMoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpLCBwYXJ0OwogICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYXJ5Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBwYXJ0ID0gYXJ5W2ldOwogICAgICAgICAgICAgICAgaWYgKHBhcnQgPT09ICcuJykgewogICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSwgMSk7CiAgICAgICAgICAgICAgICAgICAgaSAtPSAxOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0ID09PSAnLi4nKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gSWYgYXQgdGhlIHN0YXJ0LCBvciBwcmV2aW91cyB2YWx1ZSBpcyBzdGlsbCAuLiwKICAgICAgICAgICAgICAgICAgICAvLyBrZWVwIHRoZW0gc28gdGhhdCB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGggaXQgbWF5CiAgICAgICAgICAgICAgICAgICAgLy8gc3RpbGwgd29yayB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGgsIGV2ZW4gdGhvdWdoCiAgICAgICAgICAgICAgICAgICAgLy8gYXMgYW4gSUQgaXQgaXMgbGVzcyB0aGFuIGlkZWFsLiBJbiBsYXJnZXIgcG9pbnQKICAgICAgICAgICAgICAgICAgICAvLyByZWxlYXNlcywgbWF5IGJlIGJldHRlciB0byBqdXN0IGtpY2sgb3V0IGFuIGVycm9yLgogICAgICAgICAgICAgICAgICAgIGlmIChpID09PSAwIHx8IChpID09PSAxICYmIGFyeVsyXSA9PT0gJy4uJykgfHwgYXJ5W2kgLSAxXSA9PT0gJy4uJykgewogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSAtIDEsIDIpOwogICAgICAgICAgICAgICAgICAgICAgICBpIC09IDI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHaXZlbiBhIHJlbGF0aXZlIG1vZHVsZSBuYW1lLCBsaWtlIC4vc29tZXRoaW5nLCBub3JtYWxpemUgaXQgdG8KICAgICAgICAgKiBhIHJlYWwgbmFtZSB0aGF0IGNhbiBiZSBtYXBwZWQgdG8gYSBwYXRoLgogICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSByZWxhdGl2ZSBuYW1lCiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGJhc2VOYW1lIGEgcmVhbCBuYW1lIHRoYXQgdGhlIG5hbWUgYXJnIGlzIHJlbGF0aXZlCiAgICAgICAgICogdG8uCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBhcHBseU1hcCBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgdmFsdWUuIFNob3VsZAogICAgICAgICAqIG9ubHkgYmUgZG9uZSBpZiB0aGlzIG5vcm1hbGl6YXRpb24gaXMgZm9yIGEgZGVwZW5kZW5jeSBJRC4KICAgICAgICAgKiBAcmV0dXJucyB7U3RyaW5nfSBub3JtYWxpemVkIG5hbWUKICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBub3JtYWxpemUobmFtZSwgYmFzZU5hbWUsIGFwcGx5TWFwKSB7CiAgICAgICAgICAgIHZhciBwa2dNYWluLCBtYXBWYWx1ZSwgbmFtZVBhcnRzLCBpLCBqLCBuYW1lU2VnbWVudCwgbGFzdEluZGV4LAogICAgICAgICAgICAgICAgZm91bmRNYXAsIGZvdW5kSSwgZm91bmRTdGFyTWFwLCBzdGFySSwgbm9ybWFsaXplZEJhc2VQYXJ0cywKICAgICAgICAgICAgICAgIGJhc2VQYXJ0cyA9IChiYXNlTmFtZSAmJiBiYXNlTmFtZS5zcGxpdCgnLycpKSwKICAgICAgICAgICAgICAgIG1hcCA9IGNvbmZpZy5tYXAsCiAgICAgICAgICAgICAgICBzdGFyTWFwID0gbWFwICYmIG1hcFsnKiddOwoKICAgICAgICAgICAgLy9BZGp1c3QgYW55IHJlbGF0aXZlIHBhdGhzLgogICAgICAgICAgICBpZiAobmFtZSkgewogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3BsaXQoJy8nKTsKICAgICAgICAgICAgICAgIGxhc3RJbmRleCA9IG5hbWUubGVuZ3RoIC0gMTsKCiAgICAgICAgICAgICAgICAvLyBJZiB3YW50aW5nIG5vZGUgSUQgY29tcGF0aWJpbGl0eSwgc3RyaXAgLmpzIGZyb20gZW5kCiAgICAgICAgICAgICAgICAvLyBvZiBJRHMuIEhhdmUgdG8gZG8gdGhpcyBoZXJlLCBhbmQgbm90IGluIG5hbWVUb1VybAogICAgICAgICAgICAgICAgLy8gYmVjYXVzZSBub2RlIGFsbG93cyBlaXRoZXIgLmpzIG9yIG5vbiAuanMgdG8gbWFwCiAgICAgICAgICAgICAgICAvLyB0byBzYW1lIGZpbGUuCiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm5vZGVJZENvbXBhdCAmJiBqc1N1ZmZpeFJlZ0V4cC50ZXN0KG5hbWVbbGFzdEluZGV4XSkpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lW2xhc3RJbmRleF0gPSBuYW1lW2xhc3RJbmRleF0ucmVwbGFjZShqc1N1ZmZpeFJlZ0V4cCwgJycpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIFN0YXJ0cyB3aXRoIGEgJy4nIHNvIG5lZWQgdGhlIGJhc2VOYW1lCiAgICAgICAgICAgICAgICBpZiAobmFtZVswXS5jaGFyQXQoMCkgPT09ICcuJyAmJiBiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAvL0NvbnZlcnQgYmFzZU5hbWUgdG8gYXJyYXksIGFuZCBsb3Agb2ZmIHRoZSBsYXN0IHBhcnQsCiAgICAgICAgICAgICAgICAgICAgLy9zbyB0aGF0IC4gbWF0Y2hlcyB0aGF0ICdkaXJlY3RvcnknIGFuZCBub3QgbmFtZSBvZiB0aGUgYmFzZU5hbWUncwogICAgICAgICAgICAgICAgICAgIC8vbW9kdWxlLiBGb3IgaW5zdGFuY2UsIGJhc2VOYW1lIG9mICdvbmUvdHdvL3RocmVlJywgbWFwcyB0bwogICAgICAgICAgICAgICAgICAgIC8vJ29uZS90d28vdGhyZWUuanMnLCBidXQgd2Ugd2FudCB0aGUgZGlyZWN0b3J5LCAnb25lL3R3bycgZm9yCiAgICAgICAgICAgICAgICAgICAgLy90aGlzIG5vcm1hbGl6YXRpb24uCiAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZEJhc2VQYXJ0cyA9IGJhc2VQYXJ0cy5zbGljZSgwLCBiYXNlUGFydHMubGVuZ3RoIC0gMSk7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vcm1hbGl6ZWRCYXNlUGFydHMuY29uY2F0KG5hbWUpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHRyaW1Eb3RzKG5hbWUpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuam9pbignLycpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL0FwcGx5IG1hcCBjb25maWcgaWYgYXZhaWxhYmxlLgogICAgICAgICAgICBpZiAoYXBwbHlNYXAgJiYgbWFwICYmIChiYXNlUGFydHMgfHwgc3Rhck1hcCkpIHsKICAgICAgICAgICAgICAgIG5hbWVQYXJ0cyA9IG5hbWUuc3BsaXQoJy8nKTsKCiAgICAgICAgICAgICAgICBvdXRlckxvb3A6IGZvciAoaSA9IG5hbWVQYXJ0cy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lU2VnbWVudCA9IG5hbWVQYXJ0cy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9GaW5kIHRoZSBsb25nZXN0IGJhc2VOYW1lIHNlZ21lbnQgbWF0Y2ggaW4gdGhlIGNvbmZpZy4KICAgICAgICAgICAgICAgICAgICAgICAgLy9TbywgZG8gam9pbnMgb24gdGhlIGJpZ2dlc3QgdG8gc21hbGxlc3QgbGVuZ3RocyBvZiBiYXNlUGFydHMuCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaiA9IGJhc2VQYXJ0cy5sZW5ndGg7IGogPiAwOyBqIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcFZhbHVlID0gZ2V0T3duKG1hcCwgYmFzZVBhcnRzLnNsaWNlKDAsIGopLmpvaW4oJy8nKSk7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iYXNlTmFtZSBzZWdtZW50IGhhcyBjb25maWcsIGZpbmQgaWYgaXQgaGFzIG9uZSBmb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hcFZhbHVlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwVmFsdWUgPSBnZXRPd24obWFwVmFsdWUsIG5hbWVTZWdtZW50KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWFwVmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXRjaCwgdXBkYXRlIG5hbWUgdG8gdGhlIG5ldyB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRNYXAgPSBtYXBWYWx1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRJID0gaTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsgb3V0ZXJMb29wOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9DaGVjayBmb3IgYSBzdGFyIG1hcCBtYXRjaCwgYnV0IGp1c3QgaG9sZCBvbiB0byBpdCwKICAgICAgICAgICAgICAgICAgICAvL2lmIHRoZXJlIGlzIGEgc2hvcnRlciBzZWdtZW50IG1hdGNoIGxhdGVyIGluIGEgbWF0Y2hpbmcKICAgICAgICAgICAgICAgICAgICAvL2NvbmZpZywgdGhlbiBmYXZvciBvdmVyIHRoaXMgc3RhciBtYXAuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFmb3VuZFN0YXJNYXAgJiYgc3Rhck1hcCAmJiBnZXRPd24oc3Rhck1hcCwgbmFtZVNlZ21lbnQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvdW5kU3Rhck1hcCA9IGdldE93bihzdGFyTWFwLCBuYW1lU2VnbWVudCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJJID0gaTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFmb3VuZE1hcCAmJiBmb3VuZFN0YXJNYXApIHsKICAgICAgICAgICAgICAgICAgICBmb3VuZE1hcCA9IGZvdW5kU3Rhck1hcDsKICAgICAgICAgICAgICAgICAgICBmb3VuZEkgPSBzdGFySTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBpZiAoZm91bmRNYXApIHsKICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMuc3BsaWNlKDAsIGZvdW5kSSwgZm91bmRNYXApOwogICAgICAgICAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHMuam9pbignLycpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBJZiB0aGUgbmFtZSBwb2ludHMgdG8gYSBwYWNrYWdlJ3MgbmFtZSwgdXNlCiAgICAgICAgICAgIC8vIHRoZSBwYWNrYWdlIG1haW4gaW5zdGVhZC4KICAgICAgICAgICAgcGtnTWFpbiA9IGdldE93bihjb25maWcucGtncywgbmFtZSk7CgogICAgICAgICAgICByZXR1cm4gcGtnTWFpbiA/IHBrZ01haW4gOiBuYW1lOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gcmVtb3ZlU2NyaXB0KG5hbWUpIHsKICAgICAgICAgICAgaWYgKGlzQnJvd3NlcikgewogICAgICAgICAgICAgICAgZWFjaChzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHROb2RlKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKHNjcmlwdE5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKSA9PT0gbmFtZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NyaXB0Tm9kZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcmVxdWlyZWNvbnRleHQnKSA9PT0gY29udGV4dC5jb250ZXh0TmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzY3JpcHROb2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoc2NyaXB0Tm9kZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBoYXNQYXRoRmFsbGJhY2soaWQpIHsKICAgICAgICAgICAgdmFyIHBhdGhDb25maWcgPSBnZXRPd24oY29uZmlnLnBhdGhzLCBpZCk7CiAgICAgICAgICAgIGlmIChwYXRoQ29uZmlnICYmIGlzQXJyYXkocGF0aENvbmZpZykgJiYgcGF0aENvbmZpZy5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAvL1BvcCBvZmYgdGhlIGZpcnN0IGFycmF5IHZhbHVlLCBzaW5jZSBpdCBmYWlsZWQsIGFuZAogICAgICAgICAgICAgICAgLy9yZXRyeQogICAgICAgICAgICAgICAgcGF0aENvbmZpZy5zaGlmdCgpOwogICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlLnVuZGVmKGlkKTsKCiAgICAgICAgICAgICAgICAvL0N1c3RvbSByZXF1aXJlIHRoYXQgZG9lcyBub3QgZG8gbWFwIHRyYW5zbGF0aW9uLCBzaW5jZQogICAgICAgICAgICAgICAgLy9JRCBpcyAiYWJzb2x1dGUiLCBhbHJlYWR5IG1hcHBlZC9yZXNvbHZlZC4KICAgICAgICAgICAgICAgIGNvbnRleHQubWFrZVJlcXVpcmUobnVsbCwgewogICAgICAgICAgICAgICAgICAgIHNraXBNYXA6IHRydWUKICAgICAgICAgICAgICAgIH0pKFtpZF0pOwoKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvL1R1cm5zIGEgcGx1Z2luIXJlc291cmNlIHRvIFtwbHVnaW4sIHJlc291cmNlXQogICAgICAgIC8vd2l0aCB0aGUgcGx1Z2luIGJlaW5nIHVuZGVmaW5lZCBpZiB0aGUgbmFtZQogICAgICAgIC8vZGlkIG5vdCBoYXZlIGEgcGx1Z2luIHByZWZpeC4KICAgICAgICBmdW5jdGlvbiBzcGxpdFByZWZpeChuYW1lKSB7CiAgICAgICAgICAgIHZhciBwcmVmaXgsCiAgICAgICAgICAgICAgICBpbmRleCA9IG5hbWUgPyBuYW1lLmluZGV4T2YoJyEnKSA6IC0xOwogICAgICAgICAgICBpZiAoaW5kZXggPiAtMSkgewogICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZS5zdWJzdHJpbmcoMCwgaW5kZXgpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyaW5nKGluZGV4ICsgMSwgbmFtZS5sZW5ndGgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBbcHJlZml4LCBuYW1lXTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBtb2R1bGUgbWFwcGluZyB0aGF0IGluY2x1ZGVzIHBsdWdpbiBwcmVmaXgsIG1vZHVsZQogICAgICAgICAqIG5hbWUsIGFuZCBwYXRoLiBJZiBwYXJlbnRNb2R1bGVNYXAgaXMgcHJvdmlkZWQgaXQgd2lsbAogICAgICAgICAqIGFsc28gbm9ybWFsaXplIHRoZSBuYW1lIHZpYSByZXF1aXJlLm5vcm1hbGl6ZSgpCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSB0aGUgbW9kdWxlIG5hbWUKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gW3BhcmVudE1vZHVsZU1hcF0gcGFyZW50IG1vZHVsZSBtYXAKICAgICAgICAgKiBmb3IgdGhlIG1vZHVsZSBuYW1lLCB1c2VkIHRvIHJlc29sdmUgcmVsYXRpdmUgbmFtZXMuCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBpc05vcm1hbGl6ZWQ6IGlzIHRoZSBJRCBhbHJlYWR5IG5vcm1hbGl6ZWQuCiAgICAgICAgICogVGhpcyBpcyB0cnVlIGlmIHRoaXMgY2FsbCBpcyBkb25lIGZvciBhIGRlZmluZSgpIG1vZHVsZSBJRC4KICAgICAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGx5TWFwOiBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgSUQuCiAgICAgICAgICogU2hvdWxkIG9ubHkgYmUgdHJ1ZSBpZiB0aGlzIG1hcCBpcyBmb3IgYSBkZXBlbmRlbmN5LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge09iamVjdH0KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBtYWtlTW9kdWxlTWFwKG5hbWUsIHBhcmVudE1vZHVsZU1hcCwgaXNOb3JtYWxpemVkLCBhcHBseU1hcCkgewogICAgICAgICAgICB2YXIgdXJsLCBwbHVnaW5Nb2R1bGUsIHN1ZmZpeCwgbmFtZVBhcnRzLAogICAgICAgICAgICAgICAgcHJlZml4ID0gbnVsbCwKICAgICAgICAgICAgICAgIHBhcmVudE5hbWUgPSBwYXJlbnRNb2R1bGVNYXAgPyBwYXJlbnRNb2R1bGVNYXAubmFtZSA6IG51bGwsCiAgICAgICAgICAgICAgICBvcmlnaW5hbE5hbWUgPSBuYW1lLAogICAgICAgICAgICAgICAgaXNEZWZpbmUgPSB0cnVlLAogICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUgPSAnJzsKCiAgICAgICAgICAgIC8vSWYgbm8gbmFtZSwgdGhlbiBpdCBtZWFucyBpdCBpcyBhIHJlcXVpcmUgY2FsbCwgZ2VuZXJhdGUgYW4KICAgICAgICAgICAgLy9pbnRlcm5hbCBuYW1lLgogICAgICAgICAgICBpZiAoIW5hbWUpIHsKICAgICAgICAgICAgICAgIGlzRGVmaW5lID0gZmFsc2U7CiAgICAgICAgICAgICAgICBuYW1lID0gJ19AcicgKyAocmVxdWlyZUNvdW50ZXIgKz0gMSk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIG5hbWVQYXJ0cyA9IHNwbGl0UHJlZml4KG5hbWUpOwogICAgICAgICAgICBwcmVmaXggPSBuYW1lUGFydHNbMF07CiAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHNbMV07CgogICAgICAgICAgICBpZiAocHJlZml4KSB7CiAgICAgICAgICAgICAgICBwcmVmaXggPSBub3JtYWxpemUocHJlZml4LCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICBwbHVnaW5Nb2R1bGUgPSBnZXRPd24oZGVmaW5lZCwgcHJlZml4KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9BY2NvdW50IGZvciByZWxhdGl2ZSBwYXRocyBpZiB0aGVyZSBpcyBhIGJhc2UgbmFtZS4KICAgICAgICAgICAgaWYgKG5hbWUpIHsKICAgICAgICAgICAgICAgIGlmIChwcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICBpZiAocGx1Z2luTW9kdWxlICYmIHBsdWdpbk1vZHVsZS5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9QbHVnaW4gaXMgbG9hZGVkLCB1c2UgaXRzIG5vcm1hbGl6ZSBtZXRob2QuCiAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gcGx1Z2luTW9kdWxlLm5vcm1hbGl6ZShuYW1lLCBmdW5jdGlvbiAobmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIG5lc3RlZCBwbHVnaW4gcmVmZXJlbmNlcywgdGhlbiBkbyBub3QgdHJ5IHRvCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSwgYXMgaXQgd2lsbCBub3Qgbm9ybWFsaXplIGNvcnJlY3RseS4gVGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvLyBwbGFjZXMgYSByZXN0cmljdGlvbiBvbiByZXNvdXJjZUlkcywgYW5kIHRoZSBsb25nZXIKICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGVybSBzb2x1dGlvbiBpcyBub3QgdG8gbm9ybWFsaXplIHVudGlsIHBsdWdpbnMgYXJlCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvYWRlZCBhbmQgYWxsIG5vcm1hbGl6YXRpb25zIHRvIGFsbG93IGZvciBhc3luYwogICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2FkaW5nIG9mIGEgbG9hZGVyIHBsdWdpbi4gQnV0IGZvciBub3csIGZpeGVzIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAvLyBjb21tb24gdXNlcy4gRGV0YWlscyBpbiAjMTEzMQogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5hbWUuaW5kZXhPZignIScpID09PSAtMSA/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplKG5hbWUsIHBhcmVudE5hbWUsIGFwcGx5TWFwKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIC8vQSByZWd1bGFyIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CgogICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplZCBuYW1lIG1heSBiZSBhIHBsdWdpbiBJRCBkdWUgdG8gbWFwIGNvbmZpZwogICAgICAgICAgICAgICAgICAgIC8vYXBwbGljYXRpb24gaW4gbm9ybWFsaXplLiBUaGUgbWFwIGNvbmZpZyB2YWx1ZXMgbXVzdAogICAgICAgICAgICAgICAgICAgIC8vYWxyZWFkeSBiZSBub3JtYWxpemVkLCBzbyBkbyBub3QgbmVlZCB0byByZWRvIHRoYXQgcGFydC4KICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMgPSBzcGxpdFByZWZpeChub3JtYWxpemVkTmFtZSk7CiAgICAgICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZVBhcnRzWzBdOwogICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gbmFtZVBhcnRzWzFdOwogICAgICAgICAgICAgICAgICAgIGlzTm9ybWFsaXplZCA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIHVybCA9IGNvbnRleHQubmFtZVRvVXJsKG5vcm1hbGl6ZWROYW1lKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiB0aGUgaWQgaXMgYSBwbHVnaW4gaWQgdGhhdCBjYW5ub3QgYmUgZGV0ZXJtaW5lZCBpZiBpdCBuZWVkcwogICAgICAgICAgICAvL25vcm1hbGl6YXRpb24sIHN0YW1wIGl0IHdpdGggYSB1bmlxdWUgSUQgc28gdHdvIG1hdGNoaW5nIHJlbGF0aXZlCiAgICAgICAgICAgIC8vaWRzIHRoYXQgbWF5IGNvbmZsaWN0IGNhbiBiZSBzZXBhcmF0ZS4KICAgICAgICAgICAgc3VmZml4ID0gcHJlZml4ICYmICFwbHVnaW5Nb2R1bGUgJiYgIWlzTm9ybWFsaXplZCA/CiAgICAgICAgICAgICAgICAgICAgICdfdW5ub3JtYWxpemVkJyArICh1bm5vcm1hbGl6ZWRDb3VudGVyICs9IDEpIDoKICAgICAgICAgICAgICAgICAgICAgJyc7CgogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcHJlZml4OiBwcmVmaXgsCiAgICAgICAgICAgICAgICBuYW1lOiBub3JtYWxpemVkTmFtZSwKICAgICAgICAgICAgICAgIHBhcmVudE1hcDogcGFyZW50TW9kdWxlTWFwLAogICAgICAgICAgICAgICAgdW5ub3JtYWxpemVkOiAhIXN1ZmZpeCwKICAgICAgICAgICAgICAgIHVybDogdXJsLAogICAgICAgICAgICAgICAgb3JpZ2luYWxOYW1lOiBvcmlnaW5hbE5hbWUsCiAgICAgICAgICAgICAgICBpc0RlZmluZTogaXNEZWZpbmUsCiAgICAgICAgICAgICAgICBpZDogKHByZWZpeCA/CiAgICAgICAgICAgICAgICAgICAgICAgIHByZWZpeCArICchJyArIG5vcm1hbGl6ZWROYW1lIDoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUpICsgc3VmZml4CiAgICAgICAgICAgIH07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBnZXRNb2R1bGUoZGVwTWFwKSB7CiAgICAgICAgICAgIHZhciBpZCA9IGRlcE1hcC5pZCwKICAgICAgICAgICAgICAgIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwoKICAgICAgICAgICAgaWYgKCFtb2QpIHsKICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXSA9IG5ldyBjb250ZXh0Lk1vZHVsZShkZXBNYXApOwogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gbW9kOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gb24oZGVwTWFwLCBuYW1lLCBmbikgewogICAgICAgICAgICB2YXIgaWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIGlkKTsKCiAgICAgICAgICAgIGlmIChoYXNQcm9wKGRlZmluZWQsIGlkKSAmJgogICAgICAgICAgICAgICAgICAgICghbW9kIHx8IG1vZC5kZWZpbmVFbWl0Q29tcGxldGUpKSB7CiAgICAgICAgICAgICAgICBpZiAobmFtZSA9PT0gJ2RlZmluZWQnKSB7CiAgICAgICAgICAgICAgICAgICAgZm4oZGVmaW5lZFtpZF0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgbW9kID0gZ2V0TW9kdWxlKGRlcE1hcCk7CiAgICAgICAgICAgICAgICBpZiAobW9kLmVycm9yICYmIG5hbWUgPT09ICdlcnJvcicpIHsKICAgICAgICAgICAgICAgICAgICBmbihtb2QuZXJyb3IpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBtb2Qub24obmFtZSwgZm4pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBvbkVycm9yKGVyciwgZXJyYmFjaykgewogICAgICAgICAgICB2YXIgaWRzID0gZXJyLnJlcXVpcmVNb2R1bGVzLAogICAgICAgICAgICAgICAgbm90aWZpZWQgPSBmYWxzZTsKCiAgICAgICAgICAgIGlmIChlcnJiYWNrKSB7CiAgICAgICAgICAgICAgICBlcnJiYWNrKGVycik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBlYWNoKGlkcywgZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwogICAgICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9TZXQgZXJyb3Igb24gbW9kdWxlLCBzbyBpdCBza2lwcyB0aW1lb3V0IGNoZWNrcy4KICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVycm9yID0gZXJyOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90aWZpZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIGlmICghbm90aWZpZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdG8gdHJhbnNmZXIgZ2xvYmFsUXVldWUgaXRlbXMgdG8gdGhpcyBjb250ZXh0J3MKICAgICAgICAgKiBkZWZRdWV1ZS4KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiB0YWtlR2xvYmFsUXVldWUoKSB7CiAgICAgICAgICAgIC8vUHVzaCBhbGwgdGhlIGdsb2JhbERlZlF1ZXVlIGl0ZW1zIGludG8gdGhlIGNvbnRleHQncyBkZWZRdWV1ZQogICAgICAgICAgICBpZiAoZ2xvYmFsRGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBlYWNoKGdsb2JhbERlZlF1ZXVlLCBmdW5jdGlvbihxdWV1ZUl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQgPSBxdWV1ZUl0ZW1bMF07CiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcFtpZF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBkZWZRdWV1ZS5wdXNoKHF1ZXVlSXRlbSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGdsb2JhbERlZlF1ZXVlID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGhhbmRsZXJzID0gewogICAgICAgICAgICAncmVxdWlyZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QucmVxdWlyZSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBtb2QucmVxdWlyZTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChtb2QucmVxdWlyZSA9IGNvbnRleHQubWFrZVJlcXVpcmUobW9kLm1hcCkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAnZXhwb3J0cyc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIG1vZC51c2luZ0V4cG9ydHMgPSB0cnVlOwogICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChkZWZpbmVkW21vZC5tYXAuaWRdID0gbW9kLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLmV4cG9ydHMgPSBkZWZpbmVkW21vZC5tYXAuaWRdID0ge30pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgJ21vZHVsZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QubW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vZC5tb2R1bGU7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLm1vZHVsZSA9IHsKICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IG1vZC5tYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIHVyaTogbW9kLm1hcC51cmwsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZzogZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdldE93bihjb25maWcuY29uZmlnLCBtb2QubWFwLmlkKSB8fCB7fTsKICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0czogbW9kLmV4cG9ydHMgfHwgKG1vZC5leHBvcnRzID0ge30pCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjbGVhblJlZ2lzdHJ5KGlkKSB7CiAgICAgICAgICAgIC8vQ2xlYW4gdXAgbWFjaGluZXJ5IHVzZWQgZm9yIHdhaXRpbmcgbW9kdWxlcy4KICAgICAgICAgICAgZGVsZXRlIHJlZ2lzdHJ5W2lkXTsKICAgICAgICAgICAgZGVsZXRlIGVuYWJsZWRSZWdpc3RyeVtpZF07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBicmVha0N5Y2xlKG1vZCwgdHJhY2VkLCBwcm9jZXNzZWQpIHsKICAgICAgICAgICAgdmFyIGlkID0gbW9kLm1hcC5pZDsKCiAgICAgICAgICAgIGlmIChtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgIG1vZC5lbWl0KCdlcnJvcicsIG1vZC5lcnJvcik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB0cmFjZWRbaWRdID0gdHJ1ZTsKICAgICAgICAgICAgICAgIGVhY2gobW9kLmRlcE1hcHMsIGZ1bmN0aW9uIChkZXBNYXAsIGkpIHsKICAgICAgICAgICAgICAgICAgICB2YXIgZGVwSWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlcCA9IGdldE93bihyZWdpc3RyeSwgZGVwSWQpOwoKICAgICAgICAgICAgICAgICAgICAvL09ubHkgZm9yY2UgdGhpbmdzIHRoYXQgaGF2ZSBub3QgY29tcGxldGVkCiAgICAgICAgICAgICAgICAgICAgLy9iZWluZyBkZWZpbmVkLCBzbyBzdGlsbCBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAgICAgLy9hbmQgb25seSBpZiBpdCBoYXMgbm90IGJlZW4gbWF0Y2hlZCB1cAogICAgICAgICAgICAgICAgICAgIC8vaW4gdGhlIG1vZHVsZSBhbHJlYWR5LgogICAgICAgICAgICAgICAgICAgIGlmIChkZXAgJiYgIW1vZC5kZXBNYXRjaGVkW2ldICYmICFwcm9jZXNzZWRbZGVwSWRdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChnZXRPd24odHJhY2VkLCBkZXBJZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZC5kZWZpbmVEZXAoaSwgZGVmaW5lZFtkZXBJZF0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmNoZWNrKCk7IC8vcGFzcyBmYWxzZT8KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrQ3ljbGUoZGVwLCB0cmFjZWQsIHByb2Nlc3NlZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHByb2Nlc3NlZFtpZF0gPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBjaGVja0xvYWRlZCgpIHsKICAgICAgICAgICAgdmFyIGVyciwgdXNpbmdQYXRoRmFsbGJhY2ssCiAgICAgICAgICAgICAgICB3YWl0SW50ZXJ2YWwgPSBjb25maWcud2FpdFNlY29uZHMgKiAxMDAwLAogICAgICAgICAgICAgICAgLy9JdCBpcyBwb3NzaWJsZSB0byBkaXNhYmxlIHRoZSB3YWl0IGludGVydmFsIGJ5IHVzaW5nIHdhaXRTZWNvbmRzIG9mIDAuCiAgICAgICAgICAgICAgICBleHBpcmVkID0gd2FpdEludGVydmFsICYmIChjb250ZXh0LnN0YXJ0VGltZSArIHdhaXRJbnRlcnZhbCkgPCBuZXcgRGF0ZSgpLmdldFRpbWUoKSwKICAgICAgICAgICAgICAgIG5vTG9hZHMgPSBbXSwKICAgICAgICAgICAgICAgIHJlcUNhbGxzID0gW10sCiAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSBmYWxzZSwKICAgICAgICAgICAgICAgIG5lZWRDeWNsZUNoZWNrID0gdHJ1ZTsKCiAgICAgICAgICAgIC8vRG8gbm90IGJvdGhlciBpZiB0aGlzIGNhbGwgd2FzIGEgcmVzdWx0IG9mIGEgY3ljbGUgYnJlYWsuCiAgICAgICAgICAgIGlmIChpbkNoZWNrTG9hZGVkKSB7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGluQ2hlY2tMb2FkZWQgPSB0cnVlOwoKICAgICAgICAgICAgLy9GaWd1cmUgb3V0IHRoZSBzdGF0ZSBvZiBhbGwgdGhlIG1vZHVsZXMuCiAgICAgICAgICAgIGVhY2hQcm9wKGVuYWJsZWRSZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgdmFyIG1hcCA9IG1vZC5tYXAsCiAgICAgICAgICAgICAgICAgICAgbW9kSWQgPSBtYXAuaWQ7CgogICAgICAgICAgICAgICAgLy9Ta2lwIHRoaW5ncyB0aGF0IGFyZSBub3QgZW5hYmxlZCBvciBpbiBlcnJvciBzdGF0ZS4KICAgICAgICAgICAgICAgIGlmICghbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICByZXFDYWxscy5wdXNoKG1vZCk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIHRoZSBtb2R1bGUgc2hvdWxkIGJlIGV4ZWN1dGVkLCBhbmQgaXQgaGFzIG5vdAogICAgICAgICAgICAgICAgICAgIC8vYmVlbiBpbml0ZWQgYW5kIHRpbWUgaXMgdXAsIHJlbWVtYmVyIGl0LgogICAgICAgICAgICAgICAgICAgIGlmICghbW9kLmluaXRlZCAmJiBleHBpcmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoYXNQYXRoRmFsbGJhY2sobW9kSWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2luZ1BhdGhGYWxsYmFjayA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9Mb2Fkcy5wdXNoKG1vZElkKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChtb2RJZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFtb2QuaW5pdGVkICYmIG1vZC5mZXRjaGVkICYmIG1hcC5pc0RlZmluZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW1hcC5wcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vTm8gcmVhc29uIHRvIGtlZXAgbG9va2luZyBmb3IgdW5maW5pc2hlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9sb2FkaW5nLiBJZiB0aGUgb25seSBzdGlsbExvYWRpbmcgaXMgYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9wbHVnaW4gcmVzb3VyY2UgdGhvdWdoLCBrZWVwIGdvaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iZWNhdXNlIGl0IG1heSBiZSB0aGF0IGEgcGx1Z2luIHJlc291cmNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL2lzIHdhaXRpbmcgb24gYSBub24tcGx1Z2luIGN5Y2xlLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChuZWVkQ3ljbGVDaGVjayA9IGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CgogICAgICAgICAgICBpZiAoZXhwaXJlZCAmJiBub0xvYWRzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgLy9JZiB3YWl0IHRpbWUgZXhwaXJlZCwgdGhyb3cgZXJyb3Igb2YgdW5sb2FkZWQgbW9kdWxlcy4KICAgICAgICAgICAgICAgIGVyciA9IG1ha2VFcnJvcigndGltZW91dCcsICdMb2FkIHRpbWVvdXQgZm9yIG1vZHVsZXM6ICcgKyBub0xvYWRzLCBudWxsLCBub0xvYWRzKTsKICAgICAgICAgICAgICAgIGVyci5jb250ZXh0TmFtZSA9IGNvbnRleHQuY29udGV4dE5hbWU7CiAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihlcnIpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL05vdCBleHBpcmVkLCBjaGVjayBmb3IgYSBjeWNsZS4KICAgICAgICAgICAgaWYgKG5lZWRDeWNsZUNoZWNrKSB7CiAgICAgICAgICAgICAgICBlYWNoKHJlcUNhbGxzLCBmdW5jdGlvbiAobW9kKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWtDeWNsZShtb2QsIHt9LCB7fSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiBzdGlsbCB3YWl0aW5nIG9uIGxvYWRzLCBhbmQgdGhlIHdhaXRpbmcgbG9hZCBpcyBzb21ldGhpbmcKICAgICAgICAgICAgLy9vdGhlciB0aGFuIGEgcGx1Z2luIHJlc291cmNlLCBvciB0aGVyZSBhcmUgc3RpbGwgb3V0c3RhbmRpbmcKICAgICAgICAgICAgLy9zY3JpcHRzLCB0aGVuIGp1c3QgdHJ5IGJhY2sgbGF0ZXIuCiAgICAgICAgICAgIGlmICgoIWV4cGlyZWQgfHwgdXNpbmdQYXRoRmFsbGJhY2spICYmIHN0aWxsTG9hZGluZykgewogICAgICAgICAgICAgICAgLy9Tb21ldGhpbmcgaXMgc3RpbGwgd2FpdGluZyB0byBsb2FkLiBXYWl0IGZvciBpdCwgYnV0IG9ubHkKICAgICAgICAgICAgICAgIC8vaWYgYSB0aW1lb3V0IGlzIG5vdCBhbHJlYWR5IGluIGVmZmVjdC4KICAgICAgICAgICAgICAgIGlmICgoaXNCcm93c2VyIHx8IGlzV2ViV29ya2VyKSAmJiAhY2hlY2tMb2FkZWRUaW1lb3V0SWQpIHsKICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrTG9hZGVkKCk7CiAgICAgICAgICAgICAgICAgICAgfSwgNTApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBpbkNoZWNrTG9hZGVkID0gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICBNb2R1bGUgPSBmdW5jdGlvbiAobWFwKSB7CiAgICAgICAgICAgIHRoaXMuZXZlbnRzID0gZ2V0T3duKHVuZGVmRXZlbnRzLCBtYXAuaWQpIHx8IHt9OwogICAgICAgICAgICB0aGlzLm1hcCA9IG1hcDsKICAgICAgICAgICAgdGhpcy5zaGltID0gZ2V0T3duKGNvbmZpZy5zaGltLCBtYXAuaWQpOwogICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHMgPSBbXTsKICAgICAgICAgICAgdGhpcy5kZXBNYXBzID0gW107CiAgICAgICAgICAgIHRoaXMuZGVwTWF0Y2hlZCA9IFtdOwogICAgICAgICAgICB0aGlzLnBsdWdpbk1hcHMgPSB7fTsKICAgICAgICAgICAgdGhpcy5kZXBDb3VudCA9IDA7CgogICAgICAgICAgICAvKiB0aGlzLmV4cG9ydHMgdGhpcy5mYWN0b3J5CiAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcyA9IFtdLAogICAgICAgICAgICAgICB0aGlzLmVuYWJsZWQsIHRoaXMuZmV0Y2hlZAogICAgICAgICAgICAqLwogICAgICAgIH07CgogICAgICAgIE1vZHVsZS5wcm90b3R5cGUgPSB7CiAgICAgICAgICAgIGluaXQ6IGZ1bmN0aW9uIChkZXBNYXBzLCBmYWN0b3J5LCBlcnJiYWNrLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIG5vdCBkbyBtb3JlIGluaXRzIGlmIGFscmVhZHkgZG9uZS4gQ2FuIGhhcHBlbiBpZiB0aGVyZQogICAgICAgICAgICAgICAgLy9hcmUgbXVsdGlwbGUgZGVmaW5lIGNhbGxzIGZvciB0aGUgc2FtZSBtb2R1bGUuIFRoYXQgaXMgbm90CiAgICAgICAgICAgICAgICAvL2Egbm9ybWFsLCBjb21tb24gY2FzZSwgYnV0IGl0IGlzIGFsc28gbm90IHVuZXhwZWN0ZWQuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgdGhpcy5mYWN0b3J5ID0gZmFjdG9yeTsKCiAgICAgICAgICAgICAgICBpZiAoZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgIC8vUmVnaXN0ZXIgZm9yIGVycm9ycyBvbiB0aGlzIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLm9uKCdlcnJvcicsIGVycmJhY2spOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgIC8vSWYgbm8gZXJyYmFjayBhbHJlYWR5LCBidXQgdGhlcmUgYXJlIGVycm9yIGxpc3RlbmVycwogICAgICAgICAgICAgICAgICAgIC8vb24gdGhpcyBtb2R1bGUsIHNldCB1cCBhbiBlcnJiYWNrIHRvIHBhc3MgdG8gdGhlIGRlcHMuCiAgICAgICAgICAgICAgICAgICAgZXJyYmFjayA9IGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0RvIGEgY29weSBvZiB0aGUgZGVwZW5kZW5jeSBhcnJheSwgc28gdGhhdAogICAgICAgICAgICAgICAgLy9zb3VyY2UgaW5wdXRzIGFyZSBub3QgbW9kaWZpZWQuIEZvciBleGFtcGxlCiAgICAgICAgICAgICAgICAvLyJzaGltIiBkZXBzIGFyZSBwYXNzZWQgaW4gaGVyZSBkaXJlY3RseSwgYW5kCiAgICAgICAgICAgICAgICAvL2RvaW5nIGEgZGlyZWN0IG1vZGlmaWNhdGlvbiBvZiB0aGUgZGVwTWFwcyBhcnJheQogICAgICAgICAgICAgICAgLy93b3VsZCBhZmZlY3QgdGhhdCBjb25maWcuCiAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMgPSBkZXBNYXBzICYmIGRlcE1hcHMuc2xpY2UoMCk7CgogICAgICAgICAgICAgICAgdGhpcy5lcnJiYWNrID0gZXJyYmFjazsKCiAgICAgICAgICAgICAgICAvL0luZGljYXRlIHRoaXMgbW9kdWxlIGhhcyBiZSBpbml0aWFsaXplZAogICAgICAgICAgICAgICAgdGhpcy5pbml0ZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIHRoaXMuaWdub3JlID0gb3B0aW9ucy5pZ25vcmU7CgogICAgICAgICAgICAgICAgLy9Db3VsZCBoYXZlIG9wdGlvbiB0byBpbml0IHRoaXMgbW9kdWxlIGluIGVuYWJsZWQgbW9kZSwKICAgICAgICAgICAgICAgIC8vb3IgY291bGQgaGF2ZSBiZWVuIHByZXZpb3VzbHkgbWFya2VkIGFzIGVuYWJsZWQuIEhvd2V2ZXIsCiAgICAgICAgICAgICAgICAvL3RoZSBkZXBlbmRlbmNpZXMgYXJlIG5vdCBrbm93biB1bnRpbCBpbml0IGlzIGNhbGxlZC4gU28KICAgICAgICAgICAgICAgIC8vaWYgZW5hYmxlZCBwcmV2aW91c2x5LCBub3cgdHJpZ2dlciBkZXBlbmRlbmNpZXMgYXMgZW5hYmxlZC4KICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVuYWJsZWQgfHwgdGhpcy5lbmFibGVkKSB7CiAgICAgICAgICAgICAgICAgICAgLy9FbmFibGUgdGhpcyBtb2R1bGUgYW5kIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAvL1dpbGwgY2FsbCB0aGlzLmNoZWNrKCkKICAgICAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmNoZWNrKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBkZWZpbmVEZXA6IGZ1bmN0aW9uIChpLCBkZXBFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAvL0JlY2F1c2Ugb2YgY3ljbGVzLCBkZWZpbmVkIGNhbGxiYWNrIGZvciBhIGdpdmVuCiAgICAgICAgICAgICAgICAvL2V4cG9ydCBjYW4gYmUgY2FsbGVkIG1vcmUgdGhhbiBvbmNlLgogICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRlcE1hdGNoZWRbaV0pIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hdGNoZWRbaV0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwQ291bnQgLT0gMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHNbaV0gPSBkZXBFeHBvcnRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLmZldGNoZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0aGlzLmZldGNoZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIGNvbnRleHQuc3RhcnRUaW1lID0gKG5ldyBEYXRlKCkpLmdldFRpbWUoKTsKCiAgICAgICAgICAgICAgICB2YXIgbWFwID0gdGhpcy5tYXA7CgogICAgICAgICAgICAgICAgLy9JZiB0aGUgbWFuYWdlciBpcyBmb3IgYSBwbHVnaW4gbWFuYWdlZCByZXNvdXJjZSwKICAgICAgICAgICAgICAgIC8vYXNrIHRoZSBwbHVnaW4gdG8gbG9hZCBpdCBub3cuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5tYWtlUmVxdWlyZSh0aGlzLm1hcCwgewogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVCdWlsZENhbGxiYWNrOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgfSkodGhpcy5zaGltLmRlcHMgfHwgW10sIGJpbmQodGhpcywgZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgfSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL1JlZ3VsYXIgZGVwZW5kZW5jeS4KICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBsb2FkOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICB2YXIgdXJsID0gdGhpcy5tYXAudXJsOwoKICAgICAgICAgICAgICAgIC8vUmVndWxhciBkZXBlbmRlbmN5LgogICAgICAgICAgICAgICAgaWYgKCF1cmxGZXRjaGVkW3VybF0pIHsKICAgICAgICAgICAgICAgICAgICB1cmxGZXRjaGVkW3VybF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIGNvbnRleHQubG9hZCh0aGlzLm1hcC5pZCwgdXJsKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBDaGVja3MgaWYgdGhlIG1vZHVsZSBpcyByZWFkeSB0byBkZWZpbmUgaXRzZWxmLCBhbmQgaWYgc28sCiAgICAgICAgICAgICAqIGRlZmluZSBpdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNoZWNrOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZW5hYmxlZCB8fCB0aGlzLmVuYWJsaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHZhciBlcnIsIGNqc01vZHVsZSwKICAgICAgICAgICAgICAgICAgICBpZCA9IHRoaXMubWFwLmlkLAogICAgICAgICAgICAgICAgICAgIGRlcEV4cG9ydHMgPSB0aGlzLmRlcEV4cG9ydHMsCiAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0cywKICAgICAgICAgICAgICAgICAgICBmYWN0b3J5ID0gdGhpcy5mYWN0b3J5OwoKICAgICAgICAgICAgICAgIGlmICghdGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGZldGNoIGlmIG5vdCBhbHJlYWR5IGluIHRoZSBkZWZRdWV1ZS4KICAgICAgICAgICAgICAgICAgICBpZiAoIWhhc1Byb3AoY29udGV4dC5kZWZRdWV1ZU1hcCwgaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZmV0Y2goKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgdGhpcy5lcnJvcik7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLmRlZmluaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgLy9UaGUgZmFjdG9yeSBjb3VsZCB0cmlnZ2VyIGFub3RoZXIgcmVxdWlyZSBjYWxsCiAgICAgICAgICAgICAgICAgICAgLy90aGF0IHdvdWxkIHJlc3VsdCBpbiBjaGVja2luZyB0aGlzIG1vZHVsZSB0bwogICAgICAgICAgICAgICAgICAgIC8vZGVmaW5lIGl0c2VsZiBhZ2Fpbi4gSWYgYWxyZWFkeSBpbiB0aGUgcHJvY2VzcwogICAgICAgICAgICAgICAgICAgIC8vb2YgZG9pbmcgdGhhdCwgc2tpcCB0aGlzIHdvcmsuCiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWZpbmluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlcENvdW50IDwgMSAmJiAhdGhpcy5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0Z1bmN0aW9uKGZhY3RvcnkpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjb250ZXh0LmV4ZWNDYihpZCwgZmFjdG9yeSwgZGVwRXhwb3J0cywgZXhwb3J0cyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyID0gZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGYXZvciByZXR1cm4gdmFsdWUgb3ZlciBleHBvcnRzLiBJZiBub2RlL2NqcyBpbiBwbGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlbiB3aWxsIG5vdCBoYXZlIGEgcmV0dXJuIHZhbHVlIGFueXdheS4gRmF2b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1vZHVsZS5leHBvcnRzIGFzc2lnbm1lbnQgb3ZlciBleHBvcnRzIG9iamVjdC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hcC5pc0RlZmluZSAmJiBleHBvcnRzID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjanNNb2R1bGUgPSB0aGlzLm1vZHVsZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2pzTW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjanNNb2R1bGUuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMudXNpbmdFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vZXhwb3J0cyBhbHJlYWR5IHNldCB0aGUgZGVmaW5lZCB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZXJlIGlzIGFuIGVycm9yIGxpc3RlbmVyLCBmYXZvciBwYXNzaW5nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdG8gdGhhdCBpbnN0ZWFkIG9mIHRocm93aW5nIGFuIGVycm9yLiBIb3dldmVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9ubHkgZG8gaXQgZm9yIGRlZmluZSgpJ2QgIG1vZHVsZXMuIHJlcXVpcmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBlcnJiYWNrcyBzaG91bGQgbm90IGJlIGNhbGxlZCBmb3IgZmFpbHVyZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGVpciBjYWxsYmFja3MgKCM2OTkpLiBIb3dldmVyIGlmIGEgZ2xvYmFsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb25FcnJvciBpcyBzZXQsIHVzZSB0aGF0LgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodGhpcy5ldmVudHMuZXJyb3IgJiYgdGhpcy5tYXAuaXNEZWZpbmUpIHx8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5vbkVycm9yICE9PSBkZWZhdWx0T25FcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1hcCA9IHRoaXMubWFwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1vZHVsZXMgPSB0aGlzLm1hcC5pc0RlZmluZSA/IFt0aGlzLm1hcC5pZF0gOiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZVR5cGUgPSB0aGlzLm1hcC5pc0RlZmluZSA/ICdkZWZpbmUnIDogJ3JlcXVpcmUnOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcigodGhpcy5lcnJvciA9IGVycikpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvZyB0aGUgZXJyb3IgZm9yIGRlYnVnZ2luZy4gSWYgcHJvbWlzZXMgY291bGQgYmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXNlZCwgdGhpcyB3b3VsZCBiZSBkaWZmZXJlbnQsIGJ1dCBtYWtpbmcgZG8uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBEbyBub3Qgd2FudCB0byBjb21wbGV0ZWx5IGxvc2UgdGhlIGVycm9yLiBXaGlsZSB0aGlzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpbGwgbWVzcyB1cCBwcm9jZXNzaW5nIGFuZCBsZWFkIHRvIHNpbWlsYXIgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcyBidWcgMTQ0MCwgaXQgYXQgbGVhc3Qgc3VyZmFjZXMgdGhlIGVycm9yLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIGxpdGVyYWwgdmFsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBmYWN0b3J5OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmV4cG9ydHMgPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubWFwLmlzRGVmaW5lICYmICF0aGlzLmlnbm9yZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmaW5lZFtpZF0gPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEub25SZXNvdXJjZUxvYWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzTG9hZE1hcHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNMb2FkTWFwcy5wdXNoKGRlcE1hcC5ub3JtYWxpemVkTWFwIHx8IGRlcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxLm9uUmVzb3VyY2VMb2FkKGNvbnRleHQsIHRoaXMubWFwLCByZXNMb2FkTWFwcyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQ2xlYW4gdXAKICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9GaW5pc2hlZCB0aGUgZGVmaW5lIHN0YWdlLiBBbGxvdyBjYWxsaW5nIGNoZWNrIGFnYWluCiAgICAgICAgICAgICAgICAgICAgLy90byBhbGxvdyBkZWZpbmUgbm90aWZpY2F0aW9ucyBiZWxvdyBpbiB0aGUgY2FzZSBvZiBhCiAgICAgICAgICAgICAgICAgICAgLy9jeWNsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluaW5nID0gZmFsc2U7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlZmluZWQgJiYgIXRoaXMuZGVmaW5lRW1pdHRlZCkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXR0ZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2RlZmluZWQnLCB0aGlzLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXRDb21wbGV0ZSA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGNhbGxQbHVnaW46IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHZhciBtYXAgPSB0aGlzLm1hcCwKICAgICAgICAgICAgICAgICAgICBpZCA9IG1hcC5pZCwKICAgICAgICAgICAgICAgICAgICAvL01hcCBhbHJlYWR5IG5vcm1hbGl6ZWQgdGhlIHByZWZpeC4KICAgICAgICAgICAgICAgICAgICBwbHVnaW5NYXAgPSBtYWtlTW9kdWxlTWFwKG1hcC5wcmVmaXgpOwoKICAgICAgICAgICAgICAgIC8vTWFyayB0aGlzIGFzIGEgZGVwZW5kZW5jeSBmb3IgdGhpcyBwbHVnaW4sIHNvIGl0CiAgICAgICAgICAgICAgICAvL2NhbiBiZSB0cmFjZWQgZm9yIGN5Y2xlcy4KICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcy5wdXNoKHBsdWdpbk1hcCk7CgogICAgICAgICAgICAgICAgb24ocGx1Z2luTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbikgewogICAgICAgICAgICAgICAgICAgIHZhciBsb2FkLCBub3JtYWxpemVkTWFwLCBub3JtYWxpemVkTW9kLAogICAgICAgICAgICAgICAgICAgICAgICBidW5kbGVJZCA9IGdldE93bihidW5kbGVzTWFwLCB0aGlzLm1hcC5pZCksCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSB0aGlzLm1hcC5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnROYW1lID0gdGhpcy5tYXAucGFyZW50TWFwID8gdGhpcy5tYXAucGFyZW50TWFwLm5hbWUgOiBudWxsLAogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKG1hcC5wYXJlbnRNYXAsIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZUJ1aWxkQ2FsbGJhY2s6IHRydWUKICAgICAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgICAgIC8vSWYgY3VycmVudCBtYXAgaXMgbm90IG5vcm1hbGl6ZWQsIHdhaXQgZm9yIHRoYXQKICAgICAgICAgICAgICAgICAgICAvL25vcm1hbGl6ZWQgbmFtZSB0byBsb2FkIGluc3RlYWQgb2YgY29udGludWluZy4KICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5tYXAudW5ub3JtYWxpemVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIHRoZSBJRCBpZiB0aGUgcGx1Z2luIGFsbG93cyBpdC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBsdWdpbi5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBwbHVnaW4ubm9ybWFsaXplKG5hbWUsIGZ1bmN0aW9uIChuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pIHx8ICcnOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL3ByZWZpeCBhbmQgbmFtZSBzaG91bGQgYWxyZWFkeSBiZSBub3JtYWxpemVkLCBubyBuZWVkCiAgICAgICAgICAgICAgICAgICAgICAgIC8vZm9yIGFwcGx5aW5nIG1hcCBjb25maWcgYWdhaW4gZWl0aGVyLgogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTWFwID0gbWFrZU1vZHVsZU1hcChtYXAucHJlZml4ICsgJyEnICsgbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXAucGFyZW50TWFwKTsKICAgICAgICAgICAgICAgICAgICAgICAgb24obm9ybWFsaXplZE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkZWZpbmVkJywgYmluZCh0aGlzLCBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hcC5ub3JtYWxpemVkTWFwID0gbm9ybWFsaXplZE1hcDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZTogdHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE1vZCA9IGdldE93bihyZWdpc3RyeSwgbm9ybWFsaXplZE1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkTW9kKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL01hcmsgdGhpcyBhcyBhIGRlcGVuZGVuY3kgZm9yIHRoaXMgcGx1Z2luLCBzbyBpdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9jYW4gYmUgdHJhY2VkIGZvciBjeWNsZXMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMucHVzaChub3JtYWxpemVkTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5ldmVudHMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLm9uKCdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0lmIGEgcGF0aHMgY29uZmlnLCB0aGVuIGp1c3QgbG9hZCB0aGF0IGZpbGUgaW5zdGVhZCB0bwogICAgICAgICAgICAgICAgICAgIC8vcmVzb2x2ZSB0aGUgcGx1Z2luLCBhcyBpdCBpcyBidWlsdCBpbnRvIHRoYXQgcGF0aHMgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWFwLnVybCA9IGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkKTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGxvYWQgPSBiaW5kKHRoaXMsIGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICBsb2FkLmVycm9yID0gYmluZCh0aGlzLCBmdW5jdGlvbiAoZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdGVkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycjsKICAgICAgICAgICAgICAgICAgICAgICAgZXJyLnJlcXVpcmVNb2R1bGVzID0gW2lkXTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vUmVtb3ZlIHRlbXAgdW5ub3JtYWxpemVkIG1vZHVsZXMgZm9yIHRoaXMgbW9kdWxlLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NpbmNlIHRoZXkgd2lsbCBuZXZlciBiZSByZXNvbHZlZCBvdGhlcndpc2Ugbm93LgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaWQuaW5kZXhPZihpZCArICdfdW5ub3JtYWxpemVkJykgPT09IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhblJlZ2lzdHJ5KG1vZC5tYXAuaWQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9BbGxvdyBwbHVnaW5zIHRvIGxvYWQgb3RoZXIgY29kZSB3aXRob3V0IGhhdmluZyB0byBrbm93IHRoZQogICAgICAgICAgICAgICAgICAgIC8vY29udGV4dCBvciBob3cgdG8gJ2NvbXBsZXRlJyB0aGUgbG9hZC4KICAgICAgICAgICAgICAgICAgICBsb2FkLmZyb21UZXh0ID0gYmluZCh0aGlzLCBmdW5jdGlvbiAodGV4dCwgdGV4dEFsdCkgewogICAgICAgICAgICAgICAgICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtb2R1bGVOYW1lID0gbWFwLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVNYXAgPSBtYWtlTW9kdWxlTWFwKG1vZHVsZU5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzSW50ZXJhY3RpdmUgPSB1c2VJbnRlcmFjdGl2ZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQXMgb2YgMi4xLjAsIHN1cHBvcnQganVzdCBwYXNzaW5nIHRoZSB0ZXh0LCB0byByZWluZm9yY2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9mcm9tVGV4dCBvbmx5IGJlaW5nIGNhbGxlZCBvbmNlIHBlciByZXNvdXJjZS4gU3RpbGwKICAgICAgICAgICAgICAgICAgICAgICAgLy9zdXBwb3J0IG9sZCBzdHlsZSBvZiBwYXNzaW5nIG1vZHVsZU5hbWUgYnV0IGRpc2NhcmQKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGF0IG1vZHVsZU5hbWUgaW4gZmF2b3Igb2YgdGhlIGludGVybmFsIHJlZi4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRleHRBbHQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQgPSB0ZXh0QWx0OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1R1cm4gb2ZmIGludGVyYWN0aXZlIHNjcmlwdCBtYXRjaGluZyBmb3IgSUUgZm9yIGFueSBkZWZpbmUKICAgICAgICAgICAgICAgICAgICAgICAgLy9jYWxscyBpbiB0aGUgdGV4dCwgdGhlbiB0dXJuIGl0IGJhY2sgb24gYXQgdGhlIGVuZC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0ludGVyYWN0aXZlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1ByaW1lIHRoZSBzeXN0ZW0gYnkgY3JlYXRpbmcgYSBtb2R1bGUgaW5zdGFuY2UgZm9yCiAgICAgICAgICAgICAgICAgICAgICAgIC8vaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGdldE1vZHVsZShtb2R1bGVNYXApOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9UcmFuc2ZlciBhbnkgY29uZmlnIHRvIHRoaXMgb3RoZXIgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzUHJvcChjb25maWcuY29uZmlnLCBpZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5jb25maWdbbW9kdWxlTmFtZV0gPSBjb25maWcuY29uZmlnW2lkXTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5leGVjKHRleHQpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ2Zyb210ZXh0ZXZhbCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdmcm9tVGV4dCBldmFsIGZvciAnICsgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcgZmFpbGVkOiAnICsgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2lkXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXJrIHRoaXMgYXMgYSBkZXBlbmRlbmN5IGZvciB0aGUgcGx1Z2luCiAgICAgICAgICAgICAgICAgICAgICAgIC8vcmVzb3VyY2UKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBNYXBzLnB1c2gobW9kdWxlTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3VwcG9ydCBhbm9ueW1vdXMgbW9kdWxlcy4KICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQobW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgdGhlIHZhbHVlIG9mIHRoYXQgbW9kdWxlIHRvIHRoZSB2YWx1ZSBmb3IgdGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvL3Jlc291cmNlIElELgogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUoW21vZHVsZU5hbWVdLCBsb2FkKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9Vc2UgcGFyZW50TmFtZSBoZXJlIHNpbmNlIHRoZSBwbHVnaW4ncyBuYW1lIGlzIG5vdCByZWxpYWJsZSwKICAgICAgICAgICAgICAgICAgICAvL2NvdWxkIGJlIHNvbWUgd2VpcmQgc3RyaW5nIHdpdGggbm8gcGF0aCB0aGF0IGFjdHVhbGx5IHdhbnRzIHRvCiAgICAgICAgICAgICAgICAgICAgLy9yZWZlcmVuY2UgdGhlIHBhcmVudE5hbWUncyBwYXRoLgogICAgICAgICAgICAgICAgICAgIHBsdWdpbi5sb2FkKG1hcC5uYW1lLCBsb2NhbFJlcXVpcmUsIGxvYWQsIGNvbmZpZyk7CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luTWFwc1twbHVnaW5NYXAuaWRdID0gcGx1Z2luTWFwOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZW5hYmxlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBlbmFibGVkUmVnaXN0cnlbdGhpcy5tYXAuaWRdID0gdGhpczsKICAgICAgICAgICAgICAgIHRoaXMuZW5hYmxlZCA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9TZXQgZmxhZyBtZW50aW9uaW5nIHRoYXQgdGhlIG1vZHVsZSBpcyBlbmFibGluZywKICAgICAgICAgICAgICAgIC8vc28gdGhhdCBpbW1lZGlhdGUgY2FsbHMgdG8gdGhlIGRlZmluZWQgY2FsbGJhY2tzCiAgICAgICAgICAgICAgICAvL2ZvciBkZXBlbmRlbmNpZXMgZG8gbm90IHRyaWdnZXIgaW5hZHZlcnRlbnQgbG9hZAogICAgICAgICAgICAgICAgLy93aXRoIHRoZSBkZXBDb3VudCBzdGlsbCBiZWluZyB6ZXJvLgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9FbmFibGUgZWFjaCBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgYmluZCh0aGlzLCBmdW5jdGlvbiAoZGVwTWFwLCBpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIGlkLCBtb2QsIGhhbmRsZXI7CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwTWFwID09PSAnc3RyaW5nJykgewogICAgICAgICAgICAgICAgICAgICAgICAvL0RlcGVuZGVuY3kgbmVlZHMgdG8gYmUgY29udmVydGVkIHRvIGEgZGVwTWFwCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYW5kIHdpcmVkIHVwIHRvIHRoaXMgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBkZXBNYXAgPSBtYWtlTW9kdWxlTWFwKGRlcE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5tYXAuaXNEZWZpbmUgPyB0aGlzLm1hcCA6IHRoaXMubWFwLnBhcmVudE1hcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIXRoaXMuc2tpcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwc1tpXSA9IGRlcE1hcDsKCiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZXIgPSBnZXRPd24oaGFuZGxlcnMsIGRlcE1hcC5pZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBFeHBvcnRzW2ldID0gaGFuZGxlcih0aGlzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBDb3VudCArPSAxOwoKICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKGRlcEV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnVuZGVmZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZURlcChpLCBkZXBFeHBvcnRzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZXJyb3InLCBiaW5kKHRoaXMsIHRoaXMuZXJyYmFjaykpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXZlbnRzLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBObyBkaXJlY3QgZXJyYmFjayBvbiB0aGlzIG1vZHVsZSwgYnV0IHNvbWV0aGluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWxzZSBpcyBsaXN0ZW5pbmcgZm9yIGVycm9ycywgc28gYmUgc3VyZSB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJvcGFnYXRlIHRoZSBlcnJvciBjb3JyZWN0bHkuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbihkZXBNYXAsICdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24oZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIGVycik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlkID0gZGVwTWFwLmlkOwogICAgICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXTsKCiAgICAgICAgICAgICAgICAgICAgLy9Ta2lwIHNwZWNpYWwgbW9kdWxlcyBsaWtlICdyZXF1aXJlJywgJ2V4cG9ydHMnLCAnbW9kdWxlJwogICAgICAgICAgICAgICAgICAgIC8vQWxzbywgZG9uJ3QgY2FsbCBlbmFibGUgaWYgaXQgaXMgYWxyZWFkeSBlbmFibGVkLAogICAgICAgICAgICAgICAgICAgIC8vaW1wb3J0YW50IGluIGNpcmN1bGFyIGRlcGVuZGVuY3kgY2FzZXMuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGhhbmRsZXJzLCBpZCkgJiYgbW9kICYmICFtb2QuZW5hYmxlZCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmVuYWJsZShkZXBNYXAsIHRoaXMpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pKTsKCiAgICAgICAgICAgICAgICAvL0VuYWJsZSBlYWNoIHBsdWdpbiB0aGF0IGlzIHVzZWQgaW4KICAgICAgICAgICAgICAgIC8vYSBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoUHJvcCh0aGlzLnBsdWdpbk1hcHMsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbk1hcCkgewogICAgICAgICAgICAgICAgICAgIHZhciBtb2QgPSBnZXRPd24ocmVnaXN0cnksIHBsdWdpbk1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCAmJiAhbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IGZhbHNlOwoKICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG9uOiBmdW5jdGlvbiAobmFtZSwgY2IpIHsKICAgICAgICAgICAgICAgIHZhciBjYnMgPSB0aGlzLmV2ZW50c1tuYW1lXTsKICAgICAgICAgICAgICAgIGlmICghY2JzKSB7CiAgICAgICAgICAgICAgICAgICAgY2JzID0gdGhpcy5ldmVudHNbbmFtZV0gPSBbXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNicy5wdXNoKGNiKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGVtaXQ6IGZ1bmN0aW9uIChuYW1lLCBldnQpIHsKICAgICAgICAgICAgICAgIGVhY2godGhpcy5ldmVudHNbbmFtZV0sIGZ1bmN0aW9uIChjYikgewogICAgICAgICAgICAgICAgICAgIGNiKGV2dCk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGlmIChuYW1lID09PSAnZXJyb3InKSB7CiAgICAgICAgICAgICAgICAgICAgLy9Ob3cgdGhhdCB0aGUgZXJyb3IgaGFuZGxlciB3YXMgdHJpZ2dlcmVkLCByZW1vdmUKICAgICAgICAgICAgICAgICAgICAvL3RoZSBsaXN0ZW5lcnMsIHNpbmNlIHRoaXMgYnJva2VuIE1vZHVsZSBpbnN0YW5jZQogICAgICAgICAgICAgICAgICAgIC8vY2FuIHN0YXkgYXJvdW5kIGZvciBhIHdoaWxlIGluIHRoZSByZWdpc3RyeS4KICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5ldmVudHNbbmFtZV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjYWxsR2V0TW9kdWxlKGFyZ3MpIHsKICAgICAgICAgICAgLy9Ta2lwIG1vZHVsZXMgYWxyZWFkeSBkZWZpbmVkLgogICAgICAgICAgICBpZiAoIWhhc1Byb3AoZGVmaW5lZCwgYXJnc1swXSkpIHsKICAgICAgICAgICAgICAgIGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKGFyZ3NbMF0sIG51bGwsIHRydWUpKS5pbml0KGFyZ3NbMV0sIGFyZ3NbMl0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihub2RlLCBmdW5jLCBuYW1lLCBpZU5hbWUpIHsKICAgICAgICAgICAgLy9GYXZvciBkZXRhY2hFdmVudCBiZWNhdXNlIG9mIElFOQogICAgICAgICAgICAvL2lzc3VlLCBzZWUgYXR0YWNoRXZlbnQvYWRkRXZlbnRMaXN0ZW5lciBjb21tZW50IGVsc2V3aGVyZQogICAgICAgICAgICAvL2luIHRoaXMgZmlsZS4KICAgICAgICAgICAgaWYgKG5vZGUuZGV0YWNoRXZlbnQgJiYgIWlzT3BlcmEpIHsKICAgICAgICAgICAgICAgIC8vUHJvYmFibHkgSUUuIElmIG5vdCBpdCB3aWxsIHRocm93IGFuIGVycm9yLCB3aGljaCB3aWxsIGJlCiAgICAgICAgICAgICAgICAvL3VzZWZ1bCB0byBrbm93LgogICAgICAgICAgICAgICAgaWYgKGllTmFtZSkgewogICAgICAgICAgICAgICAgICAgIG5vZGUuZGV0YWNoRXZlbnQoaWVOYW1lLCBmdW5jKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUucmVtb3ZlRXZlbnRMaXN0ZW5lcihuYW1lLCBmdW5jLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdpdmVuIGFuIGV2ZW50IGZyb20gYSBzY3JpcHQgbm9kZSwgZ2V0IHRoZSByZXF1aXJlanMgaW5mbyBmcm9tIGl0LAogICAgICAgICAqIGFuZCB0aGVuIHJlbW92ZXMgdGhlIGV2ZW50IGxpc3RlbmVycyBvbiB0aGUgbm9kZS4KICAgICAgICAgKiBAcGFyYW0ge0V2ZW50fSBldnQKICAgICAgICAgKiBAcmV0dXJucyB7T2JqZWN0fQogICAgICAgICAqLwogICAgICAgIGZ1bmN0aW9uIGdldFNjcmlwdERhdGEoZXZ0KSB7CiAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgLy9hbGwgb2xkIGJyb3dzZXJzIHdpbGwgYmUgc3VwcG9ydGVkLCBidXQgdGhpcyBvbmUgd2FzIGVhc3kgZW5vdWdoCiAgICAgICAgICAgIC8vdG8gc3VwcG9ydCBhbmQgc3RpbGwgbWFrZXMgc2Vuc2UuCiAgICAgICAgICAgIHZhciBub2RlID0gZXZ0LmN1cnJlbnRUYXJnZXQgfHwgZXZ0LnNyY0VsZW1lbnQ7CgogICAgICAgICAgICAvL1JlbW92ZSB0aGUgbGlzdGVuZXJzIG9uY2UgaGVyZS4KICAgICAgICAgICAgcmVtb3ZlTGlzdGVuZXIobm9kZSwgY29udGV4dC5vblNjcmlwdExvYWQsICdsb2FkJywgJ29ucmVhZHlzdGF0ZWNoYW5nZScpOwogICAgICAgICAgICByZW1vdmVMaXN0ZW5lcihub2RlLCBjb250ZXh0Lm9uU2NyaXB0RXJyb3IsICdlcnJvcicpOwoKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIG5vZGU6IG5vZGUsCiAgICAgICAgICAgICAgICBpZDogbm9kZSAmJiBub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJykKICAgICAgICAgICAgfTsKICAgICAgICB9CgogICAgICAgIGZ1bmN0aW9uIGludGFrZURlZmluZXMoKSB7CiAgICAgICAgICAgIHZhciBhcmdzOwoKICAgICAgICAgICAgLy9BbnkgZGVmaW5lZCBtb2R1bGVzIGluIHRoZSBnbG9iYWwgcXVldWUsIGludGFrZSB0aGVtIG5vdy4KICAgICAgICAgICAgdGFrZUdsb2JhbFF1ZXVlKCk7CgogICAgICAgICAgICAvL01ha2Ugc3VyZSBhbnkgcmVtYWluaW5nIGRlZlF1ZXVlIGl0ZW1zIGdldCBwcm9wZXJseSBwcm9jZXNzZWQuCiAgICAgICAgICAgIHdoaWxlIChkZWZRdWV1ZS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGFyZ3MgPSBkZWZRdWV1ZS5zaGlmdCgpOwogICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ21pc21hdGNoJywgJ01pc21hdGNoZWQgYW5vbnltb3VzIGRlZmluZSgpIG1vZHVsZTogJyArCiAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3NbYXJncy5sZW5ndGggLSAxXSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL2FyZ3MgYXJlIGlkLCBkZXBzLCBmYWN0b3J5LiBTaG91bGQgYmUgbm9ybWFsaXplZCBieSB0aGUKICAgICAgICAgICAgICAgICAgICAvL2RlZmluZSgpIGZ1bmN0aW9uLgogICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoYXJncyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcCA9IHt9OwogICAgICAgIH0KCiAgICAgICAgY29udGV4dCA9IHsKICAgICAgICAgICAgY29uZmlnOiBjb25maWcsCiAgICAgICAgICAgIGNvbnRleHROYW1lOiBjb250ZXh0TmFtZSwKICAgICAgICAgICAgcmVnaXN0cnk6IHJlZ2lzdHJ5LAogICAgICAgICAgICBkZWZpbmVkOiBkZWZpbmVkLAogICAgICAgICAgICB1cmxGZXRjaGVkOiB1cmxGZXRjaGVkLAogICAgICAgICAgICBkZWZRdWV1ZTogZGVmUXVldWUsCiAgICAgICAgICAgIGRlZlF1ZXVlTWFwOiB7fSwKICAgICAgICAgICAgTW9kdWxlOiBNb2R1bGUsCiAgICAgICAgICAgIG1ha2VNb2R1bGVNYXA6IG1ha2VNb2R1bGVNYXAsCiAgICAgICAgICAgIG5leHRUaWNrOiByZXEubmV4dFRpY2ssCiAgICAgICAgICAgIG9uRXJyb3I6IG9uRXJyb3IsCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogU2V0IGEgY29uZmlndXJhdGlvbiBmb3IgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgY29uZmlnIG9iamVjdCB0byBpbnRlZ3JhdGUuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBjb25maWd1cmU6IGZ1bmN0aW9uIChjZmcpIHsKICAgICAgICAgICAgICAgIC8vTWFrZSBzdXJlIHRoZSBiYXNlVXJsIGVuZHMgaW4gYSBzbGFzaC4KICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybC5jaGFyQXQoY2ZnLmJhc2VVcmwubGVuZ3RoIC0gMSkgIT09ICcvJykgewogICAgICAgICAgICAgICAgICAgICAgICBjZmcuYmFzZVVybCArPSAnLyc7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vU2F2ZSBvZmYgdGhlIHBhdGhzIHNpbmNlIHRoZXkgcmVxdWlyZSBzcGVjaWFsIHByb2Nlc3NpbmcsCiAgICAgICAgICAgICAgICAvL3RoZXkgYXJlIGFkZGl0aXZlLgogICAgICAgICAgICAgICAgdmFyIHNoaW0gPSBjb25maWcuc2hpbSwKICAgICAgICAgICAgICAgICAgICBvYmpzID0gewogICAgICAgICAgICAgICAgICAgICAgICBwYXRoczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnOiB0cnVlLAogICAgICAgICAgICAgICAgICAgICAgICBtYXA6IHRydWUKICAgICAgICAgICAgICAgICAgICB9OwoKICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZywgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG9ianNbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjb25maWdbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHt9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIG1peGluKGNvbmZpZ1twcm9wXSwgdmFsdWUsIHRydWUsIHRydWUpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHZhbHVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIC8vUmV2ZXJzZSBtYXAgdGhlIGJ1bmRsZXMKICAgICAgICAgICAgICAgIGlmIChjZmcuYnVuZGxlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZy5idW5kbGVzLCBmdW5jdGlvbiAodmFsdWUsIHByb3ApIHsKICAgICAgICAgICAgICAgICAgICAgICAgZWFjaCh2YWx1ZSwgZnVuY3Rpb24gKHYpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2ICE9PSBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlc01hcFt2XSA9IHByb3A7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vTWVyZ2Ugc2hpbQogICAgICAgICAgICAgICAgaWYgKGNmZy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgZWFjaFByb3AoY2ZnLnNoaW0sIGZ1bmN0aW9uICh2YWx1ZSwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9Ob3JtYWxpemUgdGhlIHN0cnVjdHVyZQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlcHM6IHZhbHVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodmFsdWUuZXhwb3J0cyB8fCB2YWx1ZS5pbml0KSAmJiAhdmFsdWUuZXhwb3J0c0ZuKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5leHBvcnRzRm4gPSBjb250ZXh0Lm1ha2VTaGltRXhwb3J0cyh2YWx1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgc2hpbVtpZF0gPSB2YWx1ZTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICBjb25maWcuc2hpbSA9IHNoaW07CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgLy9BZGp1c3QgcGFja2FnZXMgaWYgbmVjZXNzYXJ5LgogICAgICAgICAgICAgICAgaWYgKGNmZy5wYWNrYWdlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2goY2ZnLnBhY2thZ2VzLCBmdW5jdGlvbiAocGtnT2JqKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsb2NhdGlvbiwgbmFtZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHBrZ09iaiA9IHR5cGVvZiBwa2dPYmogPT09ICdzdHJpbmcnID8ge25hbWU6IHBrZ09ian0gOiBwa2dPYmo7CgogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gcGtnT2JqLm5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gcGtnT2JqLmxvY2F0aW9uOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9jYXRpb24pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5wYXRoc1tuYW1lXSA9IHBrZ09iai5sb2NhdGlvbjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TYXZlIHBvaW50ZXIgdG8gbWFpbiBtb2R1bGUgSUQgZm9yIHBrZyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAvL1JlbW92ZSBsZWFkaW5nIGRvdCBpbiBtYWluLCBzbyBtYWluIHBhdGhzIGFyZSBub3JtYWxpemVkLAogICAgICAgICAgICAgICAgICAgICAgICAvL2FuZCByZW1vdmUgYW55IHRyYWlsaW5nIC5qcywgc2luY2UgZGlmZmVyZW50IHBhY2thZ2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9lbnZzIGhhdmUgZGlmZmVyZW50IGNvbnZlbnRpb25zOiBzb21lIHVzZSBhIG1vZHVsZSBuYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NvbWUgdXNlIGEgZmlsZSBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICBjb25maWcucGtnc1tuYW1lXSA9IHBrZ09iai5uYW1lICsgJy8nICsgKHBrZ09iai5tYWluIHx8ICdtYWluJykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKGN1cnJEaXJSZWdFeHAsICcnKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0lmIHRoZXJlIGFyZSBhbnkgIndhaXRpbmcgdG8gZXhlY3V0ZSIgbW9kdWxlcyBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAvL3VwZGF0ZSB0aGUgbWFwcyBmb3IgdGhlbSwgc2luY2UgdGhlaXIgaW5mbywgbGlrZSBVUkxzIHRvIGxvYWQsCiAgICAgICAgICAgICAgICAvL21heSBoYXZlIGNoYW5nZWQuCiAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIG1vZHVsZSBhbHJlYWR5IGhhcyBpbml0IGNhbGxlZCwgc2luY2UgaXQgaXMgdG9vCiAgICAgICAgICAgICAgICAgICAgLy9sYXRlIHRvIG1vZGlmeSB0aGVtLCBhbmQgaWdub3JlIHVubm9ybWFsaXplZCBvbmVzCiAgICAgICAgICAgICAgICAgICAgLy9zaW5jZSB0aGV5IGFyZSB0cmFuc2llbnQuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFtb2QuaW5pdGVkICYmICFtb2QubWFwLnVubm9ybWFsaXplZCkgewogICAgICAgICAgICAgICAgICAgICAgICBtb2QubWFwID0gbWFrZU1vZHVsZU1hcChpZCwgbnVsbCwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9JZiBhIGRlcHMgYXJyYXkgb3IgYSBjb25maWcgY2FsbGJhY2sgaXMgc3BlY2lmaWVkLCB0aGVuIGNhbGwKICAgICAgICAgICAgICAgIC8vcmVxdWlyZSB3aXRoIHRob3NlIGFyZ3MuIFRoaXMgaXMgdXNlZnVsIHdoZW4gcmVxdWlyZSBpcyBkZWZpbmVkIGFzIGEKICAgICAgICAgICAgICAgIC8vY29uZmlnIG9iamVjdCBiZWZvcmUgcmVxdWlyZS5qcyBpcyBsb2FkZWQuCiAgICAgICAgICAgICAgICBpZiAoY2ZnLmRlcHMgfHwgY2ZnLmNhbGxiYWNrKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlKGNmZy5kZXBzIHx8IFtdLCBjZmcuY2FsbGJhY2spOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgbWFrZVNoaW1FeHBvcnRzOiBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgIGZ1bmN0aW9uIGZuKCkgewogICAgICAgICAgICAgICAgICAgIHZhciByZXQ7CiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlLmluaXQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0ID0gdmFsdWUuaW5pdC5hcHBseShnbG9iYWwsIGFyZ3VtZW50cyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIHJldHVybiByZXQgfHwgKHZhbHVlLmV4cG9ydHMgJiYgZ2V0R2xvYmFsKHZhbHVlLmV4cG9ydHMpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBmbjsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG1ha2VSZXF1aXJlOiBmdW5jdGlvbiAocmVsTWFwLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICBmdW5jdGlvbiBsb2NhbFJlcXVpcmUoZGVwcywgY2FsbGJhY2ssIGVycmJhY2spIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQsIG1hcCwgcmVxdWlyZU1vZDsKCiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZW5hYmxlQnVpbGRDYWxsYmFjayAmJiBjYWxsYmFjayAmJiBpc0Z1bmN0aW9uKGNhbGxiYWNrKSkgewogICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjay5fX3JlcXVpcmVKc0J1aWxkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwcyA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzRnVuY3Rpb24oY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0ludmFsaWQgY2FsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdyZXF1aXJlYXJncycsICdJbnZhbGlkIHJlcXVpcmUgY2FsbCcpLCBlcnJiYWNrKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiByZXF1aXJlfGV4cG9ydHN8bW9kdWxlIGFyZSByZXF1ZXN0ZWQsIGdldCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy92YWx1ZSBmb3IgdGhlbSBmcm9tIHRoZSBzcGVjaWFsIGhhbmRsZXJzLiBDYXZlYXQ6CiAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBvbmx5IHdvcmtzIHdoaWxlIG1vZHVsZSBpcyBiZWluZyBkZWZpbmVkLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVsTWFwICYmIGhhc1Byb3AoaGFuZGxlcnMsIGRlcHMpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlcnNbZGVwc10ocmVnaXN0cnlbcmVsTWFwLmlkXSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3luY2hyb25vdXMgYWNjZXNzIHRvIG9uZSBtb2R1bGUuIElmIHJlcXVpcmUuZ2V0IGlzCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYXZhaWxhYmxlIChhcyBpbiB0aGUgTm9kZSBhZGFwdGVyKSwgcHJlZmVyIHRoYXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEuZ2V0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVxLmdldChjb250ZXh0LCBkZXBzLCByZWxNYXAsIGxvY2FsUmVxdWlyZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIG1vZHVsZSBuYW1lLCBpZiBpdCBjb250YWlucyAuIG9yIC4uCiAgICAgICAgICAgICAgICAgICAgICAgIG1hcCA9IG1ha2VNb2R1bGVNYXAoZGVwcywgcmVsTWFwLCBmYWxzZSwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFwLmlkOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGRlZmluZWQsIGlkKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub3Rsb2FkZWQnLCAnTW9kdWxlIG5hbWUgIicgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIgaGFzIG5vdCBiZWVuIGxvYWRlZCB5ZXQgZm9yIGNvbnRleHQ6ICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dE5hbWUgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlbE1hcCA/ICcnIDogJy4gVXNlIHJlcXVpcmUoW10pJykpKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0dyYWIgZGVmaW5lcyB3YWl0aW5nIGluIHRoZSBnbG9iYWwgcXVldWUuCiAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAvL01hcmsgYWxsIHRoZSBkZXBlbmRlbmNpZXMgYXMgbmVlZGluZyB0byBiZSBsb2FkZWQuCiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5uZXh0VGljayhmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vU29tZSBkZWZpbmVzIGNvdWxkIGhhdmUgYmVlbiBhZGRlZCBzaW5jZSB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9yZXF1aXJlIGNhbGwsIGNvbGxlY3QgdGhlbS4KICAgICAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZCA9IGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKG51bGwsIHJlbE1hcCkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TdG9yZSBpZiBtYXAgY29uZmlnIHNob3VsZCBiZSBhcHBsaWVkIHRvIHRoaXMgcmVxdWlyZQogICAgICAgICAgICAgICAgICAgICAgICAvL2NhbGwgZm9yIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5za2lwTWFwID0gb3B0aW9ucy5za2lwTWFwOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5pbml0KGRlcHMsIGNhbGxiYWNrLCBlcnJiYWNrLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tMb2FkZWQoKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsUmVxdWlyZTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBtaXhpbihsb2NhbFJlcXVpcmUsIHsKICAgICAgICAgICAgICAgICAgICBpc0Jyb3dzZXI6IGlzQnJvd3NlciwKCiAgICAgICAgICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAgICAgICAgICogQ29udmVydHMgYSBtb2R1bGUgbmFtZSArIC5leHRlbnNpb24gaW50byBhbiBVUkwgcGF0aC4KICAgICAgICAgICAgICAgICAgICAgKiAqUmVxdWlyZXMqIHRoZSB1c2Ugb2YgYSBtb2R1bGUgbmFtZS4gSXQgZG9lcyBub3Qgc3VwcG9ydCB1c2luZwogICAgICAgICAgICAgICAgICAgICAqIHBsYWluIFVSTHMgbGlrZSBuYW1lVG9VcmwuCiAgICAgICAgICAgICAgICAgICAgICovCiAgICAgICAgICAgICAgICAgICAgdG9Vcmw6IGZ1bmN0aW9uIChtb2R1bGVOYW1lUGx1c0V4dCkgewogICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBtb2R1bGVOYW1lUGx1c0V4dC5sYXN0SW5kZXhPZignLicpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudCA9IG1vZHVsZU5hbWVQbHVzRXh0LnNwbGl0KCcvJylbMF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1JlbGF0aXZlID0gc2VnbWVudCA9PT0gJy4nIHx8IHNlZ21lbnQgPT09ICcuLic7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0hhdmUgYSBmaWxlIGV4dGVuc2lvbiBhbGlhcywgYW5kIGl0IGlzIG5vdCB0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment